This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients Antony.Lee, eryksun, itaisteinherz, paul.moore, steve.dower, tim.golden, zach.ware
Date 2022-03-11.18:12:37
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1647022357.52.0.0978710709639.issue46785@roundup.psfhosted.org>
In-reply-to
Content
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;
            }
History
Date User Action Args
2022-03-11 18:12:37eryksunsetrecipients: + eryksun, paul.moore, tim.golden, zach.ware, Antony.Lee, steve.dower, itaisteinherz
2022-03-11 18:12:37eryksunsetmessageid: <1647022357.52.0.0978710709639.issue46785@roundup.psfhosted.org>
2022-03-11 18:12:37eryksunlinkissue46785 messages
2022-03-11 18:12:37eryksuncreate