summaryrefslogtreecommitdiffstats
path: root/Modules/posixmodule.c
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2023-05-29 12:36:08 (GMT)
committerGitHub <noreply@github.com>2023-05-29 12:36:08 (GMT)
commit635ce29257a7f7272af009d3c08379522317d89b (patch)
treee94651f74c58ee00798cd3874733f9e93ad529d0 /Modules/posixmodule.c
parent5dc6b18cb0c83faab556b46bdcf96ce21880fa91 (diff)
downloadcpython-635ce29257a7f7272af009d3c08379522317d89b.zip
cpython-635ce29257a7f7272af009d3c08379522317d89b.tar.gz
cpython-635ce29257a7f7272af009d3c08379522317d89b.tar.bz2
gh-104803: Implement ntpath.isdevdrive for checking whether a path is on a Windows Dev Drive (GH-104805)
(cherry picked from commit bfd20d257e4ad16a25f4bac0ea4dbb719cdf6bc7) Co-authored-by: Steve Dower <steve.dower@python.org>
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r--Modules/posixmodule.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 531f26b..77df9e7 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -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