View Single Post
  #1   (View Single Post)  
Old 13th April 2009
IdOp's Avatar
IdOp IdOp is offline
Too dumb for a smartphone
 
Join Date: May 2008
Location: twisting on the daemon's fork(2)
Posts: 1,027
Default fseek() and read() problem

I was working on an audio program on the weekend and had some weird results on BSD. Tracking it down, it seems to be related to fseek() and read(). It occurs on both

* NetBSD 4.0.1 -release i386

* OpenBSD 4.4 -release i386

What happens is this: An input file consists of a whole number of frames (frame=2352 bytes). I fseek() a whole number of frames into the file, and then try to read() the rest of the file frame-by-frame. I noticed the wrong number of frames get read, and the last read() doesn't read a whole frame (too few bytes are read). From the read(2) man page:

Quote:
The system guarantees to read the number of bytes requested if the descriptor references a normal file that has that many bytes left before the end-of-file, but in no other case.
After tracking down the problem a bit, here's a simple demo that reproduces it. First, make an input file:

$ dd if=/dev/zero of=infile bs=2352 count=9

You can vary the count to see what happens. Check the file size:

Code:
$ ls -l infile
-rw-r--r--  1 xxx  users  21168 Apr 13 10:17 infile
Then grab this file trd.c:

Code:
#include <stdio.h>
#include <unistd.h>

int
main( int argc, char* argv[] )
{
    ssize_t     nr;
    char        buf[2352];      /*  = 1 frame */
    int         ifd, j;
    FILE        *ifp;

    ifp = fopen( "infile", "rb" );
    ifd = fileno( ifp );

    printf( "where = %ld\n", ftell( ifp ) );

    if( fseek( ifp, 2352, SEEK_SET ) )    /* seek 1 frame in */
        return 1;

    printf( "where = %ld\n", ftell( ifp ) );

    for( j=1; (nr = read( ifd, (void*)buf, 2352 )) != -1; j++ ) {

        printf( "%d:  nr = %d\n", j, nr );
        if( nr==0 ) break;

    }
    fclose( ifp );
    return 0;
}
and compile it

$ gcc -Wall -o trd trd.c

and run it. E.g., with a count of 9:

Code:
$ trd
where = 0
where = 2352
1:  nr = 2352
2:  nr = 2352
3:  nr = 80
4:  nr = 0
So it's reading 2-and-a-partial frames, when it should read 8. I hope it's just me doing something dumb (as usual), but I can't see what it is. Any help or comments appreciated!
Reply With Quote