write() on 64 bit platform sometimes returns 32bit -1 as error indicator

Corinna Vinschen corinna-cygwin@cygwin.com
Fri Apr 24 14:42:06 GMT 2020


Hi John,

On Apr 23 12:36, netbsdrat--- via Cygwin wrote:
>  
> write() on 64 bit platform sometimes returns 32bit -1 as error indicator:
>  
> Using 64 bit cygwin on 64 bit platform.  Doing direct read() / write of
> disks,
> this example is using the /dev/floppy device.
>  
> Opening for writing floppy device using open() succeeds.

Thanks for the test cases.

> 2 cases:
>  
> CaseA) write() a 512 byte buffer to the floppy, succeeds with return
> value of 512, errno = 0.  This works.
>  
> CaseB) write() a 5120 byte buffer to the floppy.  This fails if we have
> recently
> formatted the floppy with windows.  Perhaps windows still has some file
> descriptor to the floppy open?

This problem is due to a restriction in Windows introduced with Windows
Vista.  In theory it gets explained at length in "Changes to the file
system and to the storage stack to restrict direct disk access and
direct volume access in Windows Vista and in Windows Server 2008" in the
Help and Support Knowledge Base at http://support.microsoft.com/kb/942448.
Unfortunately, this KB article is current unaccessible for some reason.

Basically, the restriction is that you have to lock all partitions you
want to write to via raw disk access.  So if a write() crosses a
partition boundary, you have to lock both partitions.  Before you ask,
the boot sector on a floppy is a partition on its own, just like, e. g.,
the MBR or the GPT sectors on a hard disk or ssd.

Cygwin has code which performs all necessary locking and it fails if
the locking isn't possible.  However, this code was only called for
disks so far, not for floppies.

> But this is not the point.
>  
> The point is that the return value from the write() is 4294967295
> (0xffffffff).
> This value is a 32 bit -1.  When we compare the return value to -1 (64 bit),
> the compare fails, which indicates that the write succeeded, and implies
> that
> 4294967295 bytes were written.

Got it, there was a wrong cast which lead to the return value -1 being
written as DWORD value, rather than as ssize_t value, as intended.

> [...]
> CaseC) As a third control case to make sure that I was understanding all the
> data
> widths, I tried opening a fake file, and doing the same write to it,
> expecting an error.  The error propagated correctly... the return value
> of writing to a bad file descriptor was 64 bit -1 (0xffffffffffffffff)
> and can be compared to -1 directly to detect the error.  Errno is set
> correctly.

raw writes are performed in another function than file writes, so this
particular problem was restricted to raw disk I/O.

I pushed three patches and uploaded a new developer snapshot to
https://cygwin.com/snapshots/  Please give it a try.


Thanks,
Corinna

-- 
Corinna Vinschen
Cygwin Maintainer


More information about the Cygwin mailing list