mirror of
https://github.com/python/cpython.git
synced 2025-11-02 19:12:55 +00:00
bpo-46785: Fix race condition between os.stat() and unlink on Windows (GH-31858)
This commit is contained in:
parent
ebb8b512e9
commit
39e6b8ae6a
4 changed files with 57 additions and 1 deletions
|
|
@ -24,6 +24,7 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
import sysconfig
|
import sysconfig
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import textwrap
|
||||||
import time
|
import time
|
||||||
import types
|
import types
|
||||||
import unittest
|
import unittest
|
||||||
|
|
@ -2883,6 +2884,49 @@ class Win32NtTests(unittest.TestCase):
|
||||||
|
|
||||||
self.assertEqual(0, handle_delta)
|
self.assertEqual(0, handle_delta)
|
||||||
|
|
||||||
|
@support.requires_subprocess()
|
||||||
|
def test_stat_unlink_race(self):
|
||||||
|
# bpo-46785: the implementation of os.stat() falls back to reading
|
||||||
|
# the parent directory if CreateFileW() fails with a permission
|
||||||
|
# error. If reading the parent directory fails because the file or
|
||||||
|
# directory are subsequently unlinked, or because the volume or
|
||||||
|
# share are no longer available, then the original permission error
|
||||||
|
# should not be restored.
|
||||||
|
filename = os_helper.TESTFN
|
||||||
|
self.addCleanup(os_helper.unlink, filename)
|
||||||
|
deadline = time.time() + 5
|
||||||
|
command = textwrap.dedent("""\
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
filename = sys.argv[1]
|
||||||
|
deadline = float(sys.argv[2])
|
||||||
|
|
||||||
|
while time.time() < deadline:
|
||||||
|
try:
|
||||||
|
with open(filename, "w") as f:
|
||||||
|
pass
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
os.remove(filename)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
|
||||||
|
with subprocess.Popen([sys.executable, '-c', command, filename, str(deadline)]) as proc:
|
||||||
|
while time.time() < deadline:
|
||||||
|
try:
|
||||||
|
os.stat(filename)
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
assert e.winerror == 2 # ERROR_FILE_NOT_FOUND
|
||||||
|
try:
|
||||||
|
proc.wait(1)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
proc.terminate()
|
||||||
|
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
class NonLocalSymlinkTests(unittest.TestCase):
|
class NonLocalSymlinkTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1705,6 +1705,7 @@ Anthony Starks
|
||||||
David Steele
|
David Steele
|
||||||
Oliver Steele
|
Oliver Steele
|
||||||
Greg Stein
|
Greg Stein
|
||||||
|
Itai Steinherz
|
||||||
Marek Stepniowski
|
Marek Stepniowski
|
||||||
Baruch Sterin
|
Baruch Sterin
|
||||||
Chris Stern
|
Chris Stern
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Fix race condition between :func:`os.stat` and unlinking a file on Windows, by using errors codes returned by ``FindFirstFileW()`` when appropriate in ``win32_xstat_impl``.
|
||||||
|
|
@ -1890,7 +1890,17 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result,
|
||||||
/* Try reading the parent directory. */
|
/* Try reading the parent directory. */
|
||||||
if (!attributes_from_dir(path, &fileInfo, &tagInfo.ReparseTag)) {
|
if (!attributes_from_dir(path, &fileInfo, &tagInfo.ReparseTag)) {
|
||||||
/* Cannot read the parent directory. */
|
/* Cannot read the parent directory. */
|
||||||
SetLastError(error);
|
switch (GetLastError()) {
|
||||||
|
case ERROR_FILE_NOT_FOUND: /* File cannot be found */
|
||||||
|
case ERROR_PATH_NOT_FOUND: /* File parent directory cannot be found */
|
||||||
|
case ERROR_NOT_READY: /* Drive exists but unavailable */
|
||||||
|
case ERROR_BAD_NET_NAME: /* Remote drive unavailable */
|
||||||
|
break;
|
||||||
|
/* Restore the error from CreateFileW(). */
|
||||||
|
default:
|
||||||
|
SetLastError(error);
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue