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!