diff --git a/lib/utils/io.py b/lib/utils/io.py index cec8a7dca89f316c26032e297dd1b5138663656d..80dc1f0d392d96e34b9ac73ca967c03803b3af0b 100644 --- a/lib/utils/io.py +++ b/lib/utils/io.py @@ -38,6 +38,10 @@ from ganeti.utils import filelock #: Path generating random UUID _RANDOM_UUID_FILE = "/proc/sys/kernel/random/uuid" +#: Directory used by fsck(8) to store recovered data, usually at a file +#: system's root directory +_LOST_AND_FOUND = "lost+found" + def ReadFile(file_name, size=-1, preread=None): """Reads a file. @@ -467,7 +471,7 @@ def CreateBackup(file_name): return backup_name -def ListVisibleFiles(path): +def ListVisibleFiles(path, _is_mountpoint=os.path.ismount): """Returns a list of visible files in a directory. @type path: str @@ -480,8 +484,22 @@ def ListVisibleFiles(path): if not IsNormAbsPath(path): raise errors.ProgrammerError("Path passed to ListVisibleFiles is not" " absolute/normalized: '%s'" % path) - files = [i for i in os.listdir(path) if not i.startswith(".")] - return files + + mountpoint = _is_mountpoint(path) + + def fn(name): + """File name filter. + + Ignores files starting with a dot (".") as by Unix convention they're + considered hidden. The "lost+found" directory found at the root of some + filesystems is also hidden. + + """ + return not (name.startswith(".") or + (mountpoint and name == _LOST_AND_FOUND and + os.path.isdir(os.path.join(path, name)))) + + return filter(fn, os.listdir(path)) def EnsureDirs(dirs): diff --git a/test/ganeti.utils.io_unittest.py b/test/ganeti.utils.io_unittest.py index a383203df185590da63277297bf1878b39852866..46bb009d7e9b296c340a3a34d28a305776614f57 100755 --- a/test/ganeti.utils.io_unittest.py +++ b/test/ganeti.utils.io_unittest.py @@ -239,6 +239,27 @@ class TestListVisibleFiles(unittest.TestCase): self.failUnlessRaises(errors.ProgrammerError, utils.ListVisibleFiles, "/bin/../tmp") + def testMountpoint(self): + lvfmp_fn = compat.partial(utils.ListVisibleFiles, + _is_mountpoint=lambda _: True) + self.assertEqual(lvfmp_fn(self.path), []) + + # Create "lost+found" as a regular file + self._CreateFiles(["foo", "bar", ".baz", "lost+found"]) + self.assertEqual(set(lvfmp_fn(self.path)), + set(["foo", "bar", "lost+found"])) + + # Replace "lost+found" with a directory + laf_path = utils.PathJoin(self.path, "lost+found") + utils.RemoveFile(laf_path) + os.mkdir(laf_path) + self.assertEqual(set(lvfmp_fn(self.path)), set(["foo", "bar"])) + + def testLostAndFoundNoMountpoint(self): + files = ["foo", "bar", ".Hello World", "lost+found"] + expected = ["foo", "bar", "lost+found"] + self._test(files, expected) + class TestWriteFile(unittest.TestCase): def setUp(self):