From a87dc23547db9f59fc760485193808c8f9dc8f23 Mon Sep 17 00:00:00 2001 From: "Jonathan J. Helmus" Date: Thu, 8 Oct 2026 17:31:44 -0500 Subject: [PATCH 1/3] Add a syscall fallback for os.statx Expose os.statx when build with Linux headers that provide the syscall number and struct statx, even if the build-time libc lacks a statx wrapper. Call the libc wrapper when available, to keep the symbol versioing and fortification checks. Fall back to the syscall if the wrapper is absent, either at build or run time. Detect optional struct statx fields from the available libc or kernel headers. os.statx is not longer exposed when the syscall is unavailable at build time, even is libc provides a wrapper. This is a rare edge case where glibc would emulate the behavior at runtime. --- Doc/library/os.rst | 34 +++++++------- Modules/clinic/posixmodule.c.h | 6 +-- Modules/posixmodule.c | 79 ++++++++++++++++++++------------ configure | 82 +++++++++++++++++++++++++++------- configure.ac | 39 +++++++++------- pyconfig.h.in | 6 +++ 6 files changed, 169 insertions(+), 77 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 3f0b91af4d0a86f..823ca90bc55c189 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3544,10 +3544,14 @@ features: .. seealso:: The :manpage:`statx(2)` man page. - .. availability:: Linux >= 4.11 with glibc >= 2.28. + .. availability:: Linux >= 4.11. .. versionadded:: 3.15 + .. versionchanged:: 3.16 + The function is also available when Python is built against a libc + that lacks ``statx()``, such as glibc older than 2.28. + .. class:: statx_result @@ -3576,7 +3580,7 @@ features: Equal to ``None`` if :data:`STATX_WRITE_ATOMIC` is missing from :attr:`~statx_result.stx_mask`. - .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + .. availability:: Linux >= 4.11 and build-time kernel userspace API headers >= 6.11. .. attribute:: stx_atomic_write_unit_max @@ -3586,7 +3590,7 @@ features: Equal to ``None`` if :data:`STATX_WRITE_ATOMIC` is missing from :attr:`~statx_result.stx_mask`. - .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + .. availability:: Linux >= 4.11 and build-time kernel userspace API headers >= 6.11. .. attribute:: stx_atomic_write_unit_max_opt @@ -3596,7 +3600,7 @@ features: Equal to ``None`` if :data:`STATX_WRITE_ATOMIC` is missing from :attr:`~statx_result.stx_mask`. - .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + .. availability:: Linux >= 4.11 and build-time kernel userspace API headers >= 6.16. .. attribute:: stx_atomic_write_unit_min @@ -3606,7 +3610,7 @@ features: Equal to ``None`` if :data:`STATX_WRITE_ATOMIC` is missing from :attr:`~statx_result.stx_mask`. - .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + .. availability:: Linux >= 4.11 and build-time kernel userspace API headers >= 6.11. .. attribute:: stx_attributes @@ -3680,7 +3684,7 @@ features: Equal to ``None`` if :data:`STATX_DIOALIGN` is missing from :attr:`~statx_result.stx_mask`. - .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + .. availability:: Linux >= 4.11 and build-time kernel userspace API headers >= 6.1. .. attribute:: stx_dio_offset_align @@ -3690,7 +3694,7 @@ features: Equal to ``None`` if :data:`STATX_DIOALIGN` is missing from :attr:`~statx_result.stx_mask`. - .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + .. availability:: Linux >= 4.11 and build-time kernel userspace API headers >= 6.1. .. attribute:: stx_dio_read_offset_align @@ -3700,7 +3704,7 @@ features: Equal to ``None`` if :data:`STATX_DIO_READ_ALIGN` is missing from :attr:`~statx_result.stx_mask`. - .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + .. availability:: Linux >= 4.11 and build-time kernel userspace API headers >= 6.14. .. attribute:: stx_gid @@ -3729,7 +3733,7 @@ features: Equal to ``None`` if :data:`STATX_MNT_ID` is missing from :attr:`~statx_result.stx_mask`. - .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + .. availability:: Linux >= 4.11 and build-time kernel userspace API headers >= 5.8. .. attribute:: stx_mode @@ -3789,7 +3793,7 @@ features: Equal to ``None`` if :data:`STATX_SUBVOL` is missing from :attr:`~statx_result.stx_mask`. - .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + .. availability:: Linux >= 4.11 and build-time kernel userspace API headers >= 6.10. .. attribute:: stx_uid @@ -3801,7 +3805,7 @@ features: .. seealso:: The :manpage:`statx(2)` man page. - .. availability:: Linux >= 4.11 with glibc >= 2.28. + .. availability:: Linux >= 4.11. .. versionadded:: 3.15 @@ -3830,7 +3834,7 @@ features: flags may be available even when their corresponding members in :class:`statx_result` are not available. - .. availability:: Linux >= 4.11 with glibc >= 2.28. + .. availability:: Linux >= 4.11. .. versionadded:: 3.15 @@ -3840,7 +3844,7 @@ features: up-to-date information even when doing so is expensive (for example, requiring a round trip to the server for a file on a network filesystem). - .. availability:: Linux >= 4.11 with glibc >= 2.28. + .. availability:: Linux >= 4.11. .. versionadded:: 3.15 @@ -3849,7 +3853,7 @@ features: A flag for the :func:`os.statx` function. Requests that the kernel return cached information if possible. - .. availability:: Linux >= 4.11 with glibc >= 2.28. + .. availability:: Linux >= 4.11. .. versionadded:: 3.15 @@ -3861,7 +3865,7 @@ features: In the absence of the other two flags, the kernel will generally return information as fresh as :func:`os.stat` would return. - .. availability:: Linux >= 4.11 with glibc >= 2.28. + .. availability:: Linux >= 4.11. .. versionadded:: 3.15 diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 3c3e46e065f3ea7..c182374ed273578 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -188,7 +188,7 @@ os_lstat(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kw return return_value; } -#if defined(HAVE_STATX) +#if defined(_Py_HAVE_STATX) PyDoc_STRVAR(os_statx__doc__, "statx($module, /, path, mask, *, flags=0, dir_fd=None,\n" @@ -320,7 +320,7 @@ os_statx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kw return return_value; } -#endif /* defined(HAVE_STATX) */ +#endif /* defined(_Py_HAVE_STATX) */ PyDoc_STRVAR(os_access__doc__, "access($module, /, path, mode, *, dir_fd=None, effective_ids=False,\n" @@ -13763,4 +13763,4 @@ os__emscripten_log(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #ifndef OS__EMSCRIPTEN_LOG_METHODDEF #define OS__EMSCRIPTEN_LOG_METHODDEF #endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */ -/*[clinic end generated code: output=8bf88a95035a0188 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1981d42f50f6a5fa input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 301afe1fa27be68..9e8a000e7bc0482 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -90,6 +90,9 @@ #ifdef HAVE_SYS_STAT_H # include #endif +#if defined(__linux__) && !defined(HAVE_STRUCT_STATX) && defined(HAVE_LINUX_STAT_H) +# include // struct statx on older libc versions +#endif #ifdef HAVE_SYS_WAIT_H # include // WNOHANG @@ -420,9 +423,31 @@ extern char *ctermid_r(char *); # define STRUCT_STAT struct stat #endif -#ifdef HAVE_STATX +#if defined(__linux__) && defined(__NR_statx) && \ + (defined(HAVE_STRUCT_STATX) || \ + (defined(HAVE_LINUX_STAT_H) && defined(STATX_BASIC_STATS))) +# define _Py_HAVE_STATX +#endif + +#if defined(_Py_HAVE_STATX) && defined(HAVE_STATX) /* until we can assume glibc 2.28 at runtime, we must weakly link */ # pragma weak statx +#endif + +#ifdef _Py_HAVE_STATX +/* These Linux UAPI flags may be missing from older libc headers. Including + linux/fcntl.h alongside fcntl.h would redefine libc structures. */ +# ifndef AT_NO_AUTOMOUNT +# define AT_NO_AUTOMOUNT 0x800 +# endif +# ifndef AT_EMPTY_PATH +# define AT_EMPTY_PATH 0x1000 +# endif +# ifndef AT_STATX_SYNC_AS_STAT +# define AT_STATX_SYNC_AS_STAT 0x0000 +# define AT_STATX_FORCE_SYNC 0x2000 +# define AT_STATX_DONT_SYNC 0x4000 +# endif static const unsigned int _Py_STATX_KNOWN = (STATX_BASIC_STATS | STATX_BTIME #ifdef STATX_MNT_ID | STATX_MNT_ID @@ -443,7 +468,7 @@ static const unsigned int _Py_STATX_KNOWN = (STATX_BASIC_STATS | STATX_BTIME | STATX_DIO_READ_ALIGN #endif ); -#endif /* HAVE_STATX */ +#endif /* _Py_HAVE_STATX */ #if !defined(EX_OK) && defined(EXIT_SUCCESS) @@ -1235,7 +1260,7 @@ typedef struct { #endif newfunc statresult_new_orig; PyObject *StatResultType; -#ifdef HAVE_STATX +#ifdef _Py_HAVE_STATX PyObject *StatxResultType; #endif PyObject *StatVFSResultType; @@ -2620,7 +2645,7 @@ _posix_clear(PyObject *module) Py_CLEAR(state->SchedParamType); #endif Py_CLEAR(state->StatResultType); -#ifdef HAVE_STATX +#ifdef _Py_HAVE_STATX Py_CLEAR(state->StatxResultType); #endif Py_CLEAR(state->StatVFSResultType); @@ -2648,7 +2673,7 @@ _posix_traverse(PyObject *module, visitproc visit, void *arg) Py_VISIT(state->SchedParamType); #endif Py_VISIT(state->StatResultType); -#ifdef HAVE_STATX +#ifdef _Py_HAVE_STATX Py_VISIT(state->StatxResultType); #endif Py_VISIT(state->StatVFSResultType); @@ -3337,7 +3362,7 @@ os_lstat_impl(PyObject *module, path_t *path, int dir_fd) } -#ifdef HAVE_STATX +#ifdef _Py_HAVE_STATX typedef struct { PyObject_HEAD dev_t rdev, dev; @@ -3693,12 +3718,21 @@ os_statx_impl(PyObject *module, path_t *path, unsigned int mask, int flags, } int result; - Py_BEGIN_ALLOW_THREADS + int statx_dir_fd = path->is_fd ? path->fd : dir_fd; + const char *statx_path = path->is_fd ? "" : path->narrow; if (path->is_fd) { - result = statx(path->fd, "", flags | AT_EMPTY_PATH, mask, &v->stx); + flags |= AT_EMPTY_PATH; } - else { - result = statx(dir_fd, path->narrow, flags, mask, &v->stx); + Py_BEGIN_ALLOW_THREADS +#ifdef HAVE_STATX + if (statx != NULL) { + result = statx(statx_dir_fd, statx_path, flags, mask, &v->stx); + } + else +#endif + { + result = syscall(__NR_statx, statx_dir_fd, statx_path, flags, mask, + &v->stx); } Py_END_ALLOW_THREADS @@ -3713,7 +3747,7 @@ os_statx_impl(PyObject *module, path_t *path, unsigned int mask, int flags, assert(!PyErr_Occurred()); return (PyObject *)v; } -#endif /* HAVE_STATX */ +#endif /* _Py_HAVE_STATX */ /*[clinic input] @@ -18808,7 +18842,7 @@ all_ins(PyObject *m) if (PyModule_AddIntMacro(m, AT_NO_AUTOMOUNT)) return -1; #endif -#ifdef HAVE_STATX +#ifdef _Py_HAVE_STATX if (PyModule_AddIntMacro(m, STATX_TYPE)) return -1; if (PyModule_AddIntMacro(m, STATX_MODE)) return -1; if (PyModule_AddIntMacro(m, STATX_NLINK)) return -1; @@ -18845,7 +18879,7 @@ all_ins(PyObject *m) if (PyModule_AddIntMacro(m, AT_STATX_FORCE_SYNC)) return -1; if (PyModule_AddIntMacro(m, AT_STATX_DONT_SYNC)) return -1; /* STATX_ATTR_* constants are in the stat module */ -#endif /* HAVE_STATX */ +#endif /* _Py_HAVE_STATX */ #if defined(__APPLE__) if (PyModule_AddIntConstant(m, "_COPYFILE_DATA", COPYFILE_DATA)) return -1; @@ -19126,21 +19160,10 @@ posixmodule_exec(PyObject *m) } #endif -#ifdef HAVE_STATX - if (statx == NULL) { - PyObject* dct = PyModule_GetDict(m); - if (dct == NULL) { - return -1; - } - if (PyDict_PopString(dct, "statx", NULL) < 0) { - return -1; - } - } - else { - state->StatxResultType = PyType_FromModuleAndSpec(m, &pystatx_result_spec, NULL); - if (PyModule_AddObjectRef(m, "statx_result", state->StatxResultType) < 0) { - return -1; - } +#ifdef _Py_HAVE_STATX + state->StatxResultType = PyType_FromModuleAndSpec(m, &pystatx_result_spec, NULL); + if (PyModule_AddObjectRef(m, "statx_result", state->StatxResultType) < 0) { + return -1; } #endif diff --git a/configure b/configure index 607f43db23360df..b459344b826830f 100755 --- a/configure +++ b/configure @@ -12019,6 +12019,12 @@ if test "x$ac_cv_header_linux_sched_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_SCHED_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "linux/stat.h" "ac_cv_header_linux_stat_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_stat_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_STAT_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "linux/tipc.h" "ac_cv_header_linux_tipc_h" "$ac_includes_default" if test "x$ac_cv_header_linux_tipc_h" = xyes @@ -26805,11 +26811,35 @@ printf "%s\n" "#define HAVE_SIGINFO_T_SI_BAND 1" >>confdefs.h fi -if test "$ac_cv_func_statx" = yes; then +case $ac_sys_system in #( + Linux*) : + + # Older libc headers may lack struct statx even when the kernel headers + # provide it for use with the syscall. + ac_fn_c_check_type "$LINENO" "struct statx" "ac_cv_type_struct_statx" "#include +" +if test "x$ac_cv_type_struct_statx" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_STATX 1" >>confdefs.h + + +fi + + # Some systems have the definitions of the mask bits without having the # corresponding members in struct statx. Check for members added after Linux - # 4.11 (when statx itself was added). - ac_fn_c_check_member "$LINENO" "struct statx" "stx_mnt_id" "ac_cv_member_struct_statx_stx_mnt_id" "$ac_includes_default" + # 4.11 (when statx itself was added). stx_dio_offset_align was added with + # stx_dio_mem_align; stx_atomic_write_unit_max and + # stx_atomic_write_segments_max were added with stx_atomic_write_unit_min. + # The mask bit for stx_atomic_write_unit_max_opt predates that member. + ac_fn_c_check_member "$LINENO" "struct statx" "stx_mnt_id" "ac_cv_member_struct_statx_stx_mnt_id" " + #include + #if !defined(HAVE_STRUCT_STATX) && defined(HAVE_LINUX_STAT_H) + # include + #endif + +" if test "x$ac_cv_member_struct_statx_stx_mnt_id" = xyes then : @@ -26817,8 +26847,13 @@ printf "%s\n" "#define HAVE_STRUCT_STATX_STX_MNT_ID 1" >>confdefs.h fi +ac_fn_c_check_member "$LINENO" "struct statx" "stx_dio_mem_align" "ac_cv_member_struct_statx_stx_dio_mem_align" " + #include + #if !defined(HAVE_STRUCT_STATX) && defined(HAVE_LINUX_STAT_H) + # include + #endif - ac_fn_c_check_member "$LINENO" "struct statx" "stx_dio_mem_align" "ac_cv_member_struct_statx_stx_dio_mem_align" "$ac_includes_default" +" if test "x$ac_cv_member_struct_statx_stx_dio_mem_align" = xyes then : @@ -26826,9 +26861,13 @@ printf "%s\n" "#define HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN 1" >>confdefs.h fi +ac_fn_c_check_member "$LINENO" "struct statx" "stx_subvol" "ac_cv_member_struct_statx_stx_subvol" " + #include + #if !defined(HAVE_STRUCT_STATX) && defined(HAVE_LINUX_STAT_H) + # include + #endif - # stx_dio_offset_align was added together with stx_dio_mem_align - ac_fn_c_check_member "$LINENO" "struct statx" "stx_subvol" "ac_cv_member_struct_statx_stx_subvol" "$ac_includes_default" +" if test "x$ac_cv_member_struct_statx_stx_subvol" = xyes then : @@ -26836,8 +26875,13 @@ printf "%s\n" "#define HAVE_STRUCT_STATX_STX_SUBVOL 1" >>confdefs.h fi +ac_fn_c_check_member "$LINENO" "struct statx" "stx_atomic_write_unit_min" "ac_cv_member_struct_statx_stx_atomic_write_unit_min" " + #include + #if !defined(HAVE_STRUCT_STATX) && defined(HAVE_LINUX_STAT_H) + # include + #endif - ac_fn_c_check_member "$LINENO" "struct statx" "stx_atomic_write_unit_min" "ac_cv_member_struct_statx_stx_atomic_write_unit_min" "$ac_includes_default" +" if test "x$ac_cv_member_struct_statx_stx_atomic_write_unit_min" = xyes then : @@ -26845,10 +26889,13 @@ printf "%s\n" "#define HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MIN 1" >>confdefs fi +ac_fn_c_check_member "$LINENO" "struct statx" "stx_dio_read_offset_align" "ac_cv_member_struct_statx_stx_dio_read_offset_align" " + #include + #if !defined(HAVE_STRUCT_STATX) && defined(HAVE_LINUX_STAT_H) + # include + #endif - # stx_atomic_write_unit_max and stx_atomic_write_segments_max were added - # together with stx_atomic_write_unit_min - ac_fn_c_check_member "$LINENO" "struct statx" "stx_dio_read_offset_align" "ac_cv_member_struct_statx_stx_dio_read_offset_align" "$ac_includes_default" +" if test "x$ac_cv_member_struct_statx_stx_dio_read_offset_align" = xyes then : @@ -26856,11 +26903,13 @@ printf "%s\n" "#define HAVE_STRUCT_STATX_STX_DIO_READ_OFFSET_ALIGN 1" >>confdefs fi +ac_fn_c_check_member "$LINENO" "struct statx" "stx_atomic_write_unit_max_opt" "ac_cv_member_struct_statx_stx_atomic_write_unit_max_opt" " + #include + #if !defined(HAVE_STRUCT_STATX) && defined(HAVE_LINUX_STAT_H) + # include + #endif - # stx_atomic_write_unit_max_opt was added in Linux 6.16, but is controlled by - # the STATX_WRITE_ATOMIC mask bit added in Linux 6.11, so having the mask bit - # doesn't imply having the member. - ac_fn_c_check_member "$LINENO" "struct statx" "stx_atomic_write_unit_max_opt" "ac_cv_member_struct_statx_stx_atomic_write_unit_max_opt" "$ac_includes_default" +" if test "x$ac_cv_member_struct_statx_stx_atomic_write_unit_max_opt" = xyes then : @@ -26869,7 +26918,10 @@ printf "%s\n" "#define HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MAX_OPT 1" >>conf fi -fi + ;; #( + *) : + ;; +esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for time.h that defines altzone" >&5 printf %s "checking for time.h that defines altzone... " >&6; } diff --git a/configure.ac b/configure.ac index 775b8b4e6038773..c2890faa9a7dccb 100644 --- a/configure.ac +++ b/configure.ac @@ -3194,7 +3194,7 @@ AC_DEFINE([STDC_HEADERS], [1], AC_CHECK_HEADERS([ \ alloca.h asm/types.h bluetooth.h conio.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \ io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/limits.h linux/memfd.h \ - linux/netfilter_ipv4.h linux/random.h linux/soundcard.h linux/sched.h \ + linux/netfilter_ipv4.h linux/random.h linux/soundcard.h linux/sched.h linux/stat.h \ linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h \ poll.h process.h pthread.h pthread_np.h pty.h \ sched.h setjmp.h shadow.h signal.h spawn.h sys/audioio.h sys/bsdtty.h sys/devpoll.h \ @@ -6275,23 +6275,30 @@ AC_CHECK_MEMBERS([struct passwd.pw_gecos, struct passwd.pw_passwd], [], [], [[ # Issue #21085: In Cygwin, siginfo_t does not have si_band field. AC_CHECK_MEMBERS([siginfo_t.si_band], [], [], [[@%:@include ]]) -if test "$ac_cv_func_statx" = yes; then +AS_CASE([$ac_sys_system], [Linux*], [ + # Older libc headers may lack struct statx even when the kernel headers + # provide it for use with the syscall. + AC_CHECK_TYPES([struct statx], [], [], [[#include ]]) + # Some systems have the definitions of the mask bits without having the # corresponding members in struct statx. Check for members added after Linux - # 4.11 (when statx itself was added). - AC_CHECK_MEMBERS([struct statx.stx_mnt_id]) - AC_CHECK_MEMBERS([struct statx.stx_dio_mem_align]) - # stx_dio_offset_align was added together with stx_dio_mem_align - AC_CHECK_MEMBERS([struct statx.stx_subvol]) - AC_CHECK_MEMBERS([struct statx.stx_atomic_write_unit_min]) - # stx_atomic_write_unit_max and stx_atomic_write_segments_max were added - # together with stx_atomic_write_unit_min - AC_CHECK_MEMBERS([struct statx.stx_dio_read_offset_align]) - # stx_atomic_write_unit_max_opt was added in Linux 6.16, but is controlled by - # the STATX_WRITE_ATOMIC mask bit added in Linux 6.11, so having the mask bit - # doesn't imply having the member. - AC_CHECK_MEMBERS([struct statx.stx_atomic_write_unit_max_opt]) -fi + # 4.11 (when statx itself was added). stx_dio_offset_align was added with + # stx_dio_mem_align; stx_atomic_write_unit_max and + # stx_atomic_write_segments_max were added with stx_atomic_write_unit_min. + # The mask bit for stx_atomic_write_unit_max_opt predates that member. + AC_CHECK_MEMBERS([ + struct statx.stx_mnt_id, + struct statx.stx_dio_mem_align, + struct statx.stx_subvol, + struct statx.stx_atomic_write_unit_min, + struct statx.stx_dio_read_offset_align, + struct statx.stx_atomic_write_unit_max_opt], [], [], [[ + #include + #if !defined(HAVE_STRUCT_STATX) && defined(HAVE_LINUX_STAT_H) + # include + #endif + ]]) +]) AC_CACHE_CHECK([for time.h that defines altzone], [ac_cv_header_time_altzone], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], [[return altzone;]])], diff --git a/pyconfig.h.in b/pyconfig.h.in index 0c8c7989a95f972..23115656421e443 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -871,6 +871,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_SOUNDCARD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_STAT_H + /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_TIPC_H @@ -1447,6 +1450,9 @@ /* Define to 1 if 'pw_passwd' is a member of 'struct passwd'. */ #undef HAVE_STRUCT_PASSWD_PW_PASSWD +/* Define to 1 if the system has the type 'struct statx'. */ +#undef HAVE_STRUCT_STATX + /* Define to 1 if 'stx_atomic_write_unit_max_opt' is a member of 'struct statx'. */ #undef HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MAX_OPT From 372ca4814124cb91be7a8b68921bc9dbe6aad521 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 8 Oct 2026 22:52:49 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2026-10-08-22-52-48.gh-issue-153400.4NsKKN.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-10-08-22-52-48.gh-issue-153400.4NsKKN.rst diff --git a/Misc/NEWS.d/next/Library/2026-10-08-22-52-48.gh-issue-153400.4NsKKN.rst b/Misc/NEWS.d/next/Library/2026-10-08-22-52-48.gh-issue-153400.4NsKKN.rst new file mode 100644 index 000000000000000..3e6061dfcc5450e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-08-22-52-48.gh-issue-153400.4NsKKN.rst @@ -0,0 +1,2 @@ +On Linux, :func:`os.statx` falls back to the raw syscall when the libc Python is built against does not provide the +wrapper function. This makes it possible for this function to be available on interpreters built against a libc older than glibc 2.28. From 943aa85e8f55a3f99472ffed9b3f9b8c7b3ed527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Wed, 21 Oct 2026 03:22:18 +0200 Subject: [PATCH 3/3] Fix CI: allowlist new HAVE_LINUX_STAT_H/HAVE_STRUCT_STATX macros (gh-153400) Co-authored-by: Muse Code (Meta Muse Spark) --- Tools/build/check_capi_macros_ignored.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tools/build/check_capi_macros_ignored.txt b/Tools/build/check_capi_macros_ignored.txt index 008eba4b4171433..091fa9bd846681c 100644 --- a/Tools/build/check_capi_macros_ignored.txt +++ b/Tools/build/check_capi_macros_ignored.txt @@ -344,6 +344,7 @@ HAVE_LINUX_QRTR_H HAVE_LINUX_RANDOM_H HAVE_LINUX_SCHED_H HAVE_LINUX_SOUNDCARD_H +HAVE_LINUX_STAT_H HAVE_LINUX_TIPC_H HAVE_LINUX_VM_SOCKETS_H HAVE_LINUX_WAIT_H @@ -540,6 +541,7 @@ HAVE_STROPTS_H HAVE_STRSIGNAL HAVE_STRUCT_PASSWD_PW_GECOS HAVE_STRUCT_PASSWD_PW_PASSWD +HAVE_STRUCT_STATX HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MAX_OPT HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MIN HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN