Hi Adhemerval, > A new struct __stat{64}_t64 type is added with the required > __timespec64 time definition. Both non-LFS and LFS support were > done with an extra __NR_statx call plus a conversion to the new > __stat{64}_t64 type. The statx call is done only for architectures > with support for 32-bit time_t ABI. > > Internally some extra routines to copy from/to struct stat{64} > to struct __stat{64} used on multiple implementations (stat, fstat, > lstat, and fstatat) are added on a extra file (stat_t64_cp.c). Aslo > some extra routines to copy from statx to __stat{64} is added on > statx_cp.c. > > Checked with a build for all affected ABIs. I also checked on x86_64, > i686, powerpc, powerpc64le, sparcv9, sparc64, s390, and s390x. This patch set is a huge step forward for the *stat* conversion to support 64 bit time. In fact we will only need redirections when -D__USE_TIME_BITS64 support is added. > --- > include/sys/stat.h | 32 +++++ > sysdeps/generic/struct_stat_time64.h | 7 + > sysdeps/unix/sysv/linux/Makefile | 2 +- > sysdeps/unix/sysv/linux/fstat.c | 13 +- > sysdeps/unix/sysv/linux/fstat64.c | 20 ++- > sysdeps/unix/sysv/linux/fstatat.c | 64 +++++---- > sysdeps/unix/sysv/linux/fstatat64.c | 88 ++++++++++--- > sysdeps/unix/sysv/linux/lstat.c | 13 +- > sysdeps/unix/sysv/linux/lstat64.c | 19 ++- > .../unix/sysv/linux/mips/mips64/kstat_cp.h | 23 +--- > .../unix/sysv/linux/mips/mips64/statx_cp.c | 3 - > sysdeps/unix/sysv/linux/stat.c | 13 +- > sysdeps/unix/sysv/linux/stat64.c | 20 ++- > sysdeps/unix/sysv/linux/stat_t64_cp.c | 92 +++++++++++++ > sysdeps/unix/sysv/linux/stat_t64_cp.h | 28 ++++ > sysdeps/unix/sysv/linux/statx_cp.c | 54 ++++++++ > sysdeps/unix/sysv/linux/statx_cp.h | 6 + > sysdeps/unix/sysv/linux/struct_stat_time64.h | 122 > ++++++++++++++++++ 18 files changed, 539 insertions(+), 80 > deletions(-) create mode 100644 sysdeps/generic/struct_stat_time64.h > delete mode 100644 sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c > create mode 100644 sysdeps/unix/sysv/linux/stat_t64_cp.c > create mode 100644 sysdeps/unix/sysv/linux/stat_t64_cp.h > create mode 100644 sysdeps/unix/sysv/linux/struct_stat_time64.h > > diff --git a/include/sys/stat.h b/include/sys/stat.h > index 199173b007..87d4a5ec4f 100644 > --- a/include/sys/stat.h > +++ b/include/sys/stat.h > @@ -3,6 +3,8 @@ > > #ifndef _ISOMAC > # include > +# include > +# include > # include > > static inline bool > @@ -44,6 +46,36 @@ hidden_proto (__lstat64) > hidden_proto (__fstatat64) > # endif > > +# if __TIMESIZE == 64 > +# define __stat_time64 __stat > +# define __stat64_time64 __stat64 > +# define __fstat_time64 __fstat > +# define __fstat64_time64 __fstat64 > +# define __lstat_time64 __lstat > +# define __lstat64_time64 __lstat64 > +# define __fstatat_time64 __fstatat > +# define __fstatat64_time64 __fstatat64 > +# else > +extern int __stat_time64 (const char *file, struct __stat_t64 *buf); > +libc_hidden_proto (__stat_time64); > +extern int __stat64_time64 (const char *file, struct __stat64_t64 > *buf); +hidden_proto (__stat64_time64); > +extern int __lstat_time64 (const char *file, struct __stat_t64 *buf); > +libc_hidden_proto (__lstat_time64); > +extern int __lstat64_time64 (const char *file, struct __stat64_t64 > *buf); +hidden_proto (__lstat64_time64); > +extern int __fstat_time64 (int fd, struct __stat_t64 *buf); > +libc_hidden_proto (__fstat_time64); > +extern int __fstat64_time64 (int fd, struct __stat64_t64 *buf); > +hidden_proto (__fstat64_time64); > +extern int __fstatat_time64 (int dirfd, const char *pathname, > + struct __stat_t64 *buf, int flags); > +libc_hidden_proto (__fstatat_time64); > +extern int __fstatat64_time64 (int dirfd, const char *pathname, > + struct __stat64_t64 *buf, int flags); > +hidden_proto (__fstatat64_time64); > +# endif > + > extern int __chmod (const char *__file, __mode_t __mode); > libc_hidden_proto (__chmod) > extern int __fchmod (int __fd, __mode_t __mode); > diff --git a/sysdeps/generic/struct_stat_time64.h > b/sysdeps/generic/struct_stat_time64.h new file mode 100644 > index 0000000000..24bb9f75cb > --- /dev/null > +++ b/sysdeps/generic/struct_stat_time64.h > @@ -0,0 +1,7 @@ > +#ifndef _BITS_STRUCT_STAT_TIME64_H > +#define _BITS_STRUCT_STAT_TIME64_H 1 > + > +#define __stat_t64 stat > +#define __stat64_t64 stat64 > + > +#endif > diff --git a/sysdeps/unix/sysv/linux/Makefile > b/sysdeps/unix/sysv/linux/Makefile index f189f65daf..95a51ee4f2 100644 > --- a/sysdeps/unix/sysv/linux/Makefile > +++ b/sysdeps/unix/sysv/linux/Makefile > @@ -273,7 +273,7 @@ sysdep_routines += xstatconv internal_statvfs > internal_statvfs64 \ open_nocancel open64_nocancel \ > openat_nocancel openat64_nocancel \ > read_nocancel pread64_nocancel \ > - write_nocancel statx_cp > + write_nocancel statx_cp stat_t64_cp > > sysdep_headers += bits/fcntl-linux.h > > diff --git a/sysdeps/unix/sysv/linux/fstat.c > b/sysdeps/unix/sysv/linux/fstat.c index bdbeded956..0981dbaa95 100644 > --- a/sysdeps/unix/sysv/linux/fstat.c > +++ b/sysdeps/unix/sysv/linux/fstat.c > @@ -19,13 +19,24 @@ > #include > #include > #include > +#include > > #if !XSTAT_IS_XSTAT64 > +int > +__fstat_time64 (int fd, struct __stat_t64 *buf) > +{ > + return __fstatat_time64 (fd, "", buf, AT_EMPTY_PATH); > +} > +# if __TIMESIZE != 64 > +libc_hidden_def (__fstat_time64) > + > int > __fstat (int fd, struct stat *buf) > { > - return __fstatat (fd, "", buf, AT_EMPTY_PATH); > + struct __stat_t64 st_t64; > + return __fstat_time64 (fd, &st_t64) ?: __cp_stat_t64_stat > (&st_t64, buf); } > +# endif > > weak_alias (__fstat, fstat) > #endif > diff --git a/sysdeps/unix/sysv/linux/fstat64.c > b/sysdeps/unix/sysv/linux/fstat64.c index c2ff1ff577..67667e79d8 > 100644 --- a/sysdeps/unix/sysv/linux/fstat64.c > +++ b/sysdeps/unix/sysv/linux/fstat64.c > @@ -19,16 +19,30 @@ > #define __fstat __redirect___fstat > #define fstat __redirect_fstat > #include > -#undef __fstat > -#undef fstat > #include > #include > +#include > + > +int > +__fstat64_time64 (int fd, struct __stat64_t64 *buf) > +{ > + return __fstatat64_time64 (fd, "", buf, AT_EMPTY_PATH); > +} > +#if __TIMESIZE != 64 > +hidden_def (__fstat64_time64) > > int > __fstat64 (int fd, struct stat64 *buf) > { > - return __fstatat64 (fd, "", buf, AT_EMPTY_PATH); > + struct __stat64_t64 st_t64; > + return __fstat64_time64 (fd, &st_t64) > + ?: __cp_stat64_t64_stat64 (&st_t64, buf); > } > +#endif > + > +#undef __fstat > +#undef fstat > + > hidden_def (__fstat64) > weak_alias (__fstat64, fstat64) > > diff --git a/sysdeps/unix/sysv/linux/fstatat.c > b/sysdeps/unix/sysv/linux/fstatat.c index 03ddb3f493..f65d3b74a6 > 100644 --- a/sysdeps/unix/sysv/linux/fstatat.c > +++ b/sysdeps/unix/sysv/linux/fstatat.c > @@ -22,25 +22,28 @@ > > #if !XSTAT_IS_XSTAT64 > # include > +# include > +# include > > int > -__fstatat (int fd, const char *file, struct stat *st, int flag) > +__fstatat_time64 (int fd, const char *file, struct __stat_t64 *st, > int flag) { > -# if STAT_IS_KERNEL_STAT > - /* New kABIs which uses generic pre 64-bit time Linux ABI, e.g. > - csky, nios2 */ > - int r = INLINE_SYSCALL_CALL (fstatat64, fd, file, st, flag); > - if (r == 0 && (st->__st_ino_pad != 0 > - || st->__st_size_pad != 0 > - || st->__st_blocks_pad != 0)) > - return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW); > - return r; > -# else > -# ifdef __NR_fstatat64 > - /* Old KABIs with old non-LFS support, e.g. arm, i386, hppa, m68k, > mips32, > - microblaze, s390, sh, powerpc, and sparc. */ > + struct statx stx; > + int r = INLINE_SYSCALL_CALL (statx, fd, file, flag, > STATX_BASIC_STATS, > + &stx); I'm wondering about the indentation here - I do see 3*TAB and some spaces. Shouldn't we only use spaces? And one more question what is the correct alignment: (statx, fd, file, flag &stx); or (statx, fd, file, flag &stx); > + if (r == 0 || errno != ENOSYS) > + { > + if (r == 0) > + __cp_stat_t64_statx (st, &stx); > + return r; > + } Great that the statx is used here. > + > +# ifdef __NR_fstatat64 > + /* Both new kABI which uses generic pre 64-bit time Linux ABI > (e.g. csky > + and nios) and old kABI with non-LFS support (e.g. arm, i386, > hppa, m68k, > + mips32, microblaze, s390, sh, powerpc, and sparc32). */ > struct stat64 st64; > - int r = INLINE_SYSCALL_CALL (fstatat64, fd, file, &st64, flag); > + r = INLINE_SYSCALL_CALL (fstatat64, fd, file, &st64, flag); > if (r == 0) > { > if (! in_ino_t_range (st64.st_ino) > @@ -48,7 +51,7 @@ __fstatat (int fd, const char *file, struct stat > *st, int flag) || ! in_blkcnt_t_range (st64.st_blocks)) > return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW); > > - /* Clear internal pad and reserved fields. */ > + /* Clear both pad and reserved fields. */ > memset (st, 0, sizeof (*st)); > > st->st_dev = st64.st_dev, > @@ -61,22 +64,29 @@ __fstatat (int fd, const char *file, struct stat > *st, int flag) st->st_size = st64.st_size; > st->st_blksize = st64.st_blksize; > st->st_blocks = st64.st_blocks; > - st->st_atim.tv_sec = st64.st_atim.tv_sec; > - st->st_atim.tv_nsec = st64.st_atim.tv_nsec; > - st->st_mtim.tv_sec = st64.st_mtim.tv_sec; > - st->st_mtim.tv_nsec = st64.st_mtim.tv_nsec; > - st->st_ctim.tv_sec = st64.st_ctim.tv_sec; > - st->st_ctim.tv_nsec = st64.st_ctim.tv_nsec; > + st->st_atim = valid_timespec_to_timespec64 (st64.st_atim); > + st->st_mtim = valid_timespec_to_timespec64 (st64.st_mtim); > + st->st_ctim = valid_timespec_to_timespec64 (st64.st_ctim); > } > return r; > -# else > +# else > /* 64-bit kabi outlier, e.g. mips64 and mips64-n32. */ > struct kernel_stat kst; > - int r = INTERNAL_SYSCALL_CALL (newfstatat, fd, file, &kst, flag); > - return r ?: __cp_kstat_stat (&kst, st); > -# endif /* __nr_fstatat64 */ > -# endif /* STAT_IS_KERNEL_STAT */ > + r = INTERNAL_SYSCALL_CALL (newfstatat, fd, file, &kst, flag); > + return r ?: __cp_kstat_stat_t64 (&kst, st); > +# endif /* __NR_fstatat64 */ > +} > +# if __TIMESIZE != 64 > +libc_hidden_def (__fstatat_time64) > + > +int > +__fstatat (int fd, const char *file, struct stat *buf, int flags) > +{ > + struct __stat_t64 st_t64; > + return __fstatat_time64 (fd, file, &st_t64, flags) > + ?: __cp_stat_t64_stat (&st_t64, buf); > } > +# endif > > weak_alias (__fstatat, fstatat) > #endif > diff --git a/sysdeps/unix/sysv/linux/fstatat64.c > b/sysdeps/unix/sysv/linux/fstatat64.c index 82fab107a5..b3940f0d20 > 100644 --- a/sysdeps/unix/sysv/linux/fstatat64.c > +++ b/sysdeps/unix/sysv/linux/fstatat64.c > @@ -19,56 +19,102 @@ > #define __fstatat __redirect___fstatat > #define fstatat __redirect_fstatat > #include > -#undef __fstatat > -#undef fstatat > #include > - > +#include > #include > #include > - > +#include > #include > #include > +#include > > int > -__fstatat64 (int fd, const char *file, struct stat64 *st, int flag) > +__fstatat64_time64 (int fd, const char *file, struct __stat64_t64 > *st, > + int flag) > { > + int r; > + > +#if (__WORDSIZE == 32 \ > + && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) I do guess that the above condition is to ensure that 32 bit archs (excluding x86_64-x32 - e.g. arm, riscv, etc) use statx? > + struct statx tmp; > + r = INLINE_SYSCALL_CALL (statx, fd, file, AT_NO_AUTOMOUNT | flag, > + STATX_BASIC_STATS, &tmp); > + if (r == 0 || errno != ENOSYS) > + { > + if (r == 0) > + __cp_stat64_t64_statx (st, &tmp); > + return r; > + } > +#endif > + > #if XSTAT_IS_XSTAT64 > # ifdef __NR_newfstatat > /* 64-bit kABI, e.g. aarch64, ia64, powerpc64*, s390x, riscv64, and > x86_64. */ > - return INLINE_SYSCALL_CALL (newfstatat, fd, file, st, flag); > + r = INLINE_SYSCALL_CALL (newfstatat, fd, file, st, flag); > # elif defined __NR_fstatat64 > # if STAT64_IS_KERNEL_STAT64 > - /* 64-bit kABI outlier, e.g. alpha. */ > - return INLINE_SYSCALL_CALL (fstatat64, fd, file, st, flag); > + /* 64-bit kABI outlier, e.g. alpha */ > + r = INLINE_SYSCALL_CALL (fstatat64, fd, file, st, flag); > # else > /* 64-bit kABI outlier, e.g. sparc64. */ > struct kernel_stat64 kst64; > - int r = INLINE_SYSCALL_CALL (fstatat64, fd, file, &kst64, flag); > - return r ?: __cp_stat64_kstat64 (st, &kst64); > -# endif > -# else > - /* 32-bit kABI with default 64-bit time_t, e.g. arc, riscv32. */ > - struct statx tmp; > - int r = INLINE_SYSCALL_CALL (statx, fd, file, AT_NO_AUTOMOUNT | > flag, > - STATX_BASIC_STATS, &tmp); > + r = INLINE_SYSCALL_CALL (fstatat64, fd, file, &kst64, flag); > if (r == 0) > - __cp_stat64_statx (st, &tmp); > - return r; > + r = __cp_stat64_kstat64 (st, &kst64); > +# endif > # endif > #else > # ifdef __NR_fstatat64 > /* All kABIs with non-LFS support, e.g. arm, csky, i386, hppa, > m68k, microblaze, nios2, sh, powerpc32, and sparc32. */ > - return INLINE_SYSCALL_CALL (fstatat64, fd, file, st, flag); > + struct stat64 st64; > + r = INLINE_SYSCALL_CALL (fstatat64, fd, file, &st64, flag); > + if (r == 0) > + { > + /* Clear both pad and reserved fields. */ > + memset (st, 0, sizeof (*st)); > + > + st->st_dev = st64.st_dev, > + st->st_ino = st64.st_ino; > + st->st_mode = st64.st_mode; > + st->st_nlink = st64.st_nlink; > + st->st_uid = st64.st_uid; > + st->st_gid = st64.st_gid; > + st->st_rdev = st64.st_rdev; > + st->st_size = st64.st_size; > + st->st_blksize = st64.st_blksize; > + st->st_blocks = st64.st_blocks; > + st->st_atim = valid_timespec_to_timespec64 (st64.st_atim); > + st->st_mtim = valid_timespec_to_timespec64 (st64.st_mtim); > + st->st_ctim = valid_timespec_to_timespec64 (st64.st_ctim); > + } > # else > /* 64-bit kabi outlier, e.g. mips64 and mips64-n32. */ > struct kernel_stat kst; > - int r = INTERNAL_SYSCALL_CALL (newfstatat, fd, file, &kst, flag); > - return r ?: __cp_kstat_stat64 (&kst, st); > + r = INTERNAL_SYSCALL_CALL (newfstatat, fd, file, &kst, flag); > + if (r == 0) > + r = __cp_kstat_stat64_t64 (&kst, st); > # endif > #endif > + > + return r; > } > +#if __TIMESIZE != 64 > +hidden_def (__fstatat64_time64) > + > +int > +__fstatat64 (int fd, const char *file, struct stat64 *st, int flags) > +{ > + struct __stat64_t64 st_t64; > + return __fstatat64_time64 (fd, file, &st_t64, flags) > + ?: __cp_stat64_t64_stat64 (&st_t64, st); > +} > +#endif > + > +#undef __fstatat > +#undef fstatat > + > hidden_def (__fstatat64) > weak_alias (__fstatat64, fstatat64) > > diff --git a/sysdeps/unix/sysv/linux/lstat.c > b/sysdeps/unix/sysv/linux/lstat.c index b0bdeee9e9..803ad78171 100644 > --- a/sysdeps/unix/sysv/linux/lstat.c > +++ b/sysdeps/unix/sysv/linux/lstat.c > @@ -19,13 +19,24 @@ > #include > #include > #include > +#include > > #if !XSTAT_IS_XSTAT64 > +int > +__lstat_time64 (const char *file, struct __stat_t64 *buf) > +{ > + return __fstatat_time64 (AT_FDCWD, file, buf, AT_SYMLINK_NOFOLLOW); > +} > +# if __TIMESIZE != 64 > +libc_hidden_def (__lstat_time64) > + > int > __lstat (const char *file, struct stat *buf) > { > - return __fstatat (AT_FDCWD, file, buf, AT_SYMLINK_NOFOLLOW); > + struct __stat_t64 st_t64; > + return __lstat_time64 (file, &st_t64) ?: __cp_stat_t64_stat > (&st_t64, buf); } > +# endif > > weak_alias (__lstat, lstat) > #endif > diff --git a/sysdeps/unix/sysv/linux/lstat64.c > b/sysdeps/unix/sysv/linux/lstat64.c index e5f02e9822..971ab8469d > 100644 --- a/sysdeps/unix/sysv/linux/lstat64.c > +++ b/sysdeps/unix/sysv/linux/lstat64.c > @@ -19,19 +19,32 @@ > #define __lstat __redirect___lstat > #define lstat __redirect_lstat > #include > -#undef __lstat > -#undef lstat > #include > #include > +#include > + > +int > +__lstat64_time64 (const char *file, struct __stat64_t64 *buf) > +{ > + return __fstatat64_time64 (AT_FDCWD, file, buf, > AT_SYMLINK_NOFOLLOW); +} > +#if __TIMESIZE != 64 > +hidden_def (__lstat64_time64) > > int > __lstat64 (const char *file, struct stat64 *buf) > { > - return __fstatat64 (AT_FDCWD, file, buf, AT_SYMLINK_NOFOLLOW); > + struct __stat64_t64 st_t64; > + return __lstat64_time64 (file, &st_t64) > + ?: __cp_stat64_t64_stat64 (&st_t64, buf); > } > +#endif > hidden_def (__lstat64) > weak_alias (__lstat64, lstat64) > > +#undef __lstat > +#undef lstat > + > #if XSTAT_IS_XSTAT64 > strong_alias (__lstat64, __lstat) > weak_alias (__lstat64, lstat) > diff --git a/sysdeps/unix/sysv/linux/mips/mips64/kstat_cp.h > b/sysdeps/unix/sysv/linux/mips/mips64/kstat_cp.h index > 7f226416f9..553f4226bc 100644 --- > a/sysdeps/unix/sysv/linux/mips/mips64/kstat_cp.h +++ > b/sysdeps/unix/sysv/linux/mips/mips64/kstat_cp.h @@ -20,23 +20,21 @@ > #include > > static inline int > -__cp_kstat_stat (const struct kernel_stat *kst, struct stat *st) > +__cp_kstat_stat_t64 (const struct kernel_stat *kst, struct > __stat_t64 *st) { > + if (! in_ino_t_range (kst->st_ino) > + || ! in_off_t_range (kst->st_size) > + || ! in_blkcnt_t_range (kst->st_blocks)) > + return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW); > + > st->st_dev = kst->st_dev; > - memset (&st->st_pad1, 0, sizeof (st->st_pad1)); > st->st_ino = kst->st_ino; > - if (st->st_ino != kst->st_ino) > - return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW); > st->st_mode = kst->st_mode; > st->st_nlink = kst->st_nlink; > st->st_uid = kst->st_uid; > st->st_gid = kst->st_gid; > st->st_rdev = kst->st_rdev; > - memset (&st->st_pad2, 0, sizeof (st->st_pad2)); > st->st_size = kst->st_size; > - if (st->st_size != kst->st_size) > - return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW); > - st->st_pad3 = 0; > st->st_atim.tv_sec = kst->st_atime_sec; > st->st_atim.tv_nsec = kst->st_atime_nsec; > st->st_mtim.tv_sec = kst->st_mtime_sec; > @@ -45,26 +43,20 @@ __cp_kstat_stat (const struct kernel_stat *kst, > struct stat *st) st->st_ctim.tv_nsec = kst->st_ctime_nsec; > st->st_blksize = kst->st_blksize; > st->st_blocks = kst->st_blocks; > - if (st->st_blocks != kst->st_blocks) > - return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW); > - memset (&st->st_pad5, 0, sizeof (st->st_pad5)); > > return 0; > } > > static inline int > -__cp_kstat_stat64 (const struct kernel_stat *kst, struct stat64 *st) > +__cp_kstat_stat64_t64 (const struct kernel_stat *kst, struct > __stat64_t64 *st) { > st->st_dev = kst->st_dev; > - memset (&st->st_pad1, 0, sizeof (st->st_pad1)); > st->st_ino = kst->st_ino; > st->st_mode = kst->st_mode; > st->st_nlink = kst->st_nlink; > st->st_uid = kst->st_uid; > st->st_gid = kst->st_gid; > st->st_rdev = kst->st_rdev; > - memset (&st->st_pad2, 0, sizeof (st->st_pad2)); > - st->st_pad3 = 0; > st->st_size = kst->st_size; > st->st_blksize = kst->st_blksize; > st->st_blocks = kst->st_blocks; > @@ -74,7 +66,6 @@ __cp_kstat_stat64 (const struct kernel_stat *kst, > struct stat64 *st) st->st_mtim.tv_nsec = kst->st_mtime_nsec; > st->st_ctim.tv_sec = kst->st_ctime_sec; > st->st_ctim.tv_nsec = kst->st_ctime_nsec; > - memset (&st->st_pad4, 0, sizeof (st->st_pad4)); > > return 0; > } > diff --git a/sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c > b/sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c deleted file mode > 100644 index 260cda987e..0000000000 > --- a/sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c > +++ /dev/null > @@ -1,3 +0,0 @@ > -/* Override the generic statx_cp.c which is only needed for new > 32-bit arch > - without stat64 family support. > - */ > diff --git a/sysdeps/unix/sysv/linux/stat.c > b/sysdeps/unix/sysv/linux/stat.c index a77502eb95..dcbc22da29 100644 > --- a/sysdeps/unix/sysv/linux/stat.c > +++ b/sysdeps/unix/sysv/linux/stat.c > @@ -19,13 +19,24 @@ > #include > #include > #include > +#include > > #if !XSTAT_IS_XSTAT64 > +int > +__stat_time64 (const char *file, struct __stat_t64 *buf) > +{ > + return __fstatat_time64 (AT_FDCWD, file, buf, 0); > +} > +# if __TIMESIZE != 64 > +libc_hidden_def (__stat_time64); > + > int > __stat (const char *file, struct stat *buf) > { > - return __fstatat (AT_FDCWD, file, buf, 0); > + struct __stat_t64 st_t64; > + return __stat_time64 (file, &st_t64) ?: __cp_stat_t64_stat > (&st_t64, buf); } > +# endif > > weak_alias (__stat, stat) > #endif > diff --git a/sysdeps/unix/sysv/linux/stat64.c > b/sysdeps/unix/sysv/linux/stat64.c index 2f40037c2c..bd8b17ac49 100644 > --- a/sysdeps/unix/sysv/linux/stat64.c > +++ b/sysdeps/unix/sysv/linux/stat64.c > @@ -19,16 +19,30 @@ > #define __stat __redirect___stat > #define stat __redirect_stat > #include > -#undef __stat > -#undef stat > #include > #include > +#include > + > +int > +__stat64_time64 (const char *file, struct __stat64_t64 *buf) > +{ > + return __fstatat64_time64 (AT_FDCWD, file, buf, 0); > +} > +#if __TIMESIZE != 64 > +hidden_def (__stat64_time64) > > int > __stat64 (const char *file, struct stat64 *buf) > { > - return __fstatat64 (AT_FDCWD, file, buf, 0); > + struct __stat64_t64 st_t64; > + return __stat64_time64 (file, &st_t64) > + ?: __cp_stat64_t64_stat64 (&st_t64, buf); > } > +#endif > + > +#undef __stat > +#undef stat > + > hidden_def (__stat64) > weak_alias (__stat64, stat64) > > diff --git a/sysdeps/unix/sysv/linux/stat_t64_cp.c > b/sysdeps/unix/sysv/linux/stat_t64_cp.c new file mode 100644 > index 0000000000..56459b6266 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/stat_t64_cp.c > @@ -0,0 +1,92 @@ > +/* Struct stat/stat64 to stat/stat64 conversion for Linux. > + Copyright (C) 2020 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + > + The GNU C Library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + The GNU C Library is distributed in the hope that it will be > useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with the GNU C Library. If not, see > + . */ > + > +#include > +#include > +#include > +#include > + > +#if __TIMESIZE != 64 > +/* Convert the 64-bit time_t stat ST_T64 to the non-LFS ST stat and > returns > + EOVERFLOW if any of time (access, modification, status) is larger > than > + 32-bit time_t. It is used on non-LFS stat, fstat, lstat, and > fstatat to > + convert from the the 64-bit time_t call. */ > +int > +__cp_stat_t64_stat (const struct __stat_t64 *st_t64, struct stat *st) > +{ > + if (! in_time_t_range (st_t64->st_atim.tv_sec) > + || ! in_time_t_range (st_t64->st_mtim.tv_sec) > + || ! in_time_t_range (st_t64->st_ctim.tv_sec)) > + { > + __set_errno (EOVERFLOW); > + return -1; > + } > + > + /* Clear both pad and reserved fields. */ > + memset (st, 0, sizeof (*st)); > + > + st->st_dev = st_t64->st_dev, > + st->st_ino = st_t64->st_ino; > + st->st_mode = st_t64->st_mode; > + st->st_nlink = st_t64->st_nlink; > + st->st_uid = st_t64->st_uid; > + st->st_gid = st_t64->st_gid; > + st->st_rdev = st_t64->st_rdev; > + st->st_size = st_t64->st_size; > + st->st_blksize = st_t64->st_blksize; > + st->st_blocks = st_t64->st_blocks; > + st->st_atim = valid_timespec64_to_timespec (st_t64->st_atim); > + st->st_mtim = valid_timespec64_to_timespec (st_t64->st_mtim); > + st->st_ctim = valid_timespec64_to_timespec (st_t64->st_ctim); > + > + return 0; > +} > + > +int > +__cp_stat64_t64_stat64 (const struct __stat64_t64 *st64_t64, > + struct stat64 *st64) > +{ > + if (! in_time_t_range (st64_t64->st_atim.tv_sec) > + || ! in_time_t_range (st64_t64->st_mtim.tv_sec) > + || ! in_time_t_range (st64_t64->st_ctim.tv_sec)) > + { > + __set_errno (EOVERFLOW); > + return -1; > + } > + > + /* Clear both pad and reserved fields. */ > + memset (st64, 0, sizeof (*st64)); > + > + st64->st_dev = st64_t64->st_dev, > + st64->st_ino = st64_t64->st_ino; > + st64->st_mode = st64_t64->st_mode; > + st64->st_nlink = st64_t64->st_nlink; > + st64->st_uid = st64_t64->st_uid; > + st64->st_gid = st64_t64->st_gid; > + st64->st_rdev = st64_t64->st_rdev; > + st64->st_size = st64_t64->st_size; > + st64->st_blksize = st64_t64->st_blksize; > + st64->st_blocks = st64_t64->st_blocks; > + st64->st_atim = valid_timespec64_to_timespec (st64_t64->st_atim); > + st64->st_mtim = valid_timespec64_to_timespec (st64_t64->st_mtim); > + st64->st_ctim = valid_timespec64_to_timespec (st64_t64->st_ctim); > + > + return 0; > +} > + > +#endif > diff --git a/sysdeps/unix/sysv/linux/stat_t64_cp.h > b/sysdeps/unix/sysv/linux/stat_t64_cp.h new file mode 100644 > index 0000000000..ad2bcc7a04 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/stat_t64_cp.h > @@ -0,0 +1,28 @@ > +/* Copy to/from struct stat with and without 64-bit time_t support. > + Copyright (C) 2020 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + > + The GNU C Library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + The GNU C Library is distributed in the hope that it will be > useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with the GNU C Library. If not, see > + . */ > + > +#include > + > +#if __TIMESIZE != 64 > +extern int __cp_stat_t64_stat (const struct __stat_t64 *st_t64, > + struct stat *st) > + attribute_hidden; > +extern int __cp_stat64_t64_stat64 (const struct __stat64_t64 > *st64_t64, > + struct stat64 *st64) > + attribute_hidden; > +#endif > diff --git a/sysdeps/unix/sysv/linux/statx_cp.c > b/sysdeps/unix/sysv/linux/statx_cp.c index cc6e17929e..4b35e86f8d > 100644 --- a/sysdeps/unix/sysv/linux/statx_cp.c > +++ b/sysdeps/unix/sysv/linux/statx_cp.c > @@ -47,3 +47,57 @@ __cp_stat64_statx (struct stat64 *to, struct statx > *from) to->st_blksize = from->stx_blksize; > } > #endif > + > +void > +__cp_stat_t64_statx (struct __stat_t64 *to, const struct statx *from) > +{ > + /* Clear both pad and reserved fields. */ > + memset (to, 0, sizeof (*to)); > + > + to->st_dev = ((from->stx_dev_minor & 0xff) | (from->stx_dev_major > << 8) > + | ((from->stx_dev_minor & ~0xff) << 12)); > + to->st_ino = from->stx_ino; > + to->st_mode = from->stx_mode; > + to->st_nlink = from->stx_nlink; > + to->st_uid = from->stx_uid; > + to->st_gid = from->stx_gid; > + to->st_rdev = ((from->stx_rdev_minor & 0xff) | > (from->stx_rdev_major << 8) > + | ((from->stx_rdev_minor & ~0xff) << 12)); > + to->st_size = from->stx_size; > + to->st_blksize = from->stx_blksize; > + to->st_blocks = from->stx_blocks; > + > + to->st_atime = from->stx_atime.tv_sec; > + to->st_atim.tv_nsec = from->stx_atime.tv_nsec; > + to->st_mtime = from->stx_mtime.tv_sec; > + to->st_mtim.tv_nsec = from->stx_mtime.tv_nsec; > + to->st_ctime = from->stx_ctime.tv_sec; > + to->st_ctim.tv_nsec = from->stx_ctime.tv_nsec; > +} > + > +void > +__cp_stat64_t64_statx (struct __stat64_t64 *to, const struct statx > *from) +{ > + /* Clear both pad and reserved fields. */ > + memset (to, 0, sizeof (*to)); > + > + to->st_dev = ((from->stx_dev_minor & 0xff) | (from->stx_dev_major > << 8) > + | ((from->stx_dev_minor & ~0xff) << 12)); > + to->st_ino = from->stx_ino; > + to->st_mode = from->stx_mode; > + to->st_nlink = from->stx_nlink; > + to->st_uid = from->stx_uid; > + to->st_gid = from->stx_gid; > + to->st_rdev = ((from->stx_rdev_minor & 0xff) | > (from->stx_rdev_major << 8) > + | ((from->stx_rdev_minor & ~0xff) << 12)); > + to->st_size = from->stx_size; > + to->st_blksize = from->stx_blksize; > + to->st_blocks = from->stx_blocks; > + > + to->st_atime = from->stx_atime.tv_sec; > + to->st_atim.tv_nsec = from->stx_atime.tv_nsec; > + to->st_mtime = from->stx_mtime.tv_sec; > + to->st_mtim.tv_nsec = from->stx_mtime.tv_nsec; > + to->st_ctime = from->stx_ctime.tv_sec; > + to->st_ctim.tv_nsec = from->stx_ctime.tv_nsec; > +} > diff --git a/sysdeps/unix/sysv/linux/statx_cp.h > b/sysdeps/unix/sysv/linux/statx_cp.h index fdbb807a31..bf3186ffac > 100644 --- a/sysdeps/unix/sysv/linux/statx_cp.h > +++ b/sysdeps/unix/sysv/linux/statx_cp.h > @@ -18,3 +18,9 @@ > > extern void __cp_stat64_statx (struct stat64 *to, struct statx *from) > attribute_hidden; > +extern void __cp_stat_t64_statx (struct __stat_t64 *to, > + const struct statx *from) > + attribute_hidden; > +extern void __cp_stat64_t64_statx (struct __stat64_t64 *to, > + const struct statx *from) > + attribute_hidden; > diff --git a/sysdeps/unix/sysv/linux/struct_stat_time64.h > b/sysdeps/unix/sysv/linux/struct_stat_time64.h new file mode 100644 > index 0000000000..b2a51927d0 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/struct_stat_time64.h > @@ -0,0 +1,122 @@ > +/* Struct stat with 64-bit time support. > + Copyright (C) 2020 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + > + The GNU C Library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + The GNU C Library is distributed in the hope that it will be > useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with the GNU C Library; if not, see > + . */ > + > +#ifndef _BITS_STRUCT_STAT_TIME64_H > +#define _BITS_STRUCT_STAT_TIME64_H 1 > + > +#if __TIMESIZE == 64 > +# define __stat_t64 stat > +# define __stat64_t64 stat64 > +#else > +# include > + > +# ifdef __USE_FILE_OFFSET64 > +# define __field64(type, type64, name) type64 name > +# else > +# define __field64(type, type64, name) type name > +# endif > + > +/* The definition should be equal to the 'struct __timespec64' > internal > + layout. */ > +# if BYTE_ORDER == BIG_ENDIAN > +# define __fieldts64(name) \ > + __time64_t name; __int32_t :32; __int32_t name ## nsec > +# else > +# define __fieldts64(name) \ > + __time64_t name; __int32_t name ## nsec; __int32_t :32 > +# endif > + > +/* Workaround for the definition from struct_stat.h */ > +# undef st_atime > +# undef st_mtime > +# undef st_ctime > + > +struct __stat_t64 > + { > + __dev_t st_dev; /* Device. */ > + __field64(__ino_t, __ino64_t, st_ino); /* File serial number. > */ > + __mode_t st_mode; /* File mode. */ > + __nlink_t st_nlink; /* Link count. */ > + __uid_t st_uid; /* User ID of the file's > owner. */ > + __gid_t st_gid; /* Group ID of the file's > group.*/ > + __dev_t st_rdev; /* Device number, if > device. */ > + __field64(__off_t, __off64_t, st_size); /* Size of file, in > bytes. */ > + __blksize_t st_blksize; /* Optimal block size for > I/O. */ > + __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte > blocks */ +# ifdef __USE_XOPEN2K8 > + /* Nanosecond resolution timestamps are stored in a format > + equivalent to 'struct timespec'. This is the type used > + whenever possible but the Unix namespace rules do not allow > the > + identifier 'timespec' to appear in the header. > + Therefore we have to handle the use of this header in strictly > + standard-compliant sources special. */ > + struct __timespec64 st_atim; /* Time of last access. */ > + struct __timespec64 st_mtim; /* Time of last > modification. */ > + struct __timespec64 st_ctim; /* Time of last status > change. */ +# define st_atime st_atim.tv_sec /* Backward > compatibility. */ +# define st_mtime st_mtim.tv_sec > +# define st_ctime st_ctim.tv_sec > +# else > + __fieldts64 (st_atime); > + __fieldts64 (st_mtime); > + __fieldts64 (st_ctime); > +# endif /* __USE_XOPEN2K8 */ > + }; > + > +# undef __field64 > + > +#ifdef __USE_LARGEFILE64 > +struct __stat64_t64 > + { > + __dev_t st_dev; /* Device. */ > + __ino64_t st_ino; /* file serial > number. */ > + __mode_t st_mode; /* File mode. */ > + __nlink_t st_nlink; /* Link count. */ > + __uid_t st_uid; /* User ID of the file's > owner. */ > + __gid_t st_gid; /* Group ID of the file's > group.*/ > + __dev_t st_rdev; /* Device number, if > device. */ > + __off64_t st_size; /* Size of file, in > bytes. */ > + __blksize_t st_blksize; /* Optimal block size for > I/O. */ > + __blkcnt64_t st_blocks; /* Number 512-byte blocks > allocated. */ +# ifdef __USE_XOPEN2K8 > + /* Nanosecond resolution timestamps are stored in a format > + equivalent to 'struct timespec'. This is the type used > + whenever possible but the Unix namespace rules do not allow > the > + identifier 'timespec' to appear in the header. > + Therefore we have to handle the use of this header in strictly > + standard-compliant sources special. */ > + struct __timespec64 st_atim; /* Time of last access. */ > + struct __timespec64 st_mtim; /* Time of last > modification. */ > + struct __timespec64 st_ctim; /* Time of last status > change. */ +# else > + __fieldts64 (st_atime); > + __fieldts64 (st_mtime); > + __fieldts64 (st_ctime); > +# endif /* __USE_XOPEN2K8 */ > + }; > +# endif /* __USE_LARGEFILE64 */ > + > +# undef __fieldts64 > + > +# define _STATBUF_ST_BLKSIZE > +# define _STATBUF_ST_RDEV > +# define _STATBUF_ST_NSEC > + > +# endif /* __TIMESIZE == 64 */ > + > +#endif /* _BITS_STRUCT_STAT_TIME64_H */ Despite some very minor comments, Acked-by: Lukasz Majewski Best regards, Lukasz Majewski -- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de