Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strange import errors with Python 3.12 on Windows #104820

Closed
pekkaklarck opened this issue May 23, 2023 · 2 comments
Closed

Strange import errors with Python 3.12 on Windows #104820

pekkaklarck opened this issue May 23, 2023 · 2 comments
Assignees
Labels
3.12 bugs and security fixes 3.13 bugs and security fixes OS-windows release-blocker type-bug An unexpected behavior, bug, or error

Comments

@pekkaklarck
Copy link

pekkaklarck commented May 23, 2023

I tried to test our project with Python 3.12 beta 1 on Windows but everything failed. After some debugging I noticed that module imports seem to fail when modules aren't on my C-drive:

C:\Users\peke>echo print(1) > test312.py

C:\Users\peke>py -3.12 -c "import test312"
1

C:\Users\peke>e:

E:\>echo print(1) > test312.py

E:\>py -3.12 -c "import test312"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'test312'

No problems with earlier Python versions:

E:\>py -3.11 -c "import test312"
1

Not sure does it matter, but I'm running Windows on VirtualBox and that E-drive is mapped to a directory on the Linux host.

Linked PRs

@pekkaklarck pekkaklarck added the type-bug An unexpected behavior, bug, or error label May 23, 2023
@eryksun
Copy link
Contributor

eryksun commented May 23, 2023

This is due to a bug in os.stat() for filesystems that lack support for FileIdInfo. The same bug is also the cause of the problem with pathlib.Path.is_dir() that's reported in gh-104806. pathlib.Path.is_dir() uses os.stat(), while ntpath.isdir() uses nt._path_isdir(). For example, volume "G:" on my system contains an exFAT filesystem, which doesn't support FileIdInfo.

>>> nt._path_isdir('G:\\')
True
>>> stat.S_ISDIR(os.stat('G:\\').st_mode)
False
>>> stat.S_ISBLK(os.stat('G:\\').st_mode)
True
>>> nt._path_isfile('G:\\spam.txt')
True
>>> stat.S_ISREG(os.stat('G:\\spam.txt').st_mode)
False
>>> stat.S_ISBLK(os.stat('G:\\spam.txt').st_mode)
True

As shown above, os.stat() is mistakenly reporting files and directories on this volume as block devices.

@zooba, in win32_xstat_slow_impl() in "Modules/posixmodule.c", the FileIdInfo request isn't universally supported by filesystem drivers. For example, it's not supported by FAT32/exFAT and, as demonstrated by this issue, it's not supported by the VirtualBox shared-folder filesystem.

        if (!GetFileInformationByHandle(hFile, &fileInfo) ||
            !GetFileInformationByHandleEx(hFile, FileBasicInfo,
                                          &basicInfo, sizeof(basicInfo)) ||
            !GetFileInformationByHandleEx(hFile, FileIdInfo,
                                          &idInfo, sizeof(idInfo))) {
            switch (GetLastError()) {
            case ERROR_INVALID_PARAMETER:
            case ERROR_INVALID_FUNCTION:
            case ERROR_NOT_SUPPORTED:
                /* Volumes and physical disks are block devices, e.g.
                   \\.\C: and \\.\PhysicalDrive0. */
                memset(result, 0, sizeof(*result));
                result->st_mode = 0x6000; /* S_IFBLK */
                goto cleanup;
            }
            retval = -1;
            goto cleanup;
        }

I'd add a new pointer variable, p_idInfo. If the request fails, set p_idInfo = NULL. Otherwise set p_idInfo = &idInfo. _Py_attribute_data_to_stat() in "Python/fileutils.c" falls back on the 64-bit file ID from the BY_HANDLE_FILE_INFORMATION if the id_info parameter is a NULL pointer.

Also, to err on the side of caution, _Py_attribute_data_to_stat() should fall back on the 64-bit file ID if the 128-bit file ID is 0 (i.e. both the low and high 64-bit parts are 0). The latter is the required value specified in [MS-FSCC] if a filesystem doesn't support a 128-bit file ID (even with the high 64-bit part set to 0) but for some reason the driver implements the FileIdInformation information class. I don't have an example of this. Usually it's either supported or requesting FileIdInformation fails, but the specification says we should be prepared to handle a zero value.

Also, when id_info is available, I'd prefer to use its 64-bit VolumeSerialNumber field for st_dev, which is consistent with the new by-name fast path. Else fall back on the 32-bit dwVolumeSerialNumber from the BY_HANDLE_FILE_INFORMATION. NTFS and ReFS have always supported a 64-bit volume serial number.

@eryksun
Copy link
Contributor

eryksun commented May 24, 2023

@zooba

Also, when id_info is available, I'd prefer to use its 64-bit VolumeSerialNumber field for st_dev

Sorry, Steve. I missed that you had already implemented this when I scanned over the code yesterday. I should have read it more carefully.

zooba added a commit that referenced this issue May 24, 2023
miss-islington pushed a commit to miss-islington/cpython that referenced this issue May 24, 2023
…ms that do not support FileIdInformation (pythonGH-104892)

(cherry picked from commit 6031727)

Co-authored-by: Steve Dower <steve.dower@python.org>
@zooba zooba closed this as completed May 24, 2023
zooba added a commit that referenced this issue May 29, 2023
…t do not support FileIdInformation (GH-104892)

(cherry picked from commit 6031727)

Co-authored-by: Steve Dower <steve.dower@python.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.12 bugs and security fixes 3.13 bugs and security fixes OS-windows release-blocker type-bug An unexpected behavior, bug, or error
Projects
Development

No branches or pull requests

3 participants