Issue #9035: os.path.ismount now recognises volumes mounted below
a drive root on Windows. Original patch by Atsuo Ishimoto.
This commit is contained in:
parent
536ffe161c
commit
6b528067c5
|
@ -335,16 +335,35 @@ def lexists(path):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Is a path a mount point? Either a root (with or without drive letter)
|
# Is a path a mount point?
|
||||||
# or an UNC path with at most a / or \ after the mount point.
|
# Any drive letter root (eg c:\)
|
||||||
|
# Any share UNC (eg \\server\share)
|
||||||
|
# Any volume mounted on a filesystem folder
|
||||||
|
#
|
||||||
|
# No one method detects all three situations. Historically we've lexically
|
||||||
|
# detected drive letter roots and share UNCs. The canonical approach to
|
||||||
|
# detecting mounted volumes (querying the reparse tag) fails for the most
|
||||||
|
# common case: drive letter roots. The alternative which uses GetVolumePathName
|
||||||
|
# fails if the drive letter is the result of a SUBST.
|
||||||
|
try:
|
||||||
|
from nt import _getvolumepathname
|
||||||
|
except ImportError:
|
||||||
|
_getvolumepathname = None
|
||||||
def ismount(path):
|
def ismount(path):
|
||||||
"""Test whether a path is a mount point (defined as root of drive)"""
|
"""Test whether a path is a mount point (a drive root, the root of a
|
||||||
|
share, or a mounted volume)"""
|
||||||
seps = _get_bothseps(path)
|
seps = _get_bothseps(path)
|
||||||
|
path = abspath(path)
|
||||||
root, rest = splitdrive(path)
|
root, rest = splitdrive(path)
|
||||||
if root and root[0] in seps:
|
if root and root[0] in seps:
|
||||||
return (not rest) or (rest in seps)
|
return (not rest) or (rest in seps)
|
||||||
return rest in seps
|
if rest in seps:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if _getvolumepathname:
|
||||||
|
return path.rstrip(seps) == _getvolumepathname(path).rstrip(seps)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
# Expand paths beginning with '~' or '~user'.
|
# Expand paths beginning with '~' or '~user'.
|
||||||
|
|
|
@ -256,6 +256,40 @@ class TestNtpath(unittest.TestCase):
|
||||||
# dialogs (#4804)
|
# dialogs (#4804)
|
||||||
ntpath.sameopenfile(-1, -1)
|
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:\\"))
|
||||||
|
|
||||||
|
self.assertTrue(ntpath.ismount(b"c:\\"))
|
||||||
|
self.assertTrue(ntpath.ismount(b"C:\\"))
|
||||||
|
self.assertTrue(ntpath.ismount(b"c:/"))
|
||||||
|
self.assertTrue(ntpath.ismount(b"C:/"))
|
||||||
|
self.assertTrue(ntpath.ismount(b"\\\\.\\c:\\"))
|
||||||
|
self.assertTrue(ntpath.ismount(b"\\\\.\\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$\\"))
|
||||||
|
|
||||||
|
self.assertTrue(ntpath.ismount(b"\\\\localhost\\c$"))
|
||||||
|
self.assertTrue(ntpath.ismount(b"\\\\localhost\\c$\\"))
|
||||||
|
|
||||||
|
|
||||||
class NtCommonTest(test_genericpath.CommonTest, unittest.TestCase):
|
class NtCommonTest(test_genericpath.CommonTest, unittest.TestCase):
|
||||||
pathmodule = ntpath
|
pathmodule = ntpath
|
||||||
|
|
|
@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #9035: ismount now recognises volumes mounted below a drive root
|
||||||
|
on Windows. Original patch by Atsuo Ishimoto.
|
||||||
|
|
||||||
- Issue #18214: Improve finalization of Python modules to avoid setting
|
- Issue #18214: Improve finalization of Python modules to avoid setting
|
||||||
their globals to None, in most cases.
|
their globals to None, in most cases.
|
||||||
|
|
||||||
|
|
|
@ -3711,6 +3711,47 @@ check:
|
||||||
else
|
else
|
||||||
Py_RETURN_FALSE;
|
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 */
|
#endif /* MS_WINDOWS */
|
||||||
|
|
||||||
PyDoc_STRVAR(posix_mkdir__doc__,
|
PyDoc_STRVAR(posix_mkdir__doc__,
|
||||||
|
@ -10885,6 +10926,7 @@ static PyMethodDef posix_methods[] = {
|
||||||
{"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL},
|
{"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL},
|
||||||
{"_isdir", posix__isdir, METH_VARARGS, posix__isdir__doc__},
|
{"_isdir", posix__isdir, METH_VARARGS, posix__isdir__doc__},
|
||||||
{"_getdiskusage", win32__getdiskusage, METH_VARARGS, win32__getdiskusage__doc__},
|
{"_getdiskusage", win32__getdiskusage, METH_VARARGS, win32__getdiskusage__doc__},
|
||||||
|
{"_getvolumepathname", posix__getvolumepathname, METH_VARARGS, posix__getvolumepathname__doc__},
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_GETLOADAVG
|
#ifdef HAVE_GETLOADAVG
|
||||||
{"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__},
|
{"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__},
|
||||||
|
|
Loading…
Reference in New Issue