From b62a76043e543fbb15cab7e9e8874a798bc600d2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 29 Aug 2023 17:46:46 +0200 Subject: [PATCH] gh-108638: Fix stat.filemode() when _stat is missing (#108639) Change the pure Python implementation of stat.filemode() for unknown file type: use "?", as done by the _stat.filemode(). test_stat skips TestFilemodeCStat if the _stat extension is missing. --- Lib/stat.py | 10 ++++++++-- Lib/test/test_stat.py | 6 +++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Lib/stat.py b/Lib/stat.py index fc024db3f4f..52cadbf04f6 100644 --- a/Lib/stat.py +++ b/Lib/stat.py @@ -126,6 +126,8 @@ SF_SNAPSHOT = 0x00200000 # file is a snapshot file _filemode_table = ( + # File type chars according to: + # http://en.wikibooks.org/wiki/C_Programming/POSIX_Reference/sys/stat.h ((S_IFLNK, "l"), (S_IFSOCK, "s"), # Must appear before IFREG and IFDIR as IFSOCK == IFREG | IFDIR (S_IFREG, "-"), @@ -156,13 +158,17 @@ _filemode_table = ( def filemode(mode): """Convert a file's mode to a string of the form '-rwxrwxrwx'.""" perm = [] - for table in _filemode_table: + for index, table in enumerate(_filemode_table): for bit, char in table: if mode & bit == bit: perm.append(char) break else: - perm.append("-") + if index == 0: + # Unknown filetype + perm.append("?") + else: + perm.append("-") return "".join(perm) diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index 4ba37aed2dc..0eced2fcf98 100644 --- a/Lib/test/test_stat.py +++ b/Lib/test/test_stat.py @@ -122,8 +122,11 @@ class TestFilemode: st_mode, modestr = self.get_mode() self.assertEqual(modestr, '-rwx------') self.assertS_IS("REG", st_mode) - self.assertEqual(self.statmod.S_IMODE(st_mode), + imode = self.statmod.S_IMODE(st_mode) + self.assertEqual(imode, self.statmod.S_IRWXU) + self.assertEqual(self.statmod.filemode(imode), + '?rwx------') os.chmod(TESTFN, 0o070) st_mode, modestr = self.get_mode() @@ -238,6 +241,7 @@ class TestFilemode: self.assertEqual(value, modvalue, key) +@unittest.skipIf(c_stat is None, 'need _stat extension') class TestFilemodeCStat(TestFilemode, unittest.TestCase): statmod = c_stat