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 | |
parent | 20b39d59467b0c1d858e89ded8b0cebe55e22f60 (diff) | |
download | glibc-aa03f722f3b994aaf81e72a8904bf33196780930.tar.gz glibc-aa03f722f3b994aaf81e72a8904bf33196780930.tar.xz 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>
-rw-r--r-- | include/sys/stat.h | 20 | ||||
-rw-r--r-- | sysdeps/generic/struct_stat_time64.h | 6 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/Makefile | 2 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/fstat64.c | 20 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/fstatat64.c | 95 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/lstat64.c | 19 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/mips/mips64/kstat_cp.h | 17 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c | 3 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/stat64.c | 20 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/stat_t64_cp.c | 56 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/stat_t64_cp.h | 25 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/statx_cp.c | 30 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/statx_cp.h | 3 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/struct_stat_time64.h | 85 |
14 files changed, 354 insertions, 47 deletions
diff --git a/include/sys/stat.h b/include/sys/stat.h index 3d4ea7f0c7..9f7f3a8e3b 100644 --- a/include/sys/stat.h +++ b/include/sys/stat.h @@ -3,6 +3,8 @@ #ifndef _ISOMAC # include <xstatver.h> +# include <struct___timespec64.h> +# include <struct_stat_time64.h> # include <stdbool.h> static inline bool @@ -44,6 +46,24 @@ hidden_proto (__lstat64) hidden_proto (__fstatat64) # endif +# if __TIMESIZE == 64 +# define __stat64_time64 __stat64 +# define __fstat64_time64 __fstat64 +# define __lstat64_time64 __lstat64 +# define __fstatat_time64 __fstatat +# define __fstatat64_time64 __fstatat64 +# else +extern int __stat64_time64 (const char *file, struct __stat64_t64 *buf); +hidden_proto (__stat64_time64); +extern int __lstat64_time64 (const char *file, struct __stat64_t64 *buf); +hidden_proto (__lstat64_time64); +extern int __fstat64_time64 (int fd, struct __stat64_t64 *buf); +hidden_proto (__fstat64_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..303718d1bf --- /dev/null +++ b/sysdeps/generic/struct_stat_time64.h @@ -0,0 +1,6 @@ +#ifndef _BITS_STRUCT_STAT_TIME64_H +#define _BITS_STRUCT_STAT_TIME64_H 1 + +#define __stat64_t64 stat64 + +#endif diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index e6eb92f381..d760debf40 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -275,7 +275,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/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 <sys/stat.h> -#undef __fstat -#undef fstat #include <fcntl.h> #include <kernel_stat.h> +#include <stat_t64_cp.h> + +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/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) 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 <sys/stat.h> -#undef __lstat -#undef lstat #include <fcntl.h> #include <kernel_stat.h> +#include <stat_t64_cp.h> + +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..1805d4b85f 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/kstat_cp.h +++ b/sysdeps/unix/sysv/linux/mips/mips64/kstat_cp.h @@ -22,11 +22,14 @@ static inline int __cp_kstat_stat (const struct kernel_stat *kst, struct stat *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; @@ -34,8 +37,6 @@ __cp_kstat_stat (const struct kernel_stat *kst, struct stat *st) 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; @@ -45,26 +46,21 @@ __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 +70,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/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 <sys/stat.h> -#undef __stat -#undef stat #include <fcntl.h> #include <kernel_stat.h> +#include <stat_t64_cp.h> + +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..a7de35761f --- /dev/null +++ b/sysdeps/unix/sysv/linux/stat_t64_cp.c @@ -0,0 +1,56 @@ +/* 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 + <https://www.gnu.org/licenses/>. */ + +#include <stat_t64_cp.h> +#include <string.h> +#include <errno.h> +#include <time.h> + +#if __TIMESIZE != 64 +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..18a1b92f6d --- /dev/null +++ b/sysdeps/unix/sysv/linux/stat_t64_cp.h @@ -0,0 +1,25 @@ +/* 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 + <https://www.gnu.org/licenses/>. */ + +#include <sys/stat.h> + +#if __TIMESIZE != 64 +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..8ed74feca5 100644 --- a/sysdeps/unix/sysv/linux/statx_cp.c +++ b/sysdeps/unix/sysv/linux/statx_cp.c @@ -47,3 +47,33 @@ __cp_stat64_statx (struct stat64 *to, struct statx *from) to->st_blksize = from->stx_blksize; } #endif + +#if (__WORDSIZE == 32 \ + && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) +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; +} +#endif diff --git a/sysdeps/unix/sysv/linux/statx_cp.h b/sysdeps/unix/sysv/linux/statx_cp.h index fdbb807a31..42bfd322b4 100644 --- a/sysdeps/unix/sysv/linux/statx_cp.h +++ b/sysdeps/unix/sysv/linux/statx_cp.h @@ -18,3 +18,6 @@ extern void __cp_stat64_statx (struct stat64 *to, 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..b85385b6f3 --- /dev/null +++ b/sysdeps/unix/sysv/linux/struct_stat_time64.h @@ -0,0 +1,85 @@ +/* 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 + <https://www.gnu.org/licenses/>. */ + +#ifndef _BITS_STRUCT_STAT_TIME64_H +#define _BITS_STRUCT_STAT_TIME64_H 1 + +#if __TIMESIZE == 64 +# define __stat64_t64 stat64 +#else +# ifdef __USE_LARGEFILE64 +# include <endian.h> + +/* 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 __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 <sys/stat.h> 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 */ + }; + +# define _STATBUF_ST_BLKSIZE +# define _STATBUF_ST_RDEV +# define _STATBUF_ST_NSEC + +# undef __fieldts64 + +# endif /* __USE_LARGEFILE64 */ + +# endif /* __TIMESIZE == 64 */ + +#endif /* _BITS_STRUCT_STAT_TIME64_H */ |