Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Add support for STATX_ATTR_{VERITY,DAX} and the new stx_mnt_id field
  • Loading branch information
ntninja committed Sep 15, 2022
commit 9aae324d1be35076adc39f0c7edc9cc306980343
6 changes: 6 additions & 0 deletions Doc/library/os.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2897,6 +2897,12 @@ features:
Type of device (combined major and minor number) if the queried file
was an inode device.

.. attribute:: st_mnt_id

Mount ID of the mountpoint the queried file resides on. Information on
the associated filesystem may be found by analysing
*/proc/self/mountinfo*.

On other Unix systems (such as FreeBSD), the following attributes may be
available (but may be only filled out if root tries to use them):

Expand Down
2 changes: 2 additions & 0 deletions Doc/library/stat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -447,5 +447,7 @@ meaning of these constants.
STATX_ATTR_APPEND
STATX_ATTR_NODUMP
STATX_ATTR_ENCRYPTED
STATX_ATTR_VERITY
STATX_ATTR_DAX

.. versionadded:: 3.12
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tip - update version markers in docs to "next" and it'll automagically use the right version.

2 changes: 2 additions & 0 deletions Lib/stat.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ def filemode(mode):
STATX_ATTR_APPEND = 0x0020
STATX_ATTR_NODUMP = 0x0040
STATX_ATTR_ENCRYPTED = 0x0800
STATX_ATTR_VERITY = 0x100000
STATX_ATTR_DAX = 0x200000


# If available, use C implementation
Expand Down
2 changes: 2 additions & 0 deletions Modules/_stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,8 @@ stat_exec(PyObject *module)
ADD_INT_MACRO(module, STATX_ATTR_APPEND);
ADD_INT_MACRO(module, STATX_ATTR_NODUMP);
ADD_INT_MACRO(module, STATX_ATTR_ENCRYPTED);
ADD_INT_MACRO(module, STATX_ATTR_VERITY);
ADD_INT_MACRO(module, STATX_ATTR_DAX);
#endif /* HAVE_LINUX_STATX */

return 0;
Expand Down
45 changes: 42 additions & 3 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2076,8 +2076,14 @@ win32_stat(const wchar_t* path, struct _Py_stat_struct *result)

#ifdef HAVE_LINUX_STATX

#ifdef STATX_MNT_ID // Added in Linux 5.8
# define _PY_STATX_MNT_ID STATX_MNT_ID
#else
# define _PY_STATX_MNT_ID 0x00001000U
#endif

// Extend this list when adding support for new Linux statx fields
#define LINUX_STATX_MASK STATX_BASIC_STATS | STATX_BTIME
#define LINUX_STATX_MASK STATX_BASIC_STATS | STATX_BTIME | _PY_STATX_MNT_ID

static int
linux_stat(const char* path, struct statx* result)
Expand Down Expand Up @@ -2165,6 +2171,7 @@ static PyStructSequence_Field stat_result_fields[] = {
#ifdef HAVE_LINUX_STATX
{"st_attributes", "Linux file attribute bits"},
{"st_attributes_mask", "Linux supported file attribute bits on this filesystem"},
{"st_mnt_id", "Linux mount ID of the mount containing the file"},
#endif
{0}
};
Expand Down Expand Up @@ -2220,9 +2227,11 @@ static PyStructSequence_Field stat_result_fields[] = {
#ifdef HAVE_LINUX_STATX
#define ST_ATTRIBUTES_IDX (ST_REPARSE_TAG_IDX+1)
#define ST_ATTRIBUTES_MASK_IDX (ST_REPARSE_TAG_IDX+2)
#define ST_MNT_ID_IDX (ST_REPARSE_TAG_IDX+3)
#else
#define ST_ATTRIBUTES_IDX ST_REPARSE_TAG_IDX
#define ST_ATTRIBUTES_MASK_IDX ST_REPARSE_TAG_IDX
#define ST_MNT_ID_IDX ST_REPARSE_TAG_IDX
#endif

static PyStructSequence_Desc stat_result_desc = {
Expand Down Expand Up @@ -2464,8 +2473,10 @@ _pystat_fromstructstat(PyObject *module, struct statx* stx)

// Map statx flags to BSD flags
//
// The contants used here are not defined on Linux, are available to
// Python users through the "stat" module.
// The constants used here are not defined on Linux but are available to
// Python users through the "stat" module. In general, try to follow
// FreeBSD semantics when adding a mapping here and refrain from mapping
// attributes that don't have an obvious equivalent.
flags = 0;
if(attributes & STATX_ATTR_COMPRESSED) {
flags |= 0x00000020; // UF_COMPRESSED
Expand All @@ -2482,6 +2493,17 @@ _pystat_fromstructstat(PyObject *module, struct statx* stx)
if(attributes & STATX_ATTR_ENCRYPTED) {
flags |= 0x00002000; // UF_ENCRYPTED
}
// Note: There is nothing in the FreeBSD disk flags list resembling
// `STATX_ATTR_VERITY` or `STATX_ATTR_DAX`, so leave these unmapped.
//
// In addition (as of Linux 5.19), `STATX_ATTR_DAX` does not ever appear
// to be reported when querying on-disk files that previously had the
// corresponding "x" flag set using `chattr(1)`, so even if FreeBSD adds
// a corresponding flag mapping it would likely be of little use.
//
// If these flags ever need to be mapped, remember to add a compatibility
// define for them next to the definition of `LINUX_STATX_MASK`, to ensure
// builds will continue working on older C library versions.
PyStructSequence_SET_ITEM(v, 18, PyLong_FromLong(flags));

PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX,
Expand All @@ -2494,6 +2516,23 @@ _pystat_fromstructstat(PyObject *module, struct statx* stx)
PyStructSequence_SET_ITEM(v, ST_RDEV_IDX,
_PyLong_FromDev(makedev(stx->stx_rdev_major, stx->stx_rdev_minor)));

if(stx->stx_mask & _PY_STATX_MNT_ID) {
PyStructSequence_SET_ITEM(v, ST_MNT_ID_IDX, PyLong_FromUnsignedLongLong(
#ifdef STATX_MNT_ID
stx->stx_mnt_id
#else
// `stx_mnt_id` is the next 64-bit field following `stx_dev_minor`
//
// It is safe to assume its going to be there even if the C library
// does not support it yet, since the size of `struct statx` is
// constant and value presence is only indicated by the kernel in
// the `stx_mask` field queried above if the field is actually
// supported and was set.
*((unsigned long long *) ((&stx->stx_dev_minor) + 1))
#endif /* STATX_MNT_ID */
));
}

if (PyErr_Occurred()) {
Py_DECREF(v);
return NULL;
Expand Down