The stat() call is returning a correct size.
The read() call is sensitive to how much space is available in the *destination*
buffer. Even though there is no data to
read. Expanding the *destination* buffer allows the read()
to properly return 0.
I have attached a test program that should demonstrate this
unstable behavior: "readtest.c". The bash script "runreadtest"
was used to determine the PAD value that causes correct
operation. The only variable in this program is the ammount
of PAD added to the malloc() size.
The behavior seems to be sensitive to the input file size.
Some files fail with a zero pad and others succeed. The
reason for this behavior is unclear to me. On some files I
have seen a core dump, but I can no longer recreate one.
Success is indicated by a "status = 0".
Hope this helps target the problem.
Test output: —--------------------------------------------------------------------
bash.exe-2.02$ ./readtest 0 3 readtest.c
PAD = 0, st_size = 2864, bufsize = 2864, count = 2766, status = -1
PAD = 0, st_size = 2864, bufsize = 2864, count = 2766, status = -1
PAD = 1, st_size = 2864, bufsize = 2865, count = 2766, status = -1
PAD = 0, st_size = 2864, bufsize = 2864, count = 2766, status = -1
PAD = 2, st_size = 2864, bufsize = 2866, count = 2766, status = -1
PAD = 0, st_size = 2864, bufsize = 2864, count = 2766, status = -1
PAD = 3, st_size = 2864, bufsize = 2867, count = 2766, status = -1
PAD = 0, st_size = 2864, bufsize = 2864, count = 2766, status = -1
bash.exe-2.02$ ./readtest 51 54 readtest.c
PAD = 51, st_size = 2864, bufsize = 2915, count = 2766, status = -1
PAD = 0, st_size = 2864, bufsize = 2864, count = 2766, status = -1
PAD = 52, st_size = 2864, bufsize = 2916, count = 2766, status = -1
PAD = 0, st_size = 2864, bufsize = 2864, count = 2766, status = -1
PAD = 53, st_size = 2864, bufsize = 2917, count = 2766, status = 0
PAD = 0, st_size = 2864, bufsize = 2864, count = 2766, status = 0
PAD = 54, st_size = 2864, bufsize = 2918, count = 2766, status = 0
PAD = 0, st_size = 2864, bufsize = 2864, count = 2766, status = 0
bash.exe-2.02$
—---------------------------------------------------------------------------------------
>>> Eli Zaretskii <[EMAIL PROTECTED]> 1999-12-01 02:38:07 >>>
On Wed, 1 Dec 1999, Brian J. Fox wrote:
> Is it possible that you are somehow using Cygwin in a mode where the
> default character type is a wide 16-bit character (i.e., Unicode)?
>
> No, the right thing is to use O_BINARY in the call to read();.
Are you saying that the default mode transparently expands characters
into wide characters on Cygwin?
The current assumption is that `stat' never underestimates the amount of
bytes you wind up with after reading the file, it can only overestimate
it. If that breaks in the case in point, then something should be done
about it. But I'm not sure O_BINARY is the right thing in this case.
#!/gnu/cygwin-b20/H-i586-cygwin32/bin/bash
# runreadtest - run "readtest" in a loop with PAD (0 to 2048)
let n=0
while (( $n < 2048 ))
do
if ./readtest $n $n $1; then exit; fi
let n=n+1
done
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
/*--------------------------------------------------------------------------*
* Usage: readtest pad-count max-pad input-file
* Execute once with the provided buffer PAD, and a second time with 0 PAD.
*--------------------------------------------------------------------------*/
main( int argc, char* argv[] )
{
struct stat fileinfo;
int fd;
int malloc_size;
int pad_count = 0;
int max_pad = 0;
int count = 0;
int bytes = 0;
int iter;
char* input_file_name;
char* buf;
if ( argc <= 3 )
{
fprintf( stderr,
"Usage: readtest pad_count max_pad input-input_file_name\n"
"Missing parameter!\n" );
exit( 1 );
}
pad_count = atoi( argv[1] );
max_pad = atoi( argv[2] );
input_file_name = argv[3];
for ( ; pad_count <= max_pad; ++pad_count )
{
/* First try with provided PAD */
count = bytes = 0;
fprintf( stderr, "PAD = %5d,", pad_count );
if ( (fd = open( input_file_name, O_RDONLY )) < 0 )
{
fprintf( stderr, "\topen( %s ): %s\n",
input_file_name, strerror( errno ) );
exit( 2 );
}
if ( stat( input_file_name, &fileinfo ) < 0 )
{
fprintf( stderr, "\tstat( %s ): %s\n",
input_file_name, strerror( errno ) );
exit( 3 );
}
fprintf( stderr, " st_size = %d,", fileinfo.st_size );
malloc_size = fileinfo.st_size + pad_count; /* PAD == pad_count */
if ( (buf = malloc( malloc_size )) == NULL )
{
fprintf( stderr, "malloc( %d ): %s\n",
fileinfo.st_size, strerror( errno ) );
exit( 4 );
}
while ((bytes = read (fd, buf+bytes, fileinfo.st_size )) > 0)
count += bytes;
fprintf( stderr, " bufsize = %d, count = %d, status = %d\n",
malloc_size, count, bytes );
free( buf );
close( fd );
/* Second Try With 0 PAD */
count = bytes = 0;
fprintf( stderr, "PAD = 0," );
if ( (fd = open( input_file_name, O_RDONLY )) < 0 )
{
fprintf( stderr, "\topen( %s ): %s\n",
input_file_name, strerror( errno ) );
exit( 4 );
}
if ( stat( input_file_name, &fileinfo ) < 0 )
{
fprintf( stderr, "\tstat( %s ): %s\n"
, input_file_name, strerror( errno ) );
exit( 5 );
}
fprintf( stderr, " st_size = %d,", fileinfo.st_size );
malloc_size = fileinfo.st_size; /* PAD == 0 */
if ( (buf = malloc( malloc_size )) == NULL )
{
fprintf( stderr, "\tmalloc( %d ): %s\n",
fileinfo.st_size, strerror( errno ) );
exit( 6 );
}
while ((bytes = read (fd, buf+bytes, fileinfo.st_size )) > 0)
count += bytes;
fprintf( stderr, " bufsize = %d, count = %d, status = %d\n",
malloc_size, count, bytes );
free( buf );
close( fd );
fprintf( stderr, "\n" );
}
return 1;
}