On 4/5/21, Rami Khaldi <khaldi.r...@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.
-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to