@@ -408,6 +408,18 @@ extern char *ctermid_r(char *);
408408#  define  STRUCT_STAT  struct stat
409409#endif 
410410
411+ #if  defined(__linux__ ) &&  defined(STATX_BASIC_STATS )
412+ #  pragma  weak statx
413+ #  define  HAVE_LINUX_STATX  1
414+ #  define  HAVE_LINUX_STATX_RUNTIME  (statx != NULL)
415+ /* provide definitions introduced later than statx itself */ 
416+ #  define  _Py_STATX_MNT_ID  0x00001000U
417+ #  define  _Py_STATX_SUBVOL  0x00008000U
418+ #  define  _Py_STATX_MASK  (STATX_BASIC_STATS | STATX_BTIME | _Py_STATX_MNT_ID | _Py_STATX_SUBVOL)
419+ #  define  _Py_STATX_MNT_ID_OFFSET  144
420+ #  define  _Py_STATX_SUBVOL_OFFSET  160
421+ #endif 
422+ 
411423
412424#if  !defined(EX_OK ) &&  defined(EXIT_SUCCESS )
413425#  define  EX_OK  EXIT_SUCCESS
@@ -2353,10 +2365,10 @@ static PyStructSequence_Field stat_result_fields[] = {
23532365#ifdef  HAVE_STRUCT_STAT_ST_GEN 
23542366    {"st_gen" ,    "generation number" },
23552367#endif 
2356- #if  defined(HAVE_STRUCT_STAT_ST_BIRTHTIME ) ||  defined (MS_WINDOWS )
2368+ #if  defined(HAVE_STRUCT_STAT_ST_BIRTHTIME ) ||  defined (HAVE_LINUX_STATX )  ||   defined ( MS_WINDOWS )
23572369    {"st_birthtime" ,   "time of creation" },
23582370#endif 
2359- #ifdef    MS_WINDOWS 
2371+ #if   defined( HAVE_LINUX_STATX )  ||   defined ( MS_WINDOWS ) 
23602372    {"st_birthtime_ns" , "time of creation in nanoseconds" },
23612373#endif 
23622374#ifdef  HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES 
@@ -2367,6 +2379,12 @@ static PyStructSequence_Field stat_result_fields[] = {
23672379#endif 
23682380#ifdef  HAVE_STRUCT_STAT_ST_REPARSE_TAG 
23692381    {"st_reparse_tag" , "Windows reparse tag" },
2382+ #endif 
2383+ #ifdef  HAVE_LINUX_STATX 
2384+     {"st_attributes" , "Linux file attribute bits" },
2385+     {"st_attributes_mask" , "Linux file attribute bits supported by this file" },
2386+     {"st_mnt_id" , "Linux mount ID for /proc/self/mountinfo" },
2387+     {"st_subvol" , "Linux subvolume identifier" },
23702388#endif 
23712389    {0 }
23722390};
@@ -2401,13 +2419,13 @@ static PyStructSequence_Field stat_result_fields[] = {
24012419#define  ST_GEN_IDX  ST_FLAGS_IDX
24022420#endif 
24032421
2404- #if  defined(HAVE_STRUCT_STAT_ST_BIRTHTIME ) ||  defined(MS_WINDOWS )
2422+ #if  defined(HAVE_STRUCT_STAT_ST_BIRTHTIME ) ||  defined(HAVE_LINUX_STATX )  ||  defined( MS_WINDOWS )
24052423#define  ST_BIRTHTIME_IDX  (ST_GEN_IDX+1)
24062424#else 
24072425#define  ST_BIRTHTIME_IDX  ST_GEN_IDX
24082426#endif 
24092427
2410- #ifdef    MS_WINDOWS 
2428+ #if   defined( HAVE_LINUX_STATX )  ||  defined( MS_WINDOWS ) 
24112429#define  ST_BIRTHTIME_NS_IDX  (ST_BIRTHTIME_IDX+1)
24122430#else 
24132431#define  ST_BIRTHTIME_NS_IDX  ST_BIRTHTIME_IDX
@@ -2431,6 +2449,13 @@ static PyStructSequence_Field stat_result_fields[] = {
24312449#define  ST_REPARSE_TAG_IDX  ST_FSTYPE_IDX
24322450#endif 
24332451
2452+ #ifdef  HAVE_LINUX_STATX 
2453+ #define  ST_ATTRIBUTES_IDX  (ST_REPARSE_TAG_IDX+1)
2454+ #define  ST_ATTRIBUTES_MASK_IDX  (ST_ATTRIBUTES_IDX+1)
2455+ #define  ST_MNT_ID_IDX  (ST_ATTRIBUTES_MASK_IDX+1)
2456+ #define  ST_SUBVOL_IDX  (ST_MNT_ID_IDX+1)
2457+ #endif 
2458+ 
24342459static  PyStructSequence_Desc  stat_result_desc  =  {
24352460    "stat_result" , /* name */ 
24362461    stat_result__doc__ , /* doc */ 
@@ -2790,6 +2815,99 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
27902815#undef  SET_ITEM
27912816}
27922817
2818+ #ifdef  HAVE_LINUX_STATX 
2819+ static  PyObject * 
2820+ _pystat_fromstructstatx (PyObject  * module , struct  statx  * st )
2821+ {
2822+     assert (!PyErr_Occurred ());
2823+ 
2824+     PyObject  * StatResultType  =  get_posix_state (module )-> StatResultType ;
2825+     PyObject  * v  =  PyStructSequence_New ((PyTypeObject  * )StatResultType );
2826+     if  (v  ==  NULL ) {
2827+         return  NULL ;
2828+     }
2829+ 
2830+ #define  SET_ITEM (pos , expr ) \
2831+     do { \
2832+         PyObject *obj = (expr); \
2833+         if (obj == NULL) { \
2834+             goto error; \
2835+         } \
2836+         PyStructSequence_SET_ITEM(v, (pos), obj); \
2837+     } while (0)
2838+ 
2839+     SET_ITEM (0 , PyLong_FromLong ((long )st -> stx_mode ));
2840+     static_assert (sizeof (unsigned long long ) >= sizeof (st -> stx_ino ),
2841+                   "statx.stx_ino is larger than unsigned long long" );
2842+     SET_ITEM (1 , PyLong_FromUnsignedLongLong (st -> stx_ino ));
2843+     dev_t  dev  =  makedev (st -> stx_dev_major , st -> stx_dev_minor );
2844+     SET_ITEM (2 , _PyLong_FromDev (dev ));
2845+ 
2846+     SET_ITEM (3 , PyLong_FromLong ((long )st -> stx_nlink ));
2847+     SET_ITEM (4 , _PyLong_FromUid (st -> stx_uid ));
2848+     SET_ITEM (5 , _PyLong_FromGid (st -> stx_gid ));
2849+     static_assert (sizeof (long long ) >= sizeof (st -> stx_size ),
2850+                   "statx.stx_size is larger than long long" );
2851+     SET_ITEM (6 , PyLong_FromLongLong (st -> stx_size ));
2852+ 
2853+     if  (fill_time (module , v , 7 , 10 , 13 , st -> stx_atime .tv_sec ,
2854+                   st -> stx_atime .tv_nsec ) <  0 ) {
2855+         goto error ;
2856+     }
2857+     if  (fill_time (module , v , 8 , 11 , 14 , st -> stx_mtime .tv_sec ,
2858+                   st -> stx_mtime .tv_nsec ) <  0 ) {
2859+         goto error ;
2860+     }
2861+     if  (fill_time (module , v , 9 , 12 , 15 , st -> stx_ctime .tv_sec ,
2862+                   st -> stx_ctime .tv_nsec ) <  0 ) {
2863+         goto error ;
2864+     }
2865+     if  (st -> stx_mask  &  STATX_BTIME ) {
2866+         if  (fill_time (module , v , -1 , ST_BIRTHTIME_IDX , ST_BIRTHTIME_NS_IDX ,
2867+                       st -> stx_btime .tv_sec , st -> stx_btime .tv_nsec ) <  0 ) {
2868+             goto error ;
2869+         }
2870+     }
2871+     else  {
2872+         SET_ITEM (ST_BIRTHTIME_IDX , PyFloat_FromDouble (0.0 ));
2873+         SET_ITEM (ST_BIRTHTIME_NS_IDX , _PyLong_GetZero ());
2874+     }
2875+ 
2876+     SET_ITEM (ST_BLKSIZE_IDX , PyLong_FromLong ((long )st -> stx_blksize ));
2877+     SET_ITEM (ST_BLOCKS_IDX , PyLong_FromLong ((long )st -> stx_blocks ));
2878+     dev_t  rdev  =  makedev (st -> stx_rdev_major , st -> stx_rdev_minor );
2879+     SET_ITEM (ST_RDEV_IDX , _PyLong_FromDev (rdev ));
2880+ 
2881+     SET_ITEM (ST_ATTRIBUTES_IDX , PyLong_FromUnsignedLong (st -> stx_attributes ));
2882+     SET_ITEM (ST_ATTRIBUTES_MASK_IDX , PyLong_FromLong (st -> stx_attributes_mask ));
2883+ 
2884+     if  (st -> stx_mask  &  _Py_STATX_MNT_ID ) {
2885+         void *  stx_mnt_id  =  ((unsigned char  * )st ) +  _Py_STATX_MNT_ID_OFFSET ;
2886+         SET_ITEM (ST_MNT_ID_IDX , PyLong_FromUnsignedNativeBytes (stx_mnt_id , 8 , -1 ));
2887+     }
2888+     else  {
2889+         SET_ITEM (ST_MNT_ID_IDX , Py_None );
2890+     }
2891+ 
2892+     if  (st -> stx_mask  &  _Py_STATX_SUBVOL ) {
2893+         void *  stx_subvol  =  ((unsigned char  * )st ) +  _Py_STATX_SUBVOL_OFFSET ;
2894+         SET_ITEM (ST_SUBVOL_IDX , PyLong_FromUnsignedNativeBytes (stx_subvol , 8 , -1 ));
2895+     }
2896+     else  {
2897+         SET_ITEM (ST_SUBVOL_IDX , Py_None );
2898+     }
2899+ 
2900+     assert (!PyErr_Occurred ());
2901+     return  v ;
2902+ 
2903+ error :
2904+     Py_DECREF (v );
2905+     return  NULL ;
2906+ 
2907+ #undef  SET_ITEM
2908+ }
2909+ #endif  /* HAVE_LINUX_STATX */ 
2910+ 
27932911/* POSIX methods */ 
27942912
27952913
@@ -2814,6 +2932,36 @@ posix_do_stat(PyObject *module, const char *function_name, path_t *path,
28142932        fd_and_follow_symlinks_invalid ("stat" , path -> fd , follow_symlinks ))
28152933        return  NULL ;
28162934
2935+ #ifdef  HAVE_LINUX_STATX 
2936+     struct  statx  stx  =  {};
2937+     static  int  statx_works  =  -1 ;
2938+     if  (HAVE_LINUX_STATX_RUNTIME  &&  statx_works  !=  0 ) {
2939+         int  flags  =  AT_NO_AUTOMOUNT ;
2940+         flags  |= follow_symlinks  ? 0  : AT_SYMLINK_NOFOLLOW ;
2941+         Py_BEGIN_ALLOW_THREADS 
2942+         if  (path -> fd  !=  -1 ) {
2943+             flags  |= AT_EMPTY_PATH ;
2944+             result  =  statx (path -> fd , "" , flags , _Py_STATX_MASK , & stx );
2945+         }
2946+         else  {
2947+             result  =  statx (dir_fd , path -> narrow , flags , _Py_STATX_MASK , & stx );
2948+         }
2949+         Py_END_ALLOW_THREADS 
2950+ 
2951+         if  (result  ==  -1 ) {
2952+             if  (statx_works  ==  -1 ) {
2953+                 statx_works  =  (errno  !=  ENOSYS );
2954+             }
2955+             if  (statx_works ) {
2956+                 return  path_error (path );
2957+             }
2958+         }
2959+         else  {
2960+             return  _pystat_fromstructstatx (module , & stx );
2961+         }
2962+     }
2963+ #endif  /* HAVE_LINUX_STATX */ 
2964+ 
28172965    Py_BEGIN_ALLOW_THREADS 
28182966    if  (path -> fd  !=  -1 )
28192967        result  =  FSTAT (path -> fd , & st );
0 commit comments