Issue 28075: os.stat fails when access is denied (original) (raw)
doing os.stat on the directory c:\config.msi gives different results on my Windows 10 machine, when done with py27 and py35
Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:24:40) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information.
import os os.stat('c:\config.msi') nt.stat_result(st_mode=16895, st_ino=0L, st_dev=0L, st_nlink=0, st_uid=0, st_gid=0, st_size=2891776L, st_atime=1473584558L, st_mtime=1473584558L, st_ctime=1449228297L)
Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22🔞55) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information.
import os os.stat('c:\config.msi') Traceback (most recent call last): File "", line 1, in PermissionError: [WinError 5] Zugriff verweigert: 'c:\config.msi'
-> Access denied
Python 3's os.stat tries to open a handle for the file or directory in order to call GetFileInformationByHandle. Opening a file handle via CreateFile requests at least FILE_READ_ATTRIBUTES and SYNCHRONIZE access when it calls NtCreateFile. If access is denied, os.stat is supposed to fall back on the basic WIN32_FIND_DATA information from FindFirstFile. However, it's not working as intended. For example:
>>> import os
>>> os.mkdir('test')
>>> os.system('icacls test /deny Users:(S,RA)')
processed file: test
Successfully processed 1 files; Failed processing 0 files
0
>>> os.stat('test')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
PermissionError: [WinError 5] Access is denied: 'test'
The problem is that it's mistakenly checking for ERROR_SHARING_VIOLATION instead of ERROR_ACCESS_DENIED. Technically, getting a sharing violation should be impossible here. That only applies to requesting execute (traverse), read (list), write (add file), append (add subdirectory), or delete access for the contents of the file or directory, not its metadata.
After modifying the code to instead check for ERROR_ACCESS_DENIED, os.stat correctly falls back on using the file attributes from the WIN32_FIND_DATA:
>>> os.stat('test')
os.stat_result(st_mode=16895, st_ino=0, st_dev=0, st_nlink=0,
st_uid=0, st_gid=0, st_size=0, st_atime=1473589600,
st_mtime=1473589600, st_ctime=1473589600)