Skip to content

Commit 667ece4

Browse files
committed
Add support for STATX_ATTR_{VERITY,DAX} and the new stx_mnt_id field
1 parent b231028 commit 667ece4

File tree

5 files changed

+54
-3
lines changed

5 files changed

+54
-3
lines changed

Doc/library/os.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2897,6 +2897,12 @@ features:
28972897
Type of device (combined major and minor number) if the queried file
28982898
was an inode device.
28992899

2900+
.. attribute:: st_mnt_id
2901+
2902+
Mount ID of the mountpoint the queried file resides on. Information on
2903+
the associated filesystem may be found by analysing
2904+
*/proc/self/mountinfo*.
2905+
29002906
On other Unix systems (such as FreeBSD), the following attributes may be
29012907
available (but may be only filled out if root tries to use them):
29022908

Doc/library/stat.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,5 +447,7 @@ meaning of these constants.
447447
STATX_ATTR_APPEND
448448
STATX_ATTR_NODUMP
449449
STATX_ATTR_ENCRYPTED
450+
STATX_ATTR_VERITY
451+
STATX_ATTR_DAX
450452

451453
.. versionadded:: 3.12

Lib/stat.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ def filemode(mode):
206206
STATX_ATTR_APPEND = 0x0020
207207
STATX_ATTR_NODUMP = 0x0040
208208
STATX_ATTR_ENCRYPTED = 0x0800
209+
STATX_ATTR_VERITY = 0x100000
210+
STATX_ATTR_DAX = 0x200000
209211

210212

211213
# If available, use C implementation

Modules/_stat.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,8 @@ stat_exec(PyObject *module)
664664
ADD_INT_MACRO(module, STATX_ATTR_APPEND);
665665
ADD_INT_MACRO(module, STATX_ATTR_NODUMP);
666666
ADD_INT_MACRO(module, STATX_ATTR_ENCRYPTED);
667+
ADD_INT_MACRO(module, STATX_ATTR_VERITY);
668+
ADD_INT_MACRO(module, STATX_ATTR_DAX);
667669
#endif /* HAVE_LINUX_STATX */
668670

669671
return 0;

Modules/posixmodule.c

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2076,8 +2076,14 @@ win32_stat(const wchar_t* path, struct _Py_stat_struct *result)
20762076

20772077
#ifdef HAVE_LINUX_STATX
20782078

2079+
#ifdef STATX_MNT_ID // Added in Linux 5.8
2080+
# define _PY_STATX_MNT_ID STATX_MNT_ID
2081+
#else
2082+
# define _PY_STATX_MNT_ID 0x00001000U
2083+
#endif
2084+
20792085
// Extend this list when adding support for new Linux statx fields
2080-
#define LINUX_STATX_MASK STATX_BASIC_STATS | STATX_BTIME
2086+
#define LINUX_STATX_MASK STATX_BASIC_STATS | STATX_BTIME | _PY_STATX_MNT_ID
20812087

20822088
static int
20832089
linux_stat(const char* path, struct statx* result)
@@ -2165,6 +2171,7 @@ static PyStructSequence_Field stat_result_fields[] = {
21652171
#ifdef HAVE_LINUX_STATX
21662172
{"st_attributes", "Linux file attribute bits"},
21672173
{"st_attributes_mask", "Linux supported file attribute bits on this filesystem"},
2174+
{"st_mnt_id", "Linux mount ID of the mount containing the file"},
21682175
#endif
21692176
{0}
21702177
};
@@ -2220,9 +2227,11 @@ static PyStructSequence_Field stat_result_fields[] = {
22202227
#ifdef HAVE_LINUX_STATX
22212228
#define ST_ATTRIBUTES_IDX (ST_REPARSE_TAG_IDX+1)
22222229
#define ST_ATTRIBUTES_MASK_IDX (ST_REPARSE_TAG_IDX+2)
2230+
#define ST_MNT_ID_IDX (ST_REPARSE_TAG_IDX+3)
22232231
#else
22242232
#define ST_ATTRIBUTES_IDX ST_REPARSE_TAG_IDX
22252233
#define ST_ATTRIBUTES_MASK_IDX ST_REPARSE_TAG_IDX
2234+
#define ST_MNT_ID_IDX ST_REPARSE_TAG_IDX
22262235
#endif
22272236

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

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

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

2519+
if(stx->stx_mask & _PY_STATX_MNT_ID) {
2520+
PyStructSequence_SET_ITEM(v, ST_MNT_ID_IDX, PyLong_FromUnsignedLongLong(
2521+
#ifdef STATX_MNT_ID
2522+
stx->stx_mnt_id
2523+
#else
2524+
// `stx_mnt_id` is the next 64-bit field following `stx_dev_minor`
2525+
//
2526+
// It is safe to assume its going to be there even if the C library
2527+
// does not support it yet, since the size of `struct statx` is
2528+
// constant and value presence is only indicated by the kernel in
2529+
// the `stx_mask` field queried above if the field is actually
2530+
// supported and was set.
2531+
*((unsigned long long *) ((&stx->stx_dev_minor) + 1))
2532+
#endif /* STATX_MNT_ID */
2533+
));
2534+
}
2535+
24972536
if (PyErr_Occurred()) {
24982537
Py_DECREF(v);
24992538
return NULL;

0 commit comments

Comments
 (0)