Tim Golden added the comment:
issue9035.3.patch has switched to the new memory management API and has
tweaked the tests slightly for robustness.
This approach does introduce a behavioural change: the root of a SUBSTed
drive (essentially a symlink into the Dos namespace) will raise an
OSError because GetVolumePathName returns error 87: invalid parameter.
So os.path.ismount("F:\\") will fail where F: is the result of running,
eg, "SUBST F: C:\temp".
I think the simplest thing is to special-case drive roots (which are
always mount points) and then to apply the new GetVolumePathName logic.
----------
Added file: http://bugs.python.org/file31092/issue9035.3.patch
_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue9035>
_______________________________________
diff --git a/Lib/ntpath.py b/Lib/ntpath.py
--- a/Lib/ntpath.py
+++ b/Lib/ntpath.py
@@ -336,15 +336,26 @@
return True
# Is a path a mount point? Either a root (with or without drive letter)
-# or an UNC path with at most a / or \ after the mount point.
+# or an UNC path with at most a / or \ after the mount point or a mounted
+# drive. The canonical approach which detects the IO_REPARSE_TAG_MOUNT_POINT
+# fails for drive roots.
-def ismount(path):
- """Test whether a path is a mount point (defined as root of drive)"""
- seps = _get_bothseps(path)
- root, rest = splitdrive(path)
- if root and root[0] in seps:
- return (not rest) or (rest in seps)
- return rest in seps
+try:
+ from nt import _getvolumepathname
+ def ismount(path):
+ #
+ # GetVolumePathName will return the directory itself
+ # if it is a mount point (including a drive root).
+ #
+ return abspath(path).rstrip(sep) ==
abspath(_getvolumepathname(path)).rstrip(sep)
+except ImportError:
+ def ismount(path):
+ """Test whether a path is a mount point (defined as root of drive)"""
+ seps = _get_bothseps(path)
+ root, rest = splitdrive(path)
+ if root and root[0] in seps:
+ return (not rest) or (rest in seps)
+ return rest in seps
# Expand paths beginning with '~' or '~user'.
diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
--- a/Lib/test/test_ntpath.py
+++ b/Lib/test/test_ntpath.py
@@ -256,6 +256,29 @@
# dialogs (#4804)
ntpath.sameopenfile(-1, -1)
+ def test_ismount(self):
+ self.assertTrue(ntpath.ismount("c:\\"))
+ self.assertTrue(ntpath.ismount("C:\\"))
+ self.assertTrue(ntpath.ismount("c:/"))
+ self.assertTrue(ntpath.ismount("C:/"))
+ self.assertTrue(ntpath.ismount("\\\\.\\c:\\"))
+ self.assertTrue(ntpath.ismount("\\\\.\\C:\\"))
+
+ with support.temp_dir() as d:
+ self.assertFalse(ntpath.ismount(d))
+
+ #
+ # Make sure the current folder isn't the root folder
+ # (or any other volume root). The drive-relative
+ # locations below cannot then refer to mount points
+ #
+ drive, path = ntpath.splitdrive(sys.executable)
+ with support.change_cwd(os.path.dirname(sys.executable)):
+ self.assertFalse(ntpath.ismount(drive.lower()))
+ self.assertFalse(ntpath.ismount(drive.upper()))
+
+ self.assertTrue(ntpath.ismount("\\\\localhost\\c$"))
+ self.assertTrue(ntpath.ismount("\\\\localhost\\c$\\"))
class NtCommonTest(test_genericpath.CommonTest, unittest.TestCase):
pathmodule = ntpath
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -3711,6 +3711,47 @@
else
Py_RETURN_FALSE;
}
+
+PyDoc_STRVAR(posix__getvolumepathname__doc__,
+"Return volume mount point of the specified path.");
+
+/* A helper function for ismount on windows */
+static PyObject *
+posix__getvolumepathname(PyObject *self, PyObject *args)
+{
+ PyObject *po, *result;
+ wchar_t *path, *mountpath=NULL;
+ size_t bufsize;
+ BOOL ret;
+
+ if (!PyArg_ParseTuple(args, "U|:_getvolumepathname", &po))
+ return NULL;
+ path = PyUnicode_AsUnicode(po);
+ if (path == NULL)
+ return NULL;
+
+ /* Volume path should be shorter than entire path */
+ bufsize = max(MAX_PATH, wcslen(path) * 2 * sizeof(wchar_t)+1);
+ mountpath = (wchar_t *)PyMem_Malloc(bufsize);
+ if (mountpath == NULL)
+ return PyErr_NoMemory();
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = GetVolumePathNameW(path, mountpath, bufsize);
+ Py_END_ALLOW_THREADS
+
+ if (!ret) {
+ result = win32_error_object("_getvolumepathname", po);
+ goto exit;
+ }
+ result = PyUnicode_FromWideChar(mountpath, wcslen(mountpath));
+
+exit:
+ PyMem_Free(mountpath);
+ return result;
+}
+/* end of posix__getvolumepathname */
+
#endif /* MS_WINDOWS */
PyDoc_STRVAR(posix_mkdir__doc__,
@@ -10884,6 +10925,7 @@
{"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL},
{"_isdir", posix__isdir, METH_VARARGS,
posix__isdir__doc__},
{"_getdiskusage", win32__getdiskusage, METH_VARARGS,
win32__getdiskusage__doc__},
+ {"_getvolumepathname", posix__getvolumepathname, METH_VARARGS,
posix__getvolumepathname__doc__},
#endif
#ifdef HAVE_GETLOADAVG
{"getloadavg", posix_getloadavg, METH_NOARGS,
posix_getloadavg__doc__},
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com