[comp.unix.questions] is struct stat buf.st_size always correct?

joshua@athertn.Atherton.COM (Flame Bait) (04/12/90)

I have a simple routine which uses stat() to find the size of a file,
then mallocs space for it, and then freads the whole file into a string.
Under SunOS 3.5 (mostly 4.2BSD) it seemed to work fine, but I did not
use it much.  Under SunOS 4.0.3 (mostly 4.3BSD) I sometimes end up with
extra `\377' characters at the end of the string.  It looks like the whole
file is there, but with two extra characters as well.

Is it possible that the st_size is rounded up to the nearest 4 bytes,
or something like that? 

The routine is similar to this one:

int eatfile(name, place) char *name ; char **place ;
{
    struct stat buf ;
    int size ;
    FILE *fp ;
    int s ;

    /* actions */                     /* error checking */
    s = stat(name,&buf) ;             if (s == -1) return -1 ;
    size = buf.st_size ;
    *place = malloc((unsigned)size) ; if (!*place) return -2;
    fp = fopen(name,"r") ;            if (!fp) { free(*place) ; return -3 ; }
    s = fread(*place,1,size,fp) ;     if (!s) { free(*place) ; return -4 ; }
    s = fclose(fp) ;                  if (s==EOF) { free(*place); return -5; }
    return size ;
}

Joshua Levy                          joshua@atherton.com  home:(415)968-3718
                        {decwrl|sun|hpda}!athertn!joshua  work:(408)734-9822 

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (04/12/90)

In article <21501@joshua.athertn.Atherton.COM> joshua@Atherton.COM (Flame Bait) writes:
: I have a simple routine which uses stat() to find the size of a file,
: then mallocs space for it, and then freads the whole file into a string.
: Under SunOS 3.5 (mostly 4.2BSD) it seemed to work fine, but I did not
: use it much.  Under SunOS 4.0.3 (mostly 4.3BSD) I sometimes end up with
: extra `\377' characters at the end of the string.  It looks like the whole
: file is there, but with two extra characters as well.

Two extra characters which you didn't malloc any space for.  You aren't
expecting fread() to do null termination for you, are you?  If so, you
should malloc at least one extra byte for the null.  And then you'd
discover that fread DOESN'T null terminate.

: Is it possible that the st_size is rounded up to the nearest 4 bytes,
: or something like that? 

If that were true, ls -l wouldn't work right.

: The routine is similar to this one:
: 
: int eatfile(name, place) char *name ; char **place ;
: {
:     struct stat buf ;
:     int size ;
:     FILE *fp ;
:     int s ;
: 
:     /* actions */                     /* error checking */
:     s = stat(name,&buf) ;             if (s == -1) return -1 ;
:     size = buf.st_size ;
:     *place = malloc((unsigned)size) ; if (!*place) return -2;
:     fp = fopen(name,"r") ;            if (!fp) { free(*place) ; return -3 ; }
:     s = fread(*place,1,size,fp) ;     if (!s) { free(*place) ; return -4 ; }
:     s = fclose(fp) ;                  if (s==EOF) { free(*place); return -5; }
:     return size ;
: }

Some gratuitous advice:

Why use fread?  Why not a normal open and a normal read?  It would be
less overhead.  On many systems (though not 4.0.3, I think), this has to
yank the file a piece at a time through the stdio buffers.

Larry Wall
lwall@jpl-devvax.jpl.nasa.gov

gwyn@smoke.BRL.MIL (Doug Gwyn) (04/13/90)

In article <7751@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
>Why use fread?  Why not a normal open and a normal read?  It would be
>less overhead.  On many systems (though not 4.0.3, I think), this has to
>yank the file a piece at a time through the stdio buffers.

However, if you use read(), you should write the code to loop on the
read() for the as-yet unread portion of the file until you get it all
or a 0 is returned.  fread() takes care of this for you.