Subject: Re: lseek + read = ENOENT
From: [email-masked] (Eric Blake)
To: [email-masked], [email-masked]
Cc: Sam Steingold <[email-masked]>
Date: Fri, 20 Jan 2006 02:34:35 +0000

> I cannot read the last 4-byte word in a file using lseek + read:
> 
> /* file "foo" exists and is large enough - say, 4 MB */
>   int fd = open("foo",O_RDONLY|O_BINARY);
>   uint32 data;
> /* this succeeds and correctly returns the size of file "foo" minus 4 */
>   lseek(fd,-sizeof(data),SEEK_END);
> /* this returns 0 -- instead of the expected 4 -- and sets errno to ENOENT */
>   read(fd,&data,sizeof(data));
> 
> if I run this under gdb and type
>   lseek(fd,-sizeof(data),SEEK_END);
>   read(fd,&data,sizeof(data));
> several times, eventually read() starts to return 4 and set data to the
> value I actually wrote into "foo" last.
> 
> I observe this on linux, cygwin and solaris -- what am I doing wrong?

It would have been nicer if you had provided a small example that would
compile out of the box; that would show whether you remembered to
#include <unistd.h>.

One thing you did wrong was not checking the return value of lseek.  For
all you know, the system might have been trying to tell you your lseek
was invalid, but you ignored it and proceeded on with the read anyway.

The other thing you did wrong: on cygwin, off_t is a 64-bit signed type,
but the sizeof operator is of type size_t, which is only a 32-bit unsigned
type.  The unary - on an unsigned 32-bit number is an unsigned 32-bit
number, then you promote that argument to off_t (32-bit unsigned to
64-bit signed promotion is 0-extended).  So you were calling
lseek(fd, 0x00000000fffffffcLL, SEEK_END), which is certainly
different than the intended lseek(fd, 0xfffffffffffffffcLL, SEEK_END).

--
Eric Blake

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/