From patchwork Thu Jul 23 19:46:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 40169 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A20163861968; Thu, 23 Jul 2020 19:47:20 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A20163861968 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1595533640; bh=LMKx8T5jkCS2CYBhctvvO6DzLWAj1yUtlWDQSLGrWPU=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=UWAFOF4Zo4mQdwRsdId60Ew+EBCk0uSGKIeeUVIDUmVxO7csVG5KIl4prV+hOLdUy 9ZURGhAuRXObw8nNEtmdt1gAvUNZPDEQ7FCBF4SCnDC7m4kGNpjrqVs3ZGuhGhPE9i qFSwsa9+50yRpnJY7wQqz7td610e/hEa58q9ZkGg= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x744.google.com (mail-qk1-x744.google.com [IPv6:2607:f8b0:4864:20::744]) by sourceware.org (Postfix) with ESMTPS id 0320B387086F for ; Thu, 23 Jul 2020 19:47:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 0320B387086F Received: by mail-qk1-x744.google.com with SMTP id x69so6582641qkb.1 for ; Thu, 23 Jul 2020 12:47:15 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=LMKx8T5jkCS2CYBhctvvO6DzLWAj1yUtlWDQSLGrWPU=; b=J0/PwNgyg7lyLf4uOWEEw0k2zgDIKfgOPg7xcwwLK0AgG2SJDZifJdowLc62Ewn75t us92MoxCbvUcG+nuKsbBdH6JBVjFyCyKpZsPCMHTKf/vFu7Hz1s4KuxywvZRDOmuVYBY xSGm0gyeg7ZdRr84YzxOf92WAPjfltrImVV2DB6E/7U8sf7oKCoe+pH4I6UCU3Z30aCb Hf4XOL6T0RYkAXi8DB8HjsfoT1hlKg/+z8VQs2+Lij0t3bYijZsgIKcaXiKQ7Q65j7Ms 8wKLHTgdlaZ8B15dPJ3MEzrssOPiPyvXKG1uSCXPUmCWQ5vudjYvn4aYda88r9Z0Ilgj Wx9Q== X-Gm-Message-State: AOAM530spcuk09PDz/I9rRNyFKlsXr4KjBTdptCFb2EuX9xD1/Ys0iE/ 2C1SIvHgqzKJeasOZfOqTnA536kmL2o= X-Google-Smtp-Source: ABdhPJwtaozj5m+0lTXk0P0qs0AMPwquUPWr2prNGKAniIX5JKpTeYDM4zYB4f5/PQX2d8iSIKpxbA== X-Received: by 2002:a05:620a:20dd:: with SMTP id f29mr6677316qka.484.1595533633772; Thu, 23 Jul 2020 12:47:13 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id k56sm3570639qtk.61.2020.07.23.12.47.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jul 2020 12:47:13 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH 15/16] linux: Add {f}stat{at} y2038 support Date: Thu, 23 Jul 2020 16:46:40 -0300 Message-Id: <20200723194641.1949404-16-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200723194641.1949404-1-adhemerval.zanella@linaro.org> References: <20200723194641.1949404-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Cc: Alistair Francis Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" 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. Acked-by: Lukasz Majewski --- 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); + if (r == 0 || errno != ENOSYS) + { + if (r == 0) + __cp_stat_t64_statx (st, &stx); + return r; + } + +# 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)) + 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 */