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;
}

Reply via email to