From ffa1d0b8d53f426f1f9a0d47f25440b8994c4fb0 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola' Date: Tue, 15 May 2012 15:30:25 +0200 Subject: [PATCH] #14807: move undocumented tarfile.filemode() to stat.filemode(). Add tarfile.filemode alias with deprecation warning. --- Doc/library/stat.rst | 11 ++++++++- Doc/whatsnew/3.3.rst | 8 +++++++ Lib/stat.py | 40 +++++++++++++++++++++++++++++++ Lib/tarfile.py | 48 ++++++------------------------------- Lib/test/test_stat.py | 55 +++++++++++++++++++++++++++++++++++++++++++ Misc/NEWS | 5 +++- 6 files changed, 124 insertions(+), 43 deletions(-) create mode 100644 Lib/test/test_stat.py diff --git a/Doc/library/stat.rst b/Doc/library/stat.rst index 7de98b6581e..f47f4640451 100644 --- a/Doc/library/stat.rst +++ b/Doc/library/stat.rst @@ -104,6 +104,16 @@ Example:: if __name__ == '__main__': walktree(sys.argv[1], visitfile) +An additional utility function is provided to covert a file's mode in a human +readable string: + +.. function:: filemode(mode) + + Convert a file's mode to a string of the form '-rwxrwxrwx'. + + .. versionadded:: 3.3 + + All the variables below are simply symbolic indexes into the 10-tuple returned by :func:`os.stat`, :func:`os.fstat` or :func:`os.lstat`. @@ -344,4 +354,3 @@ The following flags can be used in the *flags* argument of :func:`os.chflags`: The file is a snapshot file. See the \*BSD or Mac OS systems man page :manpage:`chflags(2)` for more information. - diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 148324e6aac..ac012367523 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1177,6 +1177,14 @@ ssl (Contributed by Colin Marc in :issue:`14204`) +stat +---- + +- The undocumented tarfile.filemode function has been moved to + :func:`stat.filemode`. It can be used to convert a file's mode to a string of + the form '-rwxrwxrwx'. + + (Contributed by Giampaolo RodolĂ  in :issue:`14807`) sys --- diff --git a/Lib/stat.py b/Lib/stat.py index 0f29498b48d..704adfe2e13 100644 --- a/Lib/stat.py +++ b/Lib/stat.py @@ -107,3 +107,43 @@ SF_IMMUTABLE = 0x00020000 # file may not be changed SF_APPEND = 0x00040000 # file may only be appended to SF_NOUNLINK = 0x00100000 # file may not be renamed or deleted SF_SNAPSHOT = 0x00200000 # file is a snapshot file + + +_filemode_table = ( + ((S_IFLNK, "l"), + (S_IFREG, "-"), + (S_IFBLK, "b"), + (S_IFDIR, "d"), + (S_IFCHR, "c"), + (S_IFIFO, "p")), + + ((S_IRUSR, "r"),), + ((S_IWUSR, "w"),), + ((S_IXUSR|S_ISUID, "s"), + (S_ISUID, "S"), + (S_IXUSR, "x")), + + ((S_IRGRP, "r"),), + ((S_IWGRP, "w"),), + ((S_IXGRP|S_ISGID, "s"), + (S_ISGID, "S"), + (S_IXGRP, "x")), + + ((S_IROTH, "r"),), + ((S_IWOTH, "w"),), + ((S_IXOTH|S_ISVTX, "t"), + (S_ISVTX, "T"), + (S_IXOTH, "x")) +) + +def filemode(mode): + """Convert a file's mode to a string of the form '-rwxrwxrwx'.""" + perm = [] + for table in _filemode_table: + for bit, char in table: + if mode & bit == bit: + perm.append(char) + break + else: + perm.append("-") + return "".join(perm) diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 8dd4c0f82db..9d38421ef6e 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -274,47 +274,13 @@ def copyfileobj(src, dst, length=None): dst.write(buf) return -filemode_table = ( - ((S_IFLNK, "l"), - (S_IFREG, "-"), - (S_IFBLK, "b"), - (S_IFDIR, "d"), - (S_IFCHR, "c"), - (S_IFIFO, "p")), - - ((TUREAD, "r"),), - ((TUWRITE, "w"),), - ((TUEXEC|TSUID, "s"), - (TSUID, "S"), - (TUEXEC, "x")), - - ((TGREAD, "r"),), - ((TGWRITE, "w"),), - ((TGEXEC|TSGID, "s"), - (TSGID, "S"), - (TGEXEC, "x")), - - ((TOREAD, "r"),), - ((TOWRITE, "w"),), - ((TOEXEC|TSVTX, "t"), - (TSVTX, "T"), - (TOEXEC, "x")) -) - def filemode(mode): - """Convert a file's mode to a string of the form - -rwxrwxrwx. - Used by TarFile.list() - """ - perm = [] - for table in filemode_table: - for bit, char in table: - if mode & bit == bit: - perm.append(char) - break - else: - perm.append("-") - return "".join(perm) + """Deprecated in this location; use stat.filemode.""" + import warnings + warnings.warn("deprecated in favor of stat.filemode", + DeprecationWarning, 2) + return stat.filemode(mode) + class TarError(Exception): """Base exception.""" @@ -1891,7 +1857,7 @@ class TarFile(object): for tarinfo in self: if verbose: - print(filemode(tarinfo.mode), end=' ') + print(stat.filemode(tarinfo.mode), end=' ') print("%s/%s" % (tarinfo.uname or tarinfo.uid, tarinfo.gname or tarinfo.gid), end=' ') if tarinfo.ischr() or tarinfo.isblk(): diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py new file mode 100644 index 00000000000..f22d8655063 --- /dev/null +++ b/Lib/test/test_stat.py @@ -0,0 +1,55 @@ +import unittest +import os +import stat +from test.support import TESTFN, run_unittest + + +def get_mode(fname=TESTFN): + return stat.filemode(os.lstat(fname).st_mode) + + +class TestFilemode(unittest.TestCase): + + def setUp(self): + try: + os.remove(TESTFN) + except OSError: + try: + os.rmdir(TESTFN) + except OSError: + pass + tearDown = setUp + + def test_mode(self): + with open(TESTFN, 'w'): + pass + os.chmod(TESTFN, 0o700) + self.assertEqual(get_mode(), '-rwx------') + os.chmod(TESTFN, 0o070) + self.assertEqual(get_mode(), '----rwx---') + os.chmod(TESTFN, 0o007) + self.assertEqual(get_mode(), '-------rwx') + os.chmod(TESTFN, 0o444) + self.assertEqual(get_mode(), '-r--r--r--') + + def test_directory(self): + os.mkdir(TESTFN) + os.chmod(TESTFN, 0o700) + self.assertEqual(get_mode(), 'drwx------') + + @unittest.skipUnless(hasattr(os, 'symlink'), 'os.symlink not available') + def test_link(self): + os.symlink(os.getcwd(), TESTFN) + self.assertEqual(get_mode(), 'lrwxrwxrwx') + + @unittest.skipUnless(hasattr(os, 'mkfifo'), 'os.mkfifo not available') + def test_fifo(self): + os.mkfifo(TESTFN, 0o700) + self.assertEqual(get_mode(), 'prwx------') + + +def test_main(): + run_unittest(TestFilemode) + +if __name__ == '__main__': + test_main() diff --git a/Misc/NEWS b/Misc/NEWS index f8ef70a7c69..95a2c4f2f1e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,10 +31,13 @@ Core and Builtins Library ------- +- Issue 14807: move undocumented tarfile.filemode() to stat.filemode() and add + doc entry. Add tarfile.filemode alias with deprecation warning. + - Issue #13815: TarFile.extractfile() now returns io.BufferedReader objects. - Issue #14532: Add a secure_compare() helper to the hmac module, to mitigate - timing attacks. Patch by Jon Oberheide. + timing attacks. Patch by Jon Oberheide. - Add importlib.util.resolve_name().