From e5b310baf709f676c86c853b30c4856df4be7d4f Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Tue, 2 Jan 2024 22:25:34 +0100 Subject: [PATCH 01/13] gh-113666: Adding missing UF_ and SF_ flags to module 'stat' Add some constants to module 'stat' that are used on macOS. --- Doc/library/stat.rst | 62 +++++++++++++++++++ Lib/stat.py | 18 +++++- ...-01-02-22-25-21.gh-issue-113666.xKZoBm.rst | 5 ++ 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2024-01-02-22-25-21.gh-issue-113666.xKZoBm.rst diff --git a/Doc/library/stat.rst b/Doc/library/stat.rst index 77538514598a50..129553a8f09257 100644 --- a/Doc/library/stat.rst +++ b/Doc/library/stat.rst @@ -350,6 +350,14 @@ 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. + + .. availability:: macOS + + .. versionadded: 3.13 + .. data:: UF_NODUMP Do not dump the file. @@ -374,10 +382,46 @@ 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:: UF_SUPPORTED + + All super-user supported flags + + .. availability:: macOS + + .. versionadded: 3.13 + +.. data:: UF_SETTABLE + + All super-user changeable 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 +434,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 +448,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 52cadbf04f6c88..2a98155eeb6a15 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() @@ -111,18 +112,31 @@ def S_ISWHT(mode): # Names for file flags +if sys.platform == "darwin": + # Group of bits in st_flags, specific to Apple platforms. + + UF_SETTABLE = 0xffff # owner settable flags + SF_SUPPORTED = 0x9f0000 # superuser supported flags + SF_SETTABLE = 0x3ffff000 # superuser settable flags + SF_SYNTHETIC = 0xc0000000 # system read-only synthetic 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 = 0x00008000 # macOS: entitlement needed for I/O +UF_HIDDEN = 0x00008000 # macOS: file should not be displayed 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/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 00000000000000..4be0021eed3cc4 --- /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. From a577ec88ac7ae81fa9054a04034a1652939618f0 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 4 Jan 2024 13:51:50 +0100 Subject: [PATCH 02/13] Update Lib/stat.py Co-authored-by: Serhiy Storchaka --- Lib/stat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/stat.py b/Lib/stat.py index 2a98155eeb6a15..946ed7a9a6d4a3 100644 --- a/Lib/stat.py +++ b/Lib/stat.py @@ -115,8 +115,8 @@ def S_ISWHT(mode): if sys.platform == "darwin": # Group of bits in st_flags, specific to Apple platforms. - UF_SETTABLE = 0xffff # owner settable flags - SF_SUPPORTED = 0x9f0000 # superuser supported flags + UF_SETTABLE = 0x0000ffff # owner settable flags + SF_SUPPORTED = 0x009f0000 # superuser supported flags SF_SETTABLE = 0x3ffff000 # superuser settable flags SF_SYNTHETIC = 0xc0000000 # system read-only synthetic flags From 8d1f532fd76f283b40f3a99fe1587ccd85be0ed3 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 4 Jan 2024 17:38:46 +0100 Subject: [PATCH 03/13] Add test that tests values of constants on macOS --- Lib/test/test_stat.py | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index a0d0f61e5a192c..8c17ae80d6f499 100644 --- a/Lib/test/test_stat.py +++ b/Lib/test/test_stat.py @@ -247,6 +247,63 @@ def test_file_attribute_constants(self): 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) + + self.assertEqual(self.statmod.SF_SUPPORTED, 0x009f0000) + self.assertEqual(self.statmod.SF_SETTABLE, 0x3fff0000) + self.assertEqual(self.statmod.SF_SYNTHETIC, 0xc0000000) + 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): From 36af895059e21863cca1e6f101a55d3e23427df7 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 4 Jan 2024 17:39:11 +0100 Subject: [PATCH 04/13] Fix definitions --- Lib/stat.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/stat.py b/Lib/stat.py index 2a98155eeb6a15..c2dabcdbf92ccd 100644 --- a/Lib/stat.py +++ b/Lib/stat.py @@ -115,9 +115,9 @@ def S_ISWHT(mode): if sys.platform == "darwin": # Group of bits in st_flags, specific to Apple platforms. - UF_SETTABLE = 0xffff # owner settable flags - SF_SUPPORTED = 0x9f0000 # superuser supported flags - SF_SETTABLE = 0x3ffff000 # superuser settable flags + UF_SETTABLE = 0x0000ffff # owner settable flags + SF_SUPPORTED = 0x009f0000 # superuser supported flags + SF_SETTABLE = 0x3fff0000 # superuser settable flags SF_SYNTHETIC = 0xc0000000 # system read-only synthetic flags UF_NODUMP = 0x00000001 # do not dump file @@ -127,7 +127,7 @@ def S_ISWHT(mode): UF_NOUNLINK = 0x00000010 # file may not be renamed or deleted UF_COMPRESSED = 0x00000020 # macOS: file is compressed UF_TRACKED = 0x00000040 # macOS: used for handling document IDs -UF_DATAVAULT = 0x00008000 # macOS: entitlement needed for I/O +UF_DATAVAULT = 0x00000080 # macOS: entitlement needed for I/O UF_HIDDEN = 0x00008000 # macOS: file should not be displayed SF_ARCHIVED = 0x00010000 # file may be archived SF_IMMUTABLE = 0x00020000 # file may not be changed From d00e54f05aac9bb87d544adccbb1495e7e03c4b1 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 4 Jan 2024 17:39:19 +0100 Subject: [PATCH 05/13] Add new definitions to _stat.c as well --- Modules/_stat.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/Modules/_stat.c b/Modules/_stat.c index 80f8a92668976b..7df305c8931772 100644 --- a/Modules/_stat.c +++ b/Modules/_stat.c @@ -226,6 +226,14 @@ 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 @@ -250,6 +258,14 @@ 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 + static mode_t _PyLong_AsMode_t(PyObject *op) { @@ -472,13 +488,24 @@ 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_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\ +UF_SETTABLE: mask of owner changable flags\n\ +SF_SETTABLE: mask of super user changeable flags\n\ +SF_SUPPORTED: mask of super user supported flags\n\ +SF_SYNTHETIC: mask of read-only synthetic flags\n\ \n" "ST_MODE\n\ @@ -549,12 +576,24 @@ stat_exec(PyObject *module) 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_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 UF_SETTABLE + ADD_INT_MACRO(module, UF_SETTABLE); + ADD_INT_MACRO(module, SF_SUPPORTED); + ADD_INT_MACRO(module, SF_SETTABLE); + ADD_INT_MACRO(module, SF_SYNTHETIC); +#endif + const char* st_constants[] = { "ST_MODE", From b68cf311e0f96097c049f957d1ba080ea4ea026b Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 4 Jan 2024 17:41:51 +0100 Subject: [PATCH 06/13] Fix typo --- Lib/stat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/stat.py b/Lib/stat.py index 220e504b2904e1..b2b07461dbcdd2 100644 --- a/Lib/stat.py +++ b/Lib/stat.py @@ -117,7 +117,7 @@ def S_ISWHT(mode): UF_SETTABLE = 0x0000ffff # owner settable flags SF_SUPPORTED = 0x009f0000 # superuser supported flags - SF_SETTABLE = 0x3ffff000 # superuser settable flags + SF_SETTABLE = 0x3fff0000 # superuser settable flags SF_SYNTHETIC = 0xc0000000 # system read-only synthetic flags UF_NODUMP = 0x00000001 # do not dump file From ab7017b86dfdfe37dec5a4a48c31993a9a028c53 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 4 Jan 2024 19:10:08 +0100 Subject: [PATCH 07/13] Add new flags to the generic tests as well. --- Lib/test/test_stat.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index 8c17ae80d6f499..2bad19842f3037 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_RESTRICTED', 'SF_FIRMLINK', 'SF_DATALESS', + 'UF_APPEND', 'UF_COMPRESSED', 'UF_HIDDEN', 'UF_IMMUTABLE', + 'UF_NODUMP', 'UF_NOUNLINK', 'UF_OPAQUE', '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'} From b63cd7e762749a91c04502e54e61223ea0165bab Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 4 Jan 2024 19:10:39 +0100 Subject: [PATCH 08/13] Fix whitespace at end of line --- Lib/test/test_stat.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index 2bad19842f3037..dfa48245035564 100644 --- a/Lib/test/test_stat.py +++ b/Lib/test/test_stat.py @@ -16,9 +16,9 @@ class TestFilemode: file_flags = {'SF_APPEND', 'SF_ARCHIVED', 'SF_IMMUTABLE', 'SF_NOUNLINK', 'SF_SNAPSHOT', 'SF_RESTRICTED', 'SF_FIRMLINK', 'SF_DATALESS', - 'UF_APPEND', 'UF_COMPRESSED', 'UF_HIDDEN', 'UF_IMMUTABLE', - 'UF_NODUMP', 'UF_NOUNLINK', 'UF_OPAQUE', 'UF_TRACKED', - 'UF_DATAVAULT'} + 'UF_APPEND', 'UF_COMPRESSED', 'UF_HIDDEN', 'UF_IMMUTABLE', + 'UF_NODUMP', 'UF_NOUNLINK', 'UF_OPAQUE', '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'} From 4ed402ec6ce298301003b22f1b4dbf6937eb25bb Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 7 Jan 2024 10:55:04 +0100 Subject: [PATCH 09/13] BSD and older macOS 1. SF_SETTABLE and UF_SETTABLE are available on BSD as well Add generic definitions to stat.py and fallback defines to _stat.c (the latter matching how we handle other generic flags) 2. Older versions of macOS do not have SF_SUPPORTED and SF_SYNTHETIC _stat.c defines those for all macOS platforms, and redefines SF_SETTABLE to match recent macOS versions. I did this primarily to end up with an explainable situation: our installers are build on recent versions of macOS and can be used on older versions. The implementation in this changeset ensures we end up with the same definitions regardless of how the binary was build (old SDK or new SDK and old deployment target) --- Doc/library/stat.rst | 8 ++------ Lib/stat.py | 11 ++--------- Lib/test/test_stat.py | 29 ++++++++++++++++++++++------- Modules/_stat.c | 38 ++++++++++++++++++++++++++++++++------ 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/Doc/library/stat.rst b/Doc/library/stat.rst index 129553a8f09257..a9db782d039a09 100644 --- a/Doc/library/stat.rst +++ b/Doc/library/stat.rst @@ -354,8 +354,6 @@ The following flags can be used in the *flags* argument of :func:`os.chflags`: All user settable flags. - .. availability:: macOS - .. versionadded: 3.13 .. data:: UF_NODUMP @@ -398,15 +396,13 @@ The following flags can be used in the *flags* argument of :func:`os.chflags`: The file should not be displayed in a GUI (macOS 10.5+). -.. data:: UF_SUPPORTED +.. data:: SF_SUPPORTED All super-user supported flags - .. availability:: macOS - .. versionadded: 3.13 -.. data:: UF_SETTABLE +.. data:: SF_SETTABLE All super-user changeable flags diff --git a/Lib/stat.py b/Lib/stat.py index b2b07461dbcdd2..9167ab185944fb 100644 --- a/Lib/stat.py +++ b/Lib/stat.py @@ -111,15 +111,7 @@ def S_ISWHT(mode): S_IXOTH = 0o0001 # execute by others # Names for file flags - -if sys.platform == "darwin": - # Group of bits in st_flags, specific to Apple platforms. - - UF_SETTABLE = 0x0000ffff # owner settable flags - SF_SUPPORTED = 0x009f0000 # superuser supported flags - SF_SETTABLE = 0x3fff0000 # superuser settable flags - SF_SYNTHETIC = 0xc0000000 # system read-only synthetic 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 @@ -129,6 +121,7 @@ def S_ISWHT(mode): 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 diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index dfa48245035564..995386d673b24f 100644 --- a/Lib/test/test_stat.py +++ b/Lib/test/test_stat.py @@ -15,10 +15,10 @@ class TestFilemode: statmod = None file_flags = {'SF_APPEND', 'SF_ARCHIVED', 'SF_IMMUTABLE', 'SF_NOUNLINK', - 'SF_SNAPSHOT', 'SF_RESTRICTED', 'SF_FIRMLINK', 'SF_DATALESS', - 'UF_APPEND', 'UF_COMPRESSED', 'UF_HIDDEN', 'UF_IMMUTABLE', - 'UF_NODUMP', 'UF_NOUNLINK', 'UF_OPAQUE', 'UF_TRACKED', - 'UF_DATAVAULT'} + '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'} @@ -241,6 +241,18 @@ def test_module_attributes(self): 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} notin 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): @@ -261,9 +273,12 @@ def test_macosx_attribute_values(self): self.assertEqual(self.statmod.UF_DATAVAULT, 0x00000080) self.assertEqual(self.statmod.UF_HIDDEN, 0x00008000) - self.assertEqual(self.statmod.SF_SUPPORTED, 0x009f0000) - self.assertEqual(self.statmod.SF_SETTABLE, 0x3fff0000) - self.assertEqual(self.statmod.SF_SYNTHETIC, 0xc0000000) + 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) diff --git a/Modules/_stat.c b/Modules/_stat.c index 7df305c8931772..b0ac28526869a7 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_ARCHIVED 0x0000ffff +#endif + #ifndef UF_NODUMP # define UF_NODUMP 0x00000001 #endif @@ -238,6 +242,10 @@ typedef unsigned short mode_t; # define UF_HIDDEN 0x00008000 #endif +#ifndef SF_SETTABLE +# define SF_ARCHIVED 0xffff0000 +#endif + #ifndef SF_ARCHIVED # define SF_ARCHIVED 0x00010000 #endif @@ -266,6 +274,22 @@ typedef unsigned short mode_t; # 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) { @@ -483,7 +507,8 @@ 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\ @@ -492,6 +517,7 @@ 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\ @@ -502,8 +528,6 @@ SF_FIRMLINK: file is a firmlink\n\ SF_DATALESS: file is a dataless object\n\ \n\ On macOS:\n\ -UF_SETTABLE: mask of owner changable flags\n\ -SF_SETTABLE: mask of super user changeable flags\n\ SF_SUPPORTED: mask of super user supported flags\n\ SF_SYNTHETIC: mask of read-only synthetic flags\n\ \n" @@ -570,6 +594,7 @@ 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); @@ -579,6 +604,7 @@ stat_exec(PyObject *module) 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); @@ -587,10 +613,10 @@ stat_exec(PyObject *module) ADD_INT_MACRO(module, SF_FIRMLINK); ADD_INT_MACRO(module, SF_DATALESS); -#ifdef UF_SETTABLE - ADD_INT_MACRO(module, UF_SETTABLE); +#ifdef SF_SUPPORTED ADD_INT_MACRO(module, SF_SUPPORTED); - ADD_INT_MACRO(module, SF_SETTABLE); +#endif +#ifdef SF_SYNTHETIC ADD_INT_MACRO(module, SF_SYNTHETIC); #endif From 97ff320458b5428aa10c37e28e5da64dfaff2ecf Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 7 Jan 2024 11:19:37 +0100 Subject: [PATCH 10/13] Fix typo --- Modules/_stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_stat.c b/Modules/_stat.c index b0ac28526869a7..68535048b0766f 100644 --- a/Modules/_stat.c +++ b/Modules/_stat.c @@ -203,7 +203,7 @@ typedef unsigned short mode_t; /* Names for file flags */ #ifndef UF_SETTABLE -# define UF_ARCHIVED 0x0000ffff +# define UF_SETTABLE 0x0000ffff #endif #ifndef UF_NODUMP From 97af986c9c5aca17ade558a7043d18be413f18e2 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 7 Jan 2024 11:20:01 +0100 Subject: [PATCH 11/13] Update Lib/test/test_stat.py Co-authored-by: Serhiy Storchaka --- Lib/test/test_stat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index 995386d673b24f..d6b6dd6e741700 100644 --- a/Lib/test/test_stat.py +++ b/Lib/test/test_stat.py @@ -246,7 +246,7 @@ def test_flags_consistent(self): for flag in self.file_flags: if flag.startswith("UF"): - self.assertTrue(getattr(self.statmod, flag) & self.statmod.UF_SETTABLE, f"{flag} notin UF_SETTABLE") + 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") From bae3f7ea7a43e8792ef1088d8e3fd4b99e57847f Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 7 Jan 2024 20:09:54 +0100 Subject: [PATCH 12/13] fix ci errors --- Modules/_stat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_stat.c b/Modules/_stat.c index 68535048b0766f..b43e79453f5b2f 100644 --- a/Modules/_stat.c +++ b/Modules/_stat.c @@ -243,7 +243,7 @@ typedef unsigned short mode_t; #endif #ifndef SF_SETTABLE -# define SF_ARCHIVED 0xffff0000 +# define SF_SETTABLE 0xffff0000 #endif #ifndef SF_ARCHIVED @@ -275,12 +275,12 @@ typedef unsigned short mode_t; #endif #if defined(__APPLE__) && !defined(SF_SUPPORTED) - /* On older macOS versions the definition of SF_SUPPORTED is different + /* 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 + * 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 From 4b576d2f2ecc0839ebaa0589b709b1930784106f Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 14 Jan 2024 16:31:28 +0100 Subject: [PATCH 13/13] Correct documentatation --- Doc/library/stat.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/stat.rst b/Doc/library/stat.rst index a9db782d039a09..c941d5557e31b5 100644 --- a/Doc/library/stat.rst +++ b/Doc/library/stat.rst @@ -396,15 +396,15 @@ The following flags can be used in the *flags* argument of :func:`os.chflags`: The file should not be displayed in a GUI (macOS 10.5+). -.. data:: SF_SUPPORTED +.. data:: SF_SETTABLE - All super-user supported flags + All super-user changeable flags .. versionadded: 3.13 -.. data:: SF_SETTABLE +.. data:: SF_SUPPORTED - All super-user changeable flags + All super-user supported flags .. availability:: macOS