[Python-Dev] RE: test_file failing on Windows

Tim Peters tim.one@home.com
Fri, 9 Nov 2001 15:57:43 -0500


[Jeremy]
> open_the_file() uses errno to check the return value of fopen().  On
> Windows, should it use GetLastError() ?

The MS docs don't document anything about fopen failure modes, beyond that
it returns NULL then.  Strongly doubt GetLastError would help, as that's
really for Win32 API calls ... OK, it's a bug in MS's internal _wopenfile.c:
if the first character of the mode string is not in "rwa", that routine
reutns NULL without setting errno.  OTOH, if the *prefix* of the mode string
is OK, it simply ignores trailing garbage (which, BTW, is OK by the C std):

>>> open('ga', 'wb and then a bunch of useless crap')
<open file 'ga', mode 'wb and then a bunch of useless crap' at 0x0078D6B0>
>>> open('ga', 'w!+ and the + is ignored')
<open file 'ga', mode 'w!+ and the + is ignored' at 0x0078D5A0>
>>>

> It seems that errno usually does the right thing on Windows, in that
> it's usually set to the expected error when fopen() fails.

Yes, but their error-in-mode code is braindead.  The lower-level MS _tsopen
does try to set errno on a bad mode:

        switch( oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR) ) {

            case _O_RDONLY:         /* read access */
                    fileaccess = GENERIC_READ;
                    break;
            case _O_WRONLY:         /* write access */
                    fileaccess = GENERIC_WRITE;
                    break;
            case _O_RDWR:           /* read and write access */
                    fileaccess = GENERIC_READ | GENERIC_WRITE;
                    break;
            default:                /* error, bad oflag */
                    errno = EINVAL;
                    _doserrno = 0L; /* not an OS error */
                    return -1;
        }

but the calling routine can't pass it a bad oflag so the EINVAL never
triggers.

> The change I made checks for EINVAL on Unix, which means the mode
> argument was invalid.  It looks like Windows sets errno to 0 in this
> case.

Actually not, and this looks like an arguable bug in our code:  we should
explictly set errno to 0 before calling fopen.  The errno we see after fopen
fails on Windows may be whatever value it had before the call.  I'll do
that.

> I wondered if GetLastError() would provide a more helpful error code.

Sorry, not in this case.