Eryk Sun <eryk...@gmail.com> added the comment:

Itai, you can add a test to Win32NtTests in Lib/test/test_os.py. Maybe spawn a 
child process that creates and unlinks a file in a loop. In the parent process 
execute a loop that tries to stat the file and ignores errors when the file or 
path isn't found. For example:

    @support.requires_subprocess()
    def test_stat_unlink_race(self):
        # bpo-46785: the implementation of os.stat() falls back on reading
        # the parent directory if CreateFileW() fails with a permission
        # error. If reading the parent directory fails because the file or
        # directory is subsequently unlinked or because the volume or
        # share is no longer available, then the original permission error
        # should not be restored.
        fname = os.path.join(os.environ['TEMP'], os_helper.TESTFN + '_46785')
        self.addCleanup(os_helper.unlink, fname)
        command = '''if 1:
            import os
            import sys
            fname = sys.argv[1]
            while True:
                try:
                    with open(fname, "w") as f:
                        pass
                except OSError:
                    pass
                try:
                    os.remove(fname)
                except OSError:
                    pass
        '''
        ignored_errors = (
            2,  # ERROR_FILE_NOT_FOUND
            3,  # ERROR_PATH_NOT_FOUND
            21, # ERROR_NOT_READY
            67, # ERROR_BAD_NET_NAME
        )
        deadline = time.time() + 5
        p = subprocess.Popen([sys.executable, '-c', command, fname])
        try:
            while time.time() < deadline:
                try:
                    os.stat(fname)
                except OSError as e:
                    if e.winerror not in ignored_errors:
                        raise
        finally:
            p.terminate()

As the above test shows, I think the error should also be kept if 
attributes_from_dir() fails with ERROR_NOT_READY or ERROR_BAD_NET_NAME. For 
example:

        switch (error) {
        case ERROR_ACCESS_DENIED:     /* Cannot sync or read attributes. */
        case ERROR_SHARING_VIOLATION: /* It's a paging file. */
            /* Try reading the parent directory. */
            if (!attributes_from_dir(path, &fileInfo, &tagInfo.ReparseTag)) {
                /* Cannot read the parent directory. */
                switch (GetLastError()) {
                // keep these error codes
                case ERROR_FILE_NOT_FOUND:
                case ERROR_PATH_NOT_FOUND:
                case ERROR_NOT_READY:
                case ERROR_BAD_NET_NAME:
                    break;
                // restore the error from CreateFileW()
                default:
                    SetLastError(error);
                }
                return -1;
            }

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue46785>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to