error on os.open API
Eryk Sun
eryksun at gmail.com
Tue Apr 6 21:38:06 EDT 2021
On 4/5/21, Rami Khaldi <khaldi.rami at gmail.com> wrote:
>
> It seems that the os.open API cannot distinguish between a permission error
> and the fact that a directory cannot be opened like files.
> The following script reproduces the scenario (tested on Python 3.8.2
> (tags/v3.8.2:7b3ab59, Feb 25 2020, 22:45:29) [MSC v.1916 32 bit (Intel)] on
> win32) :
In Windows, C open() calls WinAPI CreateFileW(), which defaults to
opening regular files by default, i.e. it calls the NTAPI
NtCreateFile() system function with the option
FILE_NON_DIRECTORY_FILE.
If the filesystem supports file streams (NTFS, ReFS), then the primary
stream in a directory is an index stream of type $INDEX_ALLOCATION. (A
directory can also have $DATA streams, but I digress.) An open can
override the FILE_NON_DIRECTORY_FILE option by explicitly opening the
index stream in the directory. For example:
fd = os.open('someDirectory::$INDEX_ALLOCATION', 0)
Alternatively, if CreateFileW() is called with the flag
FILE_FLAG_BACKUP_SEMANTICS, then it does not use the NtCreateFile()
option FILE_NON_DIRECTORY_FILE to limit the open type. This means
directories can be opened. If you want to limit this case to just
opening directories, add a trailing slash to the name.
The Universal C Runtime has an undocumented flag for C open() --
_O_OBTAIN_DIR (0x2000) -- which makes it use the CreateFileW() flag
FILE_FLAG_BACKUP_SEMANTICS. So you can also open "someDirectory" in
Windows in Python 3.5 and later as follows:
fd = os.open('someDirectory', 0x2000)
or
fd = os.open('someDirectory/', 0x2000)
> *Traceback (most recent call last): File "<stdin>", line 1, in
> <module>PermissionError: [Errno 13] Permission denied: 'someDirectory'*
Unfortunately, there are 4 layers of errors when traversing the APIs
involved here: Python <-> C <-> WinAPI <-> NTAPI. Important and
helpful details are often lost. When an NtCreateFile() system call
fails because an attempt was made to open a directory as a file, the
status code explains itself: STATUS_FILE_IS_A_DIRECTORY (0xC00000BA).
WinAPI CreateFileW() unhelpfully translates this status code to
ERROR_ACCESS_DENIED (5). Finally, C open() translates the Windows
error code as EACCES (13). Unfortunately the interpreter doesn't have
enough information to know that it should raise IsADirectoryError
instead of PermissionError.
More information about the Python-list
mailing list