public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* write() on 64 bit platform sometimes returns 32bit -1 as error indicator
@ 2020-04-23 19:36 netbsdrat
  2020-04-24 14:42 ` Corinna Vinschen
  0 siblings, 1 reply; 4+ messages in thread
From: netbsdrat @ 2020-04-23 19:36 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 3180 bytes --]

 
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.
 
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?  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.
 
The write did not succeed though.  No data was written to the floppy.
Errno is set indicating an error (13 'Permission denied'), but the return
value from write() is not correct for this situation.  Thus the write
failure cannot
be detected (except by looking at errno)!  BTW, return value in this
case == -1U, but not == -1.
 
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.
 
So I think that somewhere in the myriad of pathways between 32 / 64 bit
way down in the depths of cygwin, this unusual write error triggers a return
value of 32 bit -1 instead of 64 bit -1.
 
Is this cygwin issue?  gcc issue?  libc issue??


Thanks,

John Refling



PS:  Equally odd is the errno of 13, 'permission denied' with a different
buffer size.  You can write 512 bytes after getting the permission denied,
and then after that, write as many bytes as you want without 'permission
denied'.  Some strange things in windows, cygwin, or the interaction of the
two. 

Output of attached sample programs:


/* CaseA OUTPUT, here we test 512 which works.

	open floppy, which is OK
	fno = 3, errno = 0 'No error'
	ie: fopen() OK

	try write() 512 which is OK
	RV = 0x200 or 512, errno = 0 'No error'

	Write OK!

*/

/* CaseB OUTPUT: this case triggers bad return value

	open floppy, which is OK
	fno = 3, errno = 0 'No error'
	ie: fopen() OK

	try write() 5120 which is NOT ok, sometimes.

	RV = 0xffffffff or 4294967295, errno = 13 'Permission denied'
	but nothing actually written

	RV IS NOT == 0
	RV IS NOT < 0
	RV IS NOT == -1
	RV IS NOT == -1L
	RV IS == -1U			!!!  32 bit -1  !!!

	no way to detect this write() failure!

*/

/* CaseC OUTPUT: this case shows usual correct return value for fail

	open fake file, which fails, as expected
	fno = -1, errno = 2 'No such file or directory'

	try write() 512 to bad file, expect fail
	RV = 0xffffffffffffffff or -1, errno = 9 'Bad file descriptor'

	RV IS NOT == 0
	RV IS < 0
	RV IS == -1
	RV IS == -1L
	RV IS NOT == -1U

	can detect this failure.

*/


[-- Attachment #2: caseA.c --]
[-- Type: application/octet-stream, Size: 1541 bytes --]

#define BUFSIZZ 512

// caseA: 512 works always, more causes an error SOMETIMES, see caseB.
// john refling.  caseA.c

/* OUTPUT, here we test 512 which works.

	open floppy, which is OK
	fno = 3, errno = 0 'No error'
	ie: fopen() OK

	try write() 512 which is OK
	RV = 0x200 or 512, errno = 0 'No error'

	Write OK!

*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <err.h>
#include <sys/fcntl.h>

int main(int argc, char *argv[]) {

	char *buf = calloc(1, BUFSIZZ);

	printf("\nopen floppy, which is OK\n");
	int fno = open("/dev/floppy", O_RDWR, 0777);
	printf("fno = %d, errno = %d '%s'\n", fno, errno, strerror(errno));
	printf("ie: fopen() OK\n\n");

	// write some data to the floppy, when this fails,
	// it seems to put a "32 bit -1" in return value,
	// not a 64 bit -1 !!!

	printf("try write() 512 which is OK\n");
	errno = 0;
	ssize_t RV = write(fno, buf, BUFSIZZ);

	// print out the RV, it is a ssize_t, use %ld
	printf("RV = 0x%lx or %ld, errno = %d '%s'\n\nWrite OK!\n", (long unsigned)RV, RV, errno,
		strerror(errno));

	if (512 == RV) return(0);

	// see what constants RV matches:
	fprintf(stderr, "RV %s == 0\n", (RV == 0)?"IS":"IS NOT");
	fprintf(stderr, "RV %s < 0\n", (RV < 0)?"IS":"IS NOT");
	fprintf(stderr, "RV %s == -1\n", (RV == -1)?"IS":"IS NOT");
	fprintf(stderr, "RV %s == -1L\n", (RV == -1L)?"IS":"IS NOT");
	fprintf(stderr, "RV %s == -1U\n\n", (RV == -1U)?"IS":"IS NOT");

	return 0;
}

[-- Attachment #3: caseC.c --]
[-- Type: application/octet-stream, Size: 1685 bytes --]

#define BUFSIZZ 512

// caseC: do something that we know returns -1
// failure to make sure we understand data sizes.
// john refling.  caseC.c

/* OUTPUT: this case shows correct return value for fail

	open fake file, which fails, as expected
	fno = -1, errno = 2 'No such file or directory'

	try write() 512 to bad file, expect fail
	RV = 0xffffffffffffffff or -1, errno = 9 'Bad file descriptor'

	RV IS NOT == 0
	RV IS < 0
	RV IS == -1
	RV IS == -1L
	RV IS NOT == -1U

	can detect this failure.

*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <err.h>
#include <sys/fcntl.h>

int main(int argc, char *argv[]) {

	char *buf = calloc(1, BUFSIZZ);

	printf("\nopen fake file, which fails, as expected\n");
	int fno = open("/dev/flopZpy", O_RDWR, 0777);
	printf("fno = %d, errno = %d '%s'\n", fno, errno, strerror(errno));

	// write some data to bad file number

	printf("\ntry write() 512 to bad file, expect fail\n");
	errno = 0;
	ssize_t RV = write(fno, buf, BUFSIZZ);

	// print out the RV, it is a ssize_t, use %ld

	printf("RV = 0x%lx or %ld, errno = %d '%s'\n\n", (long unsigned)RV, RV, errno,
		strerror(errno));

	if (512 == RV) return(0);

	// see what constants RV matches:

	fprintf(stderr, "RV %s == 0\n", (RV == 0)?"IS":"IS NOT");
	fprintf(stderr, "RV %s < 0\n", (RV < 0)?"IS":"IS NOT");
	fprintf(stderr, "RV %s == -1\n", (RV == -1)?"IS":"IS NOT");
	fprintf(stderr, "RV %s == -1L\n", (RV == -1L)?"IS":"IS NOT");
	fprintf(stderr, "RV %s == -1U\n\n", (RV == -1U)?"IS":"IS NOT");

	fprintf(stderr, "can detect this failure.\n");

	return 0;
}

[-- Attachment #4: caseB.c --]
[-- Type: application/octet-stream, Size: 2014 bytes --]

#define BUFSIZZ 5120

// caseB: 5120 fails soon after a windows format a:
// maybe there is an error or not, from windows.
// hard to tell, but in any case, the return value
// is not correct.  If it works once then you
// can use any size after that point.
// john refling.  caseB.c

/* OUTPUT: this case triggers bad return value

	open floppy, which is OK
	fno = 3, errno = 0 'No error'
	ie: fopen() OK

	try write() 5120 which is NOT ok, sometimes.

	RV = 0xffffffff or 4294967295, errno = 13 'Permission denied'
	but nothing actually written

	RV IS NOT == 0
	RV IS NOT < 0
	RV IS NOT == -1
	RV IS NOT == -1L
	RV IS == -1U			!!!  32 bit -1  !!!

	no way to detect this write() failure!

*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <err.h>
#include <sys/fcntl.h>

int main(int argc, char *argv[]) {

	char *buf = calloc(1, BUFSIZZ);

	printf("\nopen floppy, which is OK\n");
	int fno = open("/dev/floppy", O_RDWR, 0777);
	printf("fno = %d, errno = %d '%s'\n", fno, errno, strerror(errno));
	printf("ie: fopen() OK\n\n");

	// write some data to the floppy, when this fails,
	// it seems to put a "32 bit -1" in return value,
	// not a 64 bit -1 !!!

	printf("try write() 5120 which is NOT ok\n");
	errno = 0;
	ssize_t RV = write(fno, buf, BUFSIZZ);

	// print out the RV, it is a ssize_t, use %ld

	printf("RV = 0x%lx or %ld, errno = %d '%s'\n\nbut nothing actually written\n", (long unsigned)RV, RV, errno,
		strerror(errno));

	if (512 == RV) return(0);

	// see what constants RV matches:

	fprintf(stderr, "RV %s == 0\n", (RV == 0)?"IS":"IS NOT");
	fprintf(stderr, "RV %s < 0\n", (RV < 0)?"IS":"IS NOT");
	fprintf(stderr, "RV %s == -1\n", (RV == -1)?"IS":"IS NOT");
	fprintf(stderr, "RV %s == -1L\n", (RV == -1L)?"IS":"IS NOT");
	fprintf(stderr, "RV %s == -1U\n\n", (RV == -1U)?"IS":"IS NOT");

	fprintf(stderr, "\nno way to detect this failure!\n");

	return 0;
}

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: write() on 64 bit platform sometimes returns 32bit -1 as error indicator
  2020-04-23 19:36 write() on 64 bit platform sometimes returns 32bit -1 as error indicator netbsdrat
@ 2020-04-24 14:42 ` Corinna Vinschen
  2020-04-24 22:01   ` Brian Inglis
  0 siblings, 1 reply; 4+ messages in thread
From: Corinna Vinschen @ 2020-04-24 14:42 UTC (permalink / raw)
  To: netbsdrat; +Cc: cygwin

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

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: write() on 64 bit platform sometimes returns 32bit -1 as error indicator
  2020-04-24 14:42 ` Corinna Vinschen
