aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorRonald Oussoren <ronaldoussoren@mac.com>2024-01-15 12:22:43 +0100
committerGitHub <noreply@github.com>2024-01-15 12:22:43 +0100
commit2010d45327128594aed332befa687c8aead010bc (patch)
tree4545de42e4d6d99ea2bc8123aa987fac4bb4a7d4
parent892155d7365c9c4a6c2dd6850b4527222ba5c217 (diff)
downloadcpython-2010d45327128594aed332befa687c8aead010bc.tar.gz
cpython-2010d45327128594aed332befa687c8aead010bc.zip
gh-113666: Adding missing UF_ and SF_ flags to module 'stat' (#113667)
Add some constants to module 'stat' that are used on macOS. Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
-rw-r--r--Doc/library/stat.rst58
-rw-r--r--Lib/stat.py13
-rw-r--r--Lib/test/test_stat.py78
-rw-r--r--Misc/NEWS.d/next/macOS/2024-01-02-22-25-21.gh-issue-113666.xKZoBm.rst5
-rw-r--r--Modules/_stat.c71
5 files changed, 217 insertions, 8 deletions
diff --git a/Doc/library/stat.rst b/Doc/library/stat.rst
index 77538514598..c941d5557e3 100644
--- a/Doc/library/stat.rst
+++ b/Doc/library/stat.rst
@@ -350,6 +350,12 @@ The following flags can also be used in the *mode* argument of :func:`os.chmod`:
The following flags can be used in the *flags* argument of :func:`os.chflags`:
+.. data:: UF_SETTABLE
+
+ All user settable flags.
+
+ .. versionadded: 3.13
+
.. data:: UF_NODUMP
Do not dump the file.
@@ -374,10 +380,44 @@ The following flags can be used in the *flags* argument of :func:`os.chflags`:
The file is stored compressed (macOS 10.6+).
+.. data:: UF_TRACKED
+
+ Used for handling document IDs (macOS)
+
+ .. versionadded: 3.13
+
+.. data:: UF_DATAVAULT
+
+ The file needs an entitlement for reading or writing (macOS 10.13+)
+
+ .. versionadded: 3.13
+
.. data:: UF_HIDDEN
The file should not be displayed in a GUI (macOS 10.5+).
+.. data:: SF_SETTABLE
+
+ All super-user changeable flags
+
+ .. versionadded: 3.13
+
+.. data:: SF_SUPPORTED
+
+ All super-user supported flags
+
+ .. availability:: macOS
+
+ .. versionadded: 3.13
+
+.. data:: SF_SYNTHETIC
+
+ All super-user read-only synthetic flags
+
+ .. availability:: macOS
+
+ .. versionadded: 3.13
+
.. data:: SF_ARCHIVED
The file may be archived.
@@ -390,6 +430,12 @@ The following flags can be used in the *flags* argument of :func:`os.chflags`:
The file may only be appended to.
+.. data:: SF_RESTRICTED
+
+ The file needs an entitlement to write to (macOS 10.13+)
+
+ .. versionadded: 3.13
+
.. data:: SF_NOUNLINK
The file may not be renamed or deleted.
@@ -398,6 +444,18 @@ The following flags can be used in the *flags* argument of :func:`os.chflags`:
The file is a snapshot file.
+.. data:: SF_FIRMLINK
+
+ The file is a firmlink (macOS 10.15+)
+
+ .. versionadded: 3.13
+
+.. data:: SF_DATALESS
+
+ The file is a dataless object (macOS 10.15+)
+
+ .. versionadded: 3.13
+
See the \*BSD or macOS systems man page :manpage:`chflags(2)` for more information.
On Windows, the following file attribute constants are available for use when
diff --git a/Lib/stat.py b/Lib/stat.py
index 52cadbf04f6..9167ab18594 100644
--- a/Lib/stat.py
+++ b/Lib/stat.py
@@ -2,6 +2,7 @@
Suggested usage: from stat import *
"""
+import sys
# Indices for stat struct members in the tuple returned by os.stat()
@@ -110,19 +111,25 @@ S_IWOTH = 0o0002 # write by others
S_IXOTH = 0o0001 # execute by others
# Names for file flags
-
+UF_SETTABLE = 0x0000ffff # owner settable flags
UF_NODUMP = 0x00000001 # do not dump file
UF_IMMUTABLE = 0x00000002 # file may not be changed
UF_APPEND = 0x00000004 # file may only be appended to
UF_OPAQUE = 0x00000008 # directory is opaque when viewed through a union stack
UF_NOUNLINK = 0x00000010 # file may not be renamed or deleted
-UF_COMPRESSED = 0x00000020 # OS X: file is hfs-compressed
-UF_HIDDEN = 0x00008000 # OS X: file should not be displayed
+UF_COMPRESSED = 0x00000020 # macOS: file is compressed
+UF_TRACKED = 0x00000040 # macOS: used for handling document IDs
+UF_DATAVAULT = 0x00000080 # macOS: entitlement needed for I/O
+UF_HIDDEN = 0x00008000 # macOS: file should not be displayed
+SF_SETTABLE = 0xffff0000 # superuser settable flags
SF_ARCHIVED = 0x00010000 # file may be archived
SF_IMMUTABLE = 0x00020000 # file may not be changed
SF_APPEND = 0x00040000 # file may only be appended to
+SF_RESTRICTED = 0x00080000 # macOS: entitlement needed for writing
SF_NOUNLINK = 0x00100000 # file may not be renamed or deleted
SF_SNAPSHOT = 0x00200000 # file is a snapshot file
+SF_FIRMLINK = 0x00800000 # macOS: file is a firmlink
+SF_DATALESS = 0x40000000 # macOS: file is a dataless object
_filemode_table = (
diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py
index a0d0f61e5a1..d6b6dd6e741 100644
--- a/Lib/test/test_stat.py
+++ b/Lib/test/test_stat.py
@@ -15,8 +15,10 @@ class TestFilemode:
statmod = None
file_flags = {'SF_APPEND', 'SF_ARCHIVED', 'SF_IMMUTABLE', 'SF_NOUNLINK',
- 'SF_SNAPSHOT', 'UF_APPEND', 'UF_COMPRESSED', 'UF_HIDDEN',
- 'UF_IMMUTABLE', 'UF_NODUMP', 'UF_NOUNLINK', 'UF_OPAQUE'}
+ 'SF_SNAPSHOT', 'SF_SETTABLE', 'SF_RESTRICTED', 'SF_FIRMLINK',
+ 'SF_DATALESS', 'UF_APPEND', 'UF_COMPRESSED', 'UF_HIDDEN',
+ 'UF_IMMUTABLE', 'UF_NODUMP', 'UF_NOUNLINK', 'UF_OPAQUE',
+ 'UF_SETTABLE', 'UF_TRACKED', 'UF_DATAVAULT'}
formats = {'S_IFBLK', 'S_IFCHR', 'S_IFDIR', 'S_IFIFO', 'S_IFLNK',
'S_IFREG', 'S_IFSOCK', 'S_IFDOOR', 'S_IFPORT', 'S_IFWHT'}
@@ -239,6 +241,18 @@ class TestFilemode:
self.assertTrue(callable(func))
self.assertEqual(func(0), 0)
+ def test_flags_consistent(self):
+ self.assertFalse(self.statmod.UF_SETTABLE & self.statmod.SF_SETTABLE)
+
+ for flag in self.file_flags:
+ if flag.startswith("UF"):
+ self.assertTrue(getattr(self.statmod, flag) & self.statmod.UF_SETTABLE, f"{flag} not in UF_SETTABLE")
+ elif sys.platform == 'darwin' and self.statmod is c_stat and flag == 'SF_DATALESS':
+ self.assertTrue(self.statmod.SF_DATALESS & self.statmod.SF_SYNTHETIC, "SF_DATALESS not in SF_SYNTHETIC")
+ self.assertFalse(self.statmod.SF_DATALESS & self.statmod.SF_SETTABLE, "SF_DATALESS in SF_SETTABLE")
+ else:
+ self.assertTrue(getattr(self.statmod, flag) & self.statmod.SF_SETTABLE, f"{flag} notin SF_SETTABLE")
+
@unittest.skipUnless(sys.platform == "win32",
"FILE_ATTRIBUTE_* constants are Win32 specific")
def test_file_attribute_constants(self):
@@ -247,6 +261,66 @@ class TestFilemode:
modvalue = getattr(self.statmod, key)
self.assertEqual(value, modvalue, key)
+ @unittest.skipUnless(sys.platform == "darwin", "macOS system check")
+ def test_macosx_attribute_values(self):
+ self.assertEqual(self.statmod.UF_SETTABLE, 0x0000ffff)
+ self.assertEqual(self.statmod.UF_NODUMP, 0x00000001)
+ self.assertEqual(self.statmod.UF_IMMUTABLE, 0x00000002)
+ self.assertEqual(self.statmod.UF_APPEND, 0x00000004)
+ self.assertEqual(self.statmod.UF_OPAQUE, 0x00000008)
+ self.assertEqual(self.statmod.UF_COMPRESSED, 0x00000020)
+ self.assertEqual(self.statmod.UF_TRACKED, 0x00000040)
+ self.assertEqual(self.statmod.UF_DATAVAULT, 0x00000080)
+ self.assertEqual(self.statmod.UF_HIDDEN, 0x00008000)
+
+ if self.statmod is c_stat:
+ self.assertEqual(self.statmod.SF_SUPPORTED, 0x009f0000)
+ self.assertEqual(self.statmod.SF_SETTABLE, 0x3fff0000)
+ self.assertEqual(self.statmod.SF_SYNTHETIC, 0xc0000000)
+ else:
+ self.assertEqual(self.statmod.SF_SETTABLE, 0xffff0000)
+ self.assertEqual(self.statmod.SF_ARCHIVED, 0x00010000)
+ self.assertEqual(self.statmod.SF_IMMUTABLE, 0x00020000)
+ self.assertEqual(self.statmod.SF_APPEND, 0x00040000)
+ self.assertEqual(self.statmod.SF_RESTRICTED, 0x00080000)
+ self.assertEqual(self.statmod.SF_NOUNLINK, 0x00100000)
+ self.assertEqual(self.statmod.SF_FIRMLINK, 0x00800000)
+ self.assertEqual(self.statmod.SF_DATALESS, 0x40000000)
+
+ self.assertFalse(isinstance(self.statmod.S_IFMT, int))
+ self.assertEqual(self.statmod.S_IFIFO, 0o010000)
+ self.assertEqual(self.statmod.S_IFCHR, 0o020000)
+ self.assertEqual(self.statmod.S_IFDIR, 0o040000)
+ self.assertEqual(self.statmod.S_IFBLK, 0o060000)
+ self.assertEqual(self.statmod.S_IFREG, 0o100000)
+ self.assertEqual(self.statmod.S_IFLNK, 0o120000)
+ self.assertEqual(self.statmod.S_IFSOCK, 0o140000)
+
+ if self.statmod is c_stat:
+ self.assertEqual(self.statmod.S_IFWHT, 0o160000)
+
+ self.assertEqual(self.statmod.S_IRWXU, 0o000700)
+ self.assertEqual(self.statmod.S_IRUSR, 0o000400)
+ self.assertEqual(self.statmod.S_IWUSR, 0o000200)
+ self.assertEqual(self.statmod.S_IXUSR, 0o000100)
+ self.assertEqual(self.statmod.S_IRWXG, 0o000070)
+ self.assertEqual(self.statmod.S_IRGRP, 0o000040)
+ self.assertEqual(self.statmod.S_IWGRP, 0o000020)
+ self.assertEqual(self.statmod.S_IXGRP, 0o000010)
+ self.assertEqual(self.statmod.S_IRWXO, 0o000007)
+ self.assertEqual(self.statmod.S_IROTH, 0o000004)
+ self.assertEqual(self.statmod.S_IWOTH, 0o000002)
+ self.assertEqual(self.statmod.S_IXOTH, 0o000001)
+ self.assertEqual(self.statmod.S_ISUID, 0o004000)
+ self.assertEqual(self.statmod.S_ISGID, 0o002000)
+ self.assertEqual(self.statmod.S_ISVTX, 0o001000)
+
+ self.assertFalse(hasattr(self.statmod, "S_ISTXT"))
+ self.assertEqual(self.statmod.S_IREAD, self.statmod.S_IRUSR)
+ self.assertEqual(self.statmod.S_IWRITE, self.statmod.S_IWUSR)
+ self.assertEqual(self.statmod.S_IEXEC, self.statmod.S_IXUSR)
+
+
@unittest.skipIf(c_stat is None, 'need _stat extension')
class TestFilemodeCStat(TestFilemode, unittest.TestCase):
diff --git a/Misc/NEWS.d/next/macOS/2024-01-02-22-25-21.gh-issue-113666.xKZoBm.rst b/Misc/NEWS.d/next/macOS/2024-01-02-22-25-21.gh-issue-113666.xKZoBm.rst
new file mode 100644
index 00000000000..4be0021eed3
--- /dev/null
+++ b/Misc/NEWS.d/next/macOS/2024-01-02-22-25-21.gh-issue-113666.xKZoBm.rst
@@ -0,0 +1,5 @@
+Add the following constants to module :mod:`stat`: ``UF_SETTABLE``,
+``UF_TRACKED``, ``UF_DATAVAULT``, ``SF_SUPPORTED``, ``SF_SETTABLE``,
+``SF_SYNTHETIC``, ``SF_RESTRICTED``, ``SF_FIRMLINK`` and ``SF_DATALESS``.
+The values ``UF_SETTABLE``, ``SF_SUPPORTED``, ``SF_SETTABLE`` and
+``SF_SYNTHETIC`` are only available on macOS.
diff --git a/Modules/_stat.c b/Modules/_stat.c
index 80f8a926689..b43e79453f5 100644
--- a/Modules/_stat.c
+++ b/Modules/_stat.c
@@ -202,6 +202,10 @@ typedef unsigned short mode_t;
/* Names for file flags */
+#ifndef UF_SETTABLE
+# define UF_SETTABLE 0x0000ffff
+#endif
+
#ifndef UF_NODUMP
# define UF_NODUMP 0x00000001
#endif
@@ -226,10 +230,22 @@ typedef unsigned short mode_t;
# define UF_COMPRESSED 0x00000020
#endif
+#ifndef UF_TRACKED
+# define UF_TRACKED 0x00000040
+#endif
+
+#ifndef UF_DATAVAULT
+# define UF_DATAVAULT 0x00000080
+#endif
+
#ifndef UF_HIDDEN
# define UF_HIDDEN 0x00008000
#endif
+#ifndef SF_SETTABLE
+# define SF_SETTABLE 0xffff0000
+#endif
+
#ifndef SF_ARCHIVED
# define SF_ARCHIVED 0x00010000
#endif
@@ -250,6 +266,30 @@ typedef unsigned short mode_t;
# define SF_SNAPSHOT 0x00200000
#endif
+#ifndef SF_FIRMLINK
+# define SF_FIRMLINK 0x00800000
+#endif
+
+#ifndef SF_DATALESS
+# define SF_DATALESS 0x40000000
+#endif
+
+#if defined(__APPLE__) && !defined(SF_SUPPORTED)
+ /* On older macOS versions the definition of SF_SUPPORTED is different
+ * from that on newer versions.
+ *
+ * Provide a consistent experience by redefining.
+ *
+ * None of bit bits set in the actual SF_SUPPORTED but not in this
+ * definition are defined on these versions of macOS.
+ */
+# undef SF_SETTABLE
+# define SF_SUPPORTED 0x009f0000
+# define SF_SETTABLE 0x3fff0000
+# define SF_SYNTHETIC 0xc0000000
+#endif
+
+
static mode_t
_PyLong_AsMode_t(PyObject *op)
{
@@ -467,18 +507,29 @@ S_IWOTH: write by others\n\
S_IXOTH: execute by others\n\
\n"
-"UF_NODUMP: do not dump file\n\
+"UF_SETTABLE: mask of owner changable flags\n\
+UF_NODUMP: do not dump file\n\
UF_IMMUTABLE: file may not be changed\n\
UF_APPEND: file may only be appended to\n\
UF_OPAQUE: directory is opaque when viewed through a union stack\n\
UF_NOUNLINK: file may not be renamed or deleted\n\
-UF_COMPRESSED: OS X: file is hfs-compressed\n\
-UF_HIDDEN: OS X: file should not be displayed\n\
+UF_COMPRESSED: macOS: file is hfs-compressed\n\
+UF_TRACKED: used for dealing with document IDs\n\
+UF_DATAVAULT: entitlement required for reading and writing\n\
+UF_HIDDEN: macOS: file should not be displayed\n\
+SF_SETTABLE: mask of super user changeable flags\n\
SF_ARCHIVED: file may be archived\n\
SF_IMMUTABLE: file may not be changed\n\
SF_APPEND: file may only be appended to\n\
+SF_RESTRICTED: entitlement required for writing\n\
SF_NOUNLINK: file may not be renamed or deleted\n\
SF_SNAPSHOT: file is a snapshot file\n\
+SF_FIRMLINK: file is a firmlink\n\
+SF_DATALESS: file is a dataless object\n\
+\n\
+On macOS:\n\
+SF_SUPPORTED: mask of super user supported flags\n\
+SF_SYNTHETIC: mask of read-only synthetic flags\n\
\n"
"ST_MODE\n\
@@ -543,18 +594,32 @@ stat_exec(PyObject *module)
ADD_INT_MACRO(module, S_IWOTH);
ADD_INT_MACRO(module, S_IXOTH);
+ ADD_INT_MACRO(module, UF_SETTABLE);
ADD_INT_MACRO(module, UF_NODUMP);
ADD_INT_MACRO(module, UF_IMMUTABLE);
ADD_INT_MACRO(module, UF_APPEND);
ADD_INT_MACRO(module, UF_OPAQUE);
ADD_INT_MACRO(module, UF_NOUNLINK);
ADD_INT_MACRO(module, UF_COMPRESSED);
+ ADD_INT_MACRO(module, UF_TRACKED);
+ ADD_INT_MACRO(module, UF_DATAVAULT);
ADD_INT_MACRO(module, UF_HIDDEN);
+ ADD_INT_MACRO(module, SF_SETTABLE);
ADD_INT_MACRO(module, SF_ARCHIVED);
ADD_INT_MACRO(module, SF_IMMUTABLE);
ADD_INT_MACRO(module, SF_APPEND);
ADD_INT_MACRO(module, SF_NOUNLINK);
ADD_INT_MACRO(module, SF_SNAPSHOT);
+ ADD_INT_MACRO(module, SF_FIRMLINK);
+ ADD_INT_MACRO(module, SF_DATALESS);
+
+#ifdef SF_SUPPORTED
+ ADD_INT_MACRO(module, SF_SUPPORTED);
+#endif
+#ifdef SF_SYNTHETIC
+ ADD_INT_MACRO(module, SF_SYNTHETIC);
+#endif
+
const char* st_constants[] = {
"ST_MODE",