|
24 | 24 | import sys |
25 | 25 | import sysconfig |
26 | 26 | import tempfile |
| 27 | +import textwrap |
27 | 28 | import time |
28 | 29 | import types |
29 | 30 | import unittest |
@@ -2883,6 +2884,49 @@ def test_getfinalpathname_handles(self): |
2883 | 2884 |
|
2884 | 2885 | self.assertEqual(0, handle_delta) |
2885 | 2886 |
|
| 2887 | + @support.requires_subprocess() |
| 2888 | + def test_stat_unlink_race(self): |
| 2889 | + # bpo-46785: the implementation of os.stat() falls back to reading |
| 2890 | + # the parent directory if CreateFileW() fails with a permission |
| 2891 | + # error. If reading the parent directory fails because the file or |
| 2892 | + # directory are subsequently unlinked, or because the volume or |
| 2893 | + # share are no longer available, then the original permission error |
| 2894 | + # should not be restored. |
| 2895 | + filename = os_helper.TESTFN |
| 2896 | + self.addCleanup(os_helper.unlink, filename) |
| 2897 | + deadline = time.time() + 5 |
| 2898 | + command = textwrap.dedent("""\ |
| 2899 | + import os |
| 2900 | + import sys |
| 2901 | + import time |
| 2902 | +
|
| 2903 | + filename = sys.argv[1] |
| 2904 | + deadline = float(sys.argv[2]) |
| 2905 | +
|
| 2906 | + while time.time() < deadline: |
| 2907 | + try: |
| 2908 | + with open(filename, "w") as f: |
| 2909 | + pass |
| 2910 | + except OSError: |
| 2911 | + pass |
| 2912 | + try: |
| 2913 | + os.remove(filename) |
| 2914 | + except OSError: |
| 2915 | + pass |
| 2916 | + """) |
| 2917 | + |
| 2918 | + with subprocess.Popen([sys.executable, '-c', command, filename, str(deadline)]) as proc: |
| 2919 | + while time.time() < deadline: |
| 2920 | + try: |
| 2921 | + os.stat(filename) |
| 2922 | + except FileNotFoundError as e: |
| 2923 | + assert e.winerror == 2 # ERROR_FILE_NOT_FOUND |
| 2924 | + try: |
| 2925 | + proc.wait(1) |
| 2926 | + except subprocess.TimeoutExpired: |
| 2927 | + proc.terminate() |
| 2928 | + |
| 2929 | + |
2886 | 2930 | @os_helper.skip_unless_symlink |
2887 | 2931 | class NonLocalSymlinkTests(unittest.TestCase): |
2888 | 2932 |
|
|
0 commit comments