diff options
author | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2020-07-20 16:02:04 -0300 |
---|---|---|
committer | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2020-10-09 17:02:07 -0300 |
commit | aa03f722f3b994aaf81e72a8904bf33196780930 (patch) | |
tree | 592a547907b3701bcf6c7ba279115caf3bbc1c1c /sysdeps/unix/sysv/linux/fstatat64.c | |
parent | 20b39d59467b0c1d858e89ded8b0cebe55e22f60 (diff) | |
download | glibc-aa03f722f3b994aaf81e72a8904bf33196780930.tar glibc-aa03f722f3b994aaf81e72a8904bf33196780930.tar.gz glibc-aa03f722f3b994aaf81e72a8904bf33196780930.tar.bz2 glibc-aa03f722f3b994aaf81e72a8904bf33196780930.zip |
linux: Add {f}stat{at} y2038 support
A new struct __stat{64}_t64 type is added with the required
__timespec64 time definition. Only LFS is added, 64-bit time with
32-bit offsets is not supposed to be supported (no existing glibc
configuration supports such a combination). It is done with an extra
__NR_statx call plus a conversion to the new __stat{64}_t64 type.
The statx call is done only for 32-bit time_t ABIs.
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 implementation
(stat_t64_cp.c). Alse 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.
Reviewed-by: Lukasz Majewski <lukma@denx.de>
Diffstat (limited to 'sysdeps/unix/sysv/linux/fstatat64.c')
-rw-r--r-- | sysdeps/unix/sysv/linux/fstatat64.c | 95 |
1 files changed, 72 insertions, 23 deletions
diff --git a/sysdeps/unix/sysv/linux/fstatat64.c b/sysdeps/unix/sysv/linux/fstatat64.c index d9d3ea5e64..ae8fc101c5 100644 --- a/sysdeps/unix/sysv/linux/fstatat64.c +++ b/sysdeps/unix/sysv/linux/fstatat64.c @@ -19,56 +19,105 @@ #define __fstatat __redirect___fstatat #define fstatat __redirect_fstatat #include <sys/stat.h> -#undef __fstatat -#undef fstatat #include <fcntl.h> - +#include <string.h> #include <kernel_stat.h> #include <sysdep.h> - +#include <time.h> #include <statx_cp.h> #include <kstat_cp.h> +#include <stat_t64_cp.h> int -__fstatat64 (int fd, const char *file, struct stat64 *buf, int flag) +__fstatat64_time64 (int fd, const char *file, struct __stat64_t64 *buf, + int flag) { + int r; + +#if (__WORDSIZE == 32 \ + && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) + /* 32-bit kABI with default 64-bit time_t, e.g. arc, riscv32. Also + 64-bit time_t support is done through statx syscall. */ + 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 (buf, &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, buf, flag); + r = INLINE_SYSCALL_CALL (newfstatat, fd, file, buf, flag); # elif defined __NR_fstatat64 # if STAT64_IS_KERNEL_STAT64 - /* 64-bit kABI outlier, e.g. alpha. */ - return INLINE_SYSCALL_CALL (fstatat64, fd, file, buf, flag); + /* 64-bit kABI outlier, e.g. alpha */ + r = INLINE_SYSCALL_CALL (fstatat64, fd, file, buf, 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 (buf, &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 (buf, &tmp); - return r; + r = __cp_stat64_kstat64 (buf, &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, buf, flag); + /* All kABIs with non-LFS support and with old 32-bit time_t support + e.g. arm, csky, i386, hppa, m68k, microblaze, nios2, sh, powerpc32, + and sparc32. */ + struct stat64 st64; + r = INLINE_SYSCALL_CALL (fstatat64, fd, file, &st64, flag); + if (r == 0) + { + /* Clear both pad and reserved fields. */ + memset (buf, 0, sizeof (*buf)); + + buf->st_dev = st64.st_dev, + buf->st_ino = st64.st_ino; + buf->st_mode = st64.st_mode; + buf->st_nlink = st64.st_nlink; + buf->st_uid = st64.st_uid; + buf->st_gid = st64.st_gid; + buf->st_rdev = st64.st_rdev; + buf->st_size = st64.st_size; + buf->st_blksize = st64.st_blksize; + buf->st_blocks = st64.st_blocks; + buf->st_atim = valid_timespec_to_timespec64 (st64.st_atim); + buf->st_mtim = valid_timespec_to_timespec64 (st64.st_mtim); + buf->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 = INLINE_SYSCALL_CALL (newfstatat, fd, file, &kst, flag); - return r ?: __cp_kstat_stat64 (&kst, buf); + r = INLINE_SYSCALL_CALL (newfstatat, fd, file, &kst, flag); + if (r == 0) + r = __cp_kstat_stat64_t64 (&kst, buf); # endif #endif + + return r; } +#if __TIMESIZE != 64 +hidden_def (__fstatat64_time64) + +int +__fstatat64 (int fd, const char *file, struct stat64 *buf, int flags) +{ + struct __stat64_t64 st_t64; + return __fstatat64_time64 (fd, file, &st_t64, flags) + ?: __cp_stat64_t64_stat64 (&st_t64, buf); +} +#endif + +#undef __fstatat +#undef fstatat + hidden_def (__fstatat64) weak_alias (__fstatat64, fstatat64) |