# 2466: ismount now recognizes mount points user can't access.
Patch by Robin Roth, backport by Xiang Zhang.
diff --git a/Lib/posixpath.py b/Lib/posixpath.py
index 8f92822..f5c2260 100644
--- a/Lib/posixpath.py
+++ b/Lib/posixpath.py
@@ -186,7 +186,7 @@
return False
try:
s1 = os.lstat(path)
- s2 = os.lstat(join(path, '..'))
+ s2 = os.lstat(realpath(join(path, '..')))
except os.error:
return False # It doesn't exist -- so not a mount point :-)
dev1 = s1.st_dev
diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py
index fbb18fd..98bf0e0 100644
--- a/Lib/test/test_posixpath.py
+++ b/Lib/test/test_posixpath.py
@@ -1,4 +1,5 @@
import unittest
+from test import symlink_support
from test import test_support, test_genericpath
from test import test_support as support
@@ -7,6 +8,11 @@
import sys
from posixpath import realpath, abspath, dirname, basename
+try:
+ import posix
+except ImportError:
+ posix = None
+
# An absolute path to a temporary filename for testing. We can't rely on TESTFN
# being an absolute path, so we need this.
@@ -100,7 +106,7 @@
f.write("foo")
f.close()
self.assertIs(posixpath.islink(test_support.TESTFN + "1"), False)
- if hasattr(os, "symlink"):
+ if symlink_support.can_symlink():
os.symlink(test_support.TESTFN + "1", test_support.TESTFN + "2")
self.assertIs(posixpath.islink(test_support.TESTFN + "2"), True)
os.remove(test_support.TESTFN + "1")
@@ -196,6 +202,64 @@
def test_ismount(self):
self.assertIs(posixpath.ismount("/"), True)
+ def test_ismount_non_existent(self):
+ # Non-existent mountpoint.
+ self.assertIs(posixpath.ismount(ABSTFN), False)
+ try:
+ os.mkdir(ABSTFN)
+ self.assertIs(posixpath.ismount(ABSTFN), False)
+ finally:
+ safe_rmdir(ABSTFN)
+
+ @symlink_support.skip_unless_symlink
+ def test_ismount_symlinks(self):
+ # Symlinks are never mountpoints.
+ try:
+ os.symlink("/", ABSTFN)
+ self.assertIs(posixpath.ismount(ABSTFN), False)
+ finally:
+ os.unlink(ABSTFN)
+
+ @unittest.skipIf(posix is None, "Test requires posix module")
+ def test_ismount_different_device(self):
+ # Simulate the path being on a different device from its parent by
+ # mocking out st_dev.
+ save_lstat = os.lstat
+ def fake_lstat(path):
+ st_ino = 0
+ st_dev = 0
+ if path == ABSTFN:
+ st_dev = 1
+ st_ino = 1
+ return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0))
+ try:
+ os.lstat = fake_lstat
+ self.assertIs(posixpath.ismount(ABSTFN), True)
+ finally:
+ os.lstat = save_lstat
+
+ @unittest.skipIf(posix is None, "Test requires posix module")
+ def test_ismount_directory_not_readable(self):
+ # issue #2466: Simulate ismount run on a directory that is not
+ # readable, which used to return False.
+ save_lstat = os.lstat
+ def fake_lstat(path):
+ st_ino = 0
+ st_dev = 0
+ if path.startswith(ABSTFN) and path != ABSTFN:
+ # ismount tries to read something inside the ABSTFN directory;
+ # simulate this being forbidden (no read permission).
+ raise OSError("Fake [Errno 13] Permission denied")
+ if path == ABSTFN:
+ st_dev = 1
+ st_ino = 1
+ return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0))
+ try:
+ os.lstat = fake_lstat
+ self.assertIs(posixpath.ismount(ABSTFN), True)
+ finally:
+ os.lstat = save_lstat
+
def test_expanduser(self):
self.assertEqual(posixpath.expanduser("foo"), "foo")
with test_support.EnvironmentVarGuard() as env: