gh-104803: Implement ntpath.isdevdrive for checking whether a path is on a Windows Dev Drive (GH-104805)

(cherry picked from commit bfd20d257e)

Co-authored-by: Steve Dower <steve.dower@python.org>
This commit is contained in:
Miss Islington (bot) 2023-05-29 05:36:08 -07:00 committed by GitHub
parent 5dc6b18cb0
commit 635ce29257
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 216 additions and 1 deletions

View file

@ -4530,6 +4530,95 @@ exit:
}
/*[clinic input]
os._path_isdevdrive
path: path_t
Determines whether the specified path is on a Windows Dev Drive.
[clinic start generated code]*/
static PyObject *
os__path_isdevdrive_impl(PyObject *module, path_t *path)
/*[clinic end generated code: output=1f437ea6677433a2 input=ee83e4996a48e23d]*/
{
#ifndef PERSISTENT_VOLUME_STATE_DEV_VOLUME
/* This flag will be documented at
https://learn.microsoft.com/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_fs_persistent_volume_information
after release, and will be available in the latest WinSDK.
We include the flag to avoid a specific version dependency
on the latest WinSDK. */
const int PERSISTENT_VOLUME_STATE_DEV_VOLUME = 0x00002000;
#endif
int err = 0;
PyObject *r = NULL;
wchar_t volume[MAX_PATH];
Py_BEGIN_ALLOW_THREADS
if (!GetVolumePathNameW(path->wide, volume, MAX_PATH)) {
/* invalid path of some kind */
/* Note that this also includes the case where a volume is mounted
in a path longer than 260 characters. This is likely to be rare
and problematic for other reasons, so a (soft) failure in this
check seems okay. */
err = GetLastError();
} else if (GetDriveTypeW(volume) != DRIVE_FIXED) {
/* only care about local dev drives */
r = Py_False;
} else {
HANDLE hVolume = CreateFileW(
volume,
FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
if (hVolume == INVALID_HANDLE_VALUE) {
err = GetLastError();
} else {
FILE_FS_PERSISTENT_VOLUME_INFORMATION volumeState = {0};
volumeState.Version = 1;
volumeState.FlagMask = PERSISTENT_VOLUME_STATE_DEV_VOLUME;
if (!DeviceIoControl(
hVolume,
FSCTL_QUERY_PERSISTENT_VOLUME_STATE,
&volumeState,
sizeof(volumeState),
&volumeState,
sizeof(volumeState),
NULL,
NULL
)) {
err = GetLastError();
}
CloseHandle(hVolume);
if (err == ERROR_INVALID_PARAMETER) {
/* not supported on this platform */
r = Py_False;
} else if (!err) {
r = (volumeState.VolumeFlags & PERSISTENT_VOLUME_STATE_DEV_VOLUME)
? Py_True : Py_False;
}
}
}
Py_END_ALLOW_THREADS
if (err) {
PyErr_SetFromWindowsErr(err);
return NULL;
}
if (r) {
return Py_NewRef(r);
}
return NULL;
}
int
_PyOS_getfullpathname(const wchar_t *path, wchar_t **abspath_p)
{
@ -15797,6 +15886,7 @@ static PyMethodDef posix_methods[] = {
OS_SETNS_METHODDEF
OS_UNSHARE_METHODDEF
OS__PATH_ISDEVDRIVE_METHODDEF
OS__PATH_ISDIR_METHODDEF
OS__PATH_ISFILE_METHODDEF
OS__PATH_ISLINK_METHODDEF