diff --git a/configure.ac b/configure.ac index 895afee804..f4a03778fe 100644 --- a/configure.ac +++ b/configure.ac @@ -1897,7 +1897,18 @@ AC_CHECK_FUNCS(sigaltstack) AC_CHECK_FUNCS(sigprocmask) AC_CHECK_FUNCS(sinh) AC_CHECK_FUNCS(spawnv) -AC_CHECK_FUNCS(statx) +AC_CHECK_FUNCS(statx, [], + [AS_CASE(["$target_os"], [linux*], + [AC_CHECK_DECLS([__NR_statx], [ac_cv_func_statx=syscall], [], + [ + @%:@ ifdef HAVE_SYSCALL_H + @%:@ include + @%:@ elif defined HAVE_SYS_SYSCALL_H + @%:@ include + @%:@ endif + ]) + ]) +]) AC_CHECK_FUNCS(symlink) AC_CHECK_FUNCS(syscall) AC_CHECK_FUNCS(sysconf) @@ -1913,6 +1924,8 @@ AC_CHECK_FUNCS(utimes) AC_CHECK_FUNCS(wait4) AC_CHECK_FUNCS(waitpid) +AS_IF([test "$ac_cv_func_statx" = syscall], [AC_DEFINE(HAVE_STATX, 0)]) + AS_CASE(["$ac_cv_func_memset_s:$ac_cv_func_qsort_s"], [*yes*], [RUBY_DEFINE_IF([!defined __STDC_WANT_LIB_EXT1__], [__STDC_WANT_LIB_EXT1__], 1)]) diff --git a/ext/pathname/extconf.rb b/ext/pathname/extconf.rb index c9133bc153..84e68277aa 100644 --- a/ext/pathname/extconf.rb +++ b/ext/pathname/extconf.rb @@ -1,4 +1,4 @@ # frozen_string_literal: false require 'mkmf' -have_struct_member("struct stat", "st_birthtimespec", "sys/stat.h") +have_func("rb_file_s_birthtime") create_makefile('pathname') diff --git a/ext/pathname/pathname.c b/ext/pathname/pathname.c index d5e58c52d8..9cf6c32039 100644 --- a/ext/pathname/pathname.c +++ b/ext/pathname/pathname.c @@ -512,7 +512,7 @@ path_atime(VALUE self) return rb_funcall(rb_cFile, id_atime, 1, get_strpath(self)); } -#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) || defined(_WIN32) +#if defined(HAVE_RB_FILE_S_BIRTHTIME) /* * call-seq: * pathname.birthtime -> time @@ -528,6 +528,7 @@ path_birthtime(VALUE self) return rb_funcall(rb_cFile, id_birthtime, 1, get_strpath(self)); } #else +/* check at compilation time for `respond_to?` */ # define path_birthtime rb_f_notimplement #endif diff --git a/file.c b/file.c index c00c43e5d4..513bde5c65 100644 --- a/file.c +++ b/file.c @@ -1113,6 +1113,24 @@ stat_without_gvl(const char *path, struct stat *st) } #ifdef HAVE_STATX + +# if HAVE_STATX == 0 +# ifdef HAVE_SYSCALL_H +# include +# elif defined HAVE_SYS_SYSCALL_H +# include +# endif +# if defined __linux__ +# include +static inline int +statx(int dirfd, const char *pathname, int flags, + unsigned int mask, struct statx *statxbuf) +{ + return syscall(__NR_statx, dirfd, pathname, flags, mask, statxbuf); +} +# endif +# endif + typedef struct no_gvl_statx_data { struct statx *stx; int fd; @@ -2360,9 +2378,10 @@ rb_file_ctime(VALUE obj) * */ -#if defined(HAVE_STAT_BIRTHTIME) -static VALUE +#if defined(HAVE_STAT_BIRTHTIME) || defined(HAVE_STATX) +RUBY_FUNC_EXPORTED VALUE rb_file_s_birthtime(VALUE klass, VALUE fname) +# if defined(HAVE_STAT_BIRTHTIME) { struct stat st; @@ -2373,9 +2392,7 @@ rb_file_s_birthtime(VALUE klass, VALUE fname) } return stat_birthtime(&st); } -#elif defined(HAVE_STATX) -static VALUE -rb_file_s_birthtime(VALUE klass, VALUE fname) +# elif defined(HAVE_STATX) { struct statx stx; @@ -2390,6 +2407,9 @@ rb_file_s_birthtime(VALUE klass, VALUE fname) } return statx_birthtime(&stx); } +# else +# error Not implemented +# endif #else # define rb_file_s_birthtime rb_f_notimplement #endif diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb index f8e4937802..78f0af71df 100644 --- a/test/pathname/test_pathname.rb +++ b/test/pathname/test_pathname.rb @@ -789,10 +789,15 @@ class TestPathname < Test::Unit::TestCase end def test_birthtime - assert_kind_of(Time, Pathname(__FILE__).birthtime) - rescue NotImplementedError - assert_raise(NotImplementedError) do - File.birthtime(__FILE__) + # Check under a (probably) local filesystem. + # Remote filesystems often may not support birthtime. + with_tmpchdir('rubytest-pathname') do |dir| + open("a", "w") {} + assert_kind_of(Time, Pathname("a").birthtime) + rescue NotImplementedError + assert_raise(NotImplementedError) do + File.birthtime("a") + end end end