summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2024-01-12 15:53:27 (GMT)
committerGitHub <noreply@github.com>2024-01-12 15:53:27 (GMT)
commit7b7cf75c027ba453c6b6e20d245e7338c70f0a03 (patch)
tree9488331e6fea687d7c776fd4a11cf8bb2d6cf825 /Lib/test
parenteb22afb0042b09f05de5077c1947053dfbf7a5c0 (diff)
downloadcpython-7b7cf75c027ba453c6b6e20d245e7338c70f0a03.zip
cpython-7b7cf75c027ba453c6b6e20d245e7338c70f0a03.tar.gz
cpython-7b7cf75c027ba453c6b6e20d245e7338c70f0a03.tar.bz2
gh-111877: Fixes stat() handling for inaccessible files on Windows (GH-113716)
(cherry picked from commit ed066481c76c6888ff5709f5b9f93b92c232a4a6) Co-authored-by: Steve Dower <steve.dower@python.org>
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_os.py60
1 files changed, 60 insertions, 0 deletions
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 2d94951..fc58f8d 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -3077,6 +3077,66 @@ class Win32NtTests(unittest.TestCase):
except subprocess.TimeoutExpired:
proc.terminate()
+ @support.requires_subprocess()
+ def test_stat_inaccessible_file(self):
+ filename = os_helper.TESTFN
+ ICACLS = os.path.expandvars(r"%SystemRoot%\System32\icacls.exe")
+
+ with open(filename, "wb") as f:
+ f.write(b'Test data')
+
+ stat1 = os.stat(filename)
+
+ try:
+ # Remove all permissions from the file
+ subprocess.check_output([ICACLS, filename, "/inheritance:r"],
+ stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as ex:
+ if support.verbose:
+ print(ICACLS, filename, "/inheritance:r", "failed.")
+ print(ex.stdout.decode("oem", "replace").rstrip())
+ try:
+ os.unlink(filename)
+ except OSError:
+ pass
+ self.skipTest("Unable to create inaccessible file")
+
+ def cleanup():
+ # Give delete permission. We are the file owner, so we can do this
+ # even though we removed all permissions earlier.
+ subprocess.check_output([ICACLS, filename, "/grant", "Everyone:(D)"],
+ stderr=subprocess.STDOUT)
+ os.unlink(filename)
+
+ self.addCleanup(cleanup)
+
+ if support.verbose:
+ print("File:", filename)
+ print("stat with access:", stat1)
+
+ # First test - we shouldn't raise here, because we still have access to
+ # the directory and can extract enough information from its metadata.
+ stat2 = os.stat(filename)
+
+ if support.verbose:
+ print(" without access:", stat2)
+
+ # We cannot get st_dev/st_ino, so ensure those are 0 or else our test
+ # is not set up correctly
+ self.assertEqual(0, stat2.st_dev)
+ self.assertEqual(0, stat2.st_ino)
+
+ # st_mode and st_size should match (for a normal file, at least)
+ self.assertEqual(stat1.st_mode, stat2.st_mode)
+ self.assertEqual(stat1.st_size, stat2.st_size)
+
+ # st_ctime and st_mtime should be the same
+ self.assertEqual(stat1.st_ctime, stat2.st_ctime)
+ self.assertEqual(stat1.st_mtime, stat2.st_mtime)
+
+ # st_atime should be the same or later
+ self.assertGreaterEqual(stat1.st_atime, stat2.st_atime)
+
@os_helper.skip_unless_symlink
class NonLocalSymlinkTests(unittest.TestCase):