8000 gh-113666: Adding missing UF_ and SF_ flags to module 'stat' by ronaldoussoren · Pull Request #113667 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-113666: Adding missing UF_ and SF_ flags to module 'stat' #113667

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions Doc/library/stat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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
Expand Down
13 changes: 10 additions & 3 deletions Lib/stat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

Suggested usage: from stat import *
"""
import sys

# Indices for stat struct members in the tuple returned by os.stat()

Expand Down Expand Up @@ -110,19 +111,25 @@ def S_ISWHT(mode):
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 = (
Expand Down
78 changes: 76 additions & 2 deletions Lib/test/test_stat.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'}
Expand Down Expand Up @@ -239,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} 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):
Expand All @@ -247,6 +261,66 @@ 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)

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):
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
71 changes: 68 additions & 3 deletions Modules/_stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
{
Expand Down Expand Up @@ -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\
Expand Down Expand Up @@ -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",
Expand Down
0