From 0b4dc4846b603025ee8da4403e87cad7739ac8f7 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Sat, 17 Sep 2016 15:49:59 +0300 Subject: Issue #28075: Check for ERROR_ACCESS_DENIED in Windows implementation of os.stat() Patch by Eryk Sun. --- Lib/test/test_os.py | 19 +++++++++++++++++++ Misc/NEWS | 3 +++ Modules/posixmodule.c | 6 ++++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index a1046b7..9189a82 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -432,6 +432,25 @@ class StatAttributeTests(unittest.TestCase): result.st_file_attributes & stat.FILE_ATTRIBUTE_DIRECTORY, stat.FILE_ATTRIBUTE_DIRECTORY) + @unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") + def test_access_denied(self): + # Default to FindFirstFile WIN32_FIND_DATA when access is + # denied. See issue 28075. + # os.environ['TEMP'] should be located on a volume that + # supports file ACLs. + fname = os.path.join(os.environ['TEMP'], self.fname) + self.addCleanup(support.unlink, fname) + create_file(fname, b'ABC') + # Deny the right to [S]YNCHRONIZE on the file to + # force CreateFile to fail with ERROR_ACCESS_DENIED. + DETACHED_PROCESS = 8 + subprocess.check_call( + ['icacls.exe', fname, '/deny', 'Users:(S)'], + creationflags=DETACHED_PROCESS + ) + result = os.stat(fname) + self.assertNotEqual(result.st_size, 0) + class UtimeTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS b/Misc/NEWS index f7fe181..8fbdd22 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -71,6 +71,9 @@ Core and Builtins Library ------- +- Issue #28075: Check for ERROR_ACCESS_DENIED in Windows implementation of + os.stat(). Patch by Eryk Sun. + - Issue #25270: Prevent codecs.escape_encode() from raising SystemError when an empty bytestring is passed. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index f6f08bf..becf654 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1515,7 +1515,9 @@ win32_xstat_impl(const char *path, struct _Py_stat_struct *result, /* Either the target doesn't exist, or we don't have access to get a handle to it. If the former, we need to return an error. If the latter, we can use attributes_from_dir. */ - if (GetLastError() != ERROR_SHARING_VIOLATION) + DWORD lastError = GetLastError(); + if (lastError != ERROR_ACCESS_DENIED && + lastError != ERROR_SHARING_VIOLATION) return -1; /* Could not get attributes on open file. Fall back to reading the directory. */ @@ -1525,7 +1527,7 @@ win32_xstat_impl(const char *path, struct _Py_stat_struct *result, if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { if (traverse) { /* Should traverse, but could not open reparse point handle */ - SetLastError(ERROR_SHARING_VIOLATION); + SetLastError(lastError); return -1; } } -- cgit v0.12