@ 2020-04-24 22:01   ` Brian Inglis
  2020-04-27  8:43     ` Corinna Vinschen
  0 siblings, 1 reply; 4+ messages in thread
From: Brian Inglis @ 2020-04-24 22:01 UTC (permalink / raw)
  To: cygwin

On 2020-04-24 08:42, Corinna Vinschen wrote:
> 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.

MS are blocking access to earlier unsupported (all Vista extended support ended
2017-04-11) system info:

[ Vista kb942448 🔎]

support.microsoft.com [links to https://support.microsoft.com/kb/942448]
We would like to show you a description here but the site won’t allow us.

Still readable via:

https://web.archive.org/web/20180217230150/https://support.microsoft.com/en-us/help/942448/changes-to-the-file-system-and-to-the-storage-stack-to-restrict-direct

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada

This email may be disturbing to some readers as it contains
too much technical detail. Reader discretion is advised.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: write() on 64 bit platform sometimes returns 32bit -1 as error indicator
  2020-04-24 22:01   ` Brian Inglis
@ 2020-04-27  8:43     ` Corinna Vinschen
  0 siblings, 0 replies; 4+ messages in thread
From: Corinna Vinschen @ 2020-04-27  8:43 UTC (permalink / raw)
  To: cygwin

On Apr 24 16:01, Brian Inglis wrote:
> On 2020-04-24 08:42, Corinna Vinschen wrote:
> > 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.
> 
> MS are blocking access to earlier unsupported (all Vista extended support ended
> 2017-04-11) system info:
> 
> [ Vista kb942448 🔎]

That doesn't make sense.  The KB article describes a change in the ABI
affecting all Windows versions since Vista.  It's not only affecting
Vista alone.  Thus the KB article is still important, especially given
the MSDN library man pages (e.g. CreateFileA) refer to it.  I added
feedback to this effect on the MSDN man pages, hopefully somebody
actually reads them and reactivates the KB article.

Besides, deleting history doesn't make sense at all.

> support.microsoft.com [links to https://support.microsoft.com/kb/942448]
> We would like to show you a description here but the site won’t allow us.
> 
> Still readable via:
> 
> https://web.archive.org/web/20180217230150/https://support.microsoft.com/en-us/help/942448/changes-to-the-file-system-and-to-the-storage-stack-to-restrict-direct

Great, thanks for the URL!  This also shows that my description above
is not entirely correct :)


Corinna

-- 
Corinna Vinschen
Cygwin Maintainer

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-04-27  8:43 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-23 19:36 write() on 64 bit platform sometimes returns 32bit -1 as error indicator netbsdrat
2020-04-24 14:42 ` Corinna Vinschen
2020-04-24 22:01   ` Brian Inglis
2020-04-27  8:43     ` Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).