glibc/sysdeps/unix/sysv/linux/fstatat64.c
WANG Xuerui e6547d635b linux: use statx for fstat if neither newfstatat nor fstatat64 is present
LoongArch is going to be the first architecture supported by Linux that
has neither fstat* nor newfstatat [1], instead exclusively relying on
statx. So in fstatat64's implementation, we need to also enable statx
usage if neither fstatat64 nor newfstatat is present, to prepare for
this new case of kernel ABI.

[1]: https://lore.kernel.org/all/20220518092619.1269111-1-chenhuacai@loongson.cn/

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2022-06-01 12:29:01 -03:00

194 lines
5.9 KiB
C

/* Get file status. Linux version.
Copyright (C) 2020-2022 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/>. */
#define __fstatat __redirect___fstatat
#define fstatat __redirect_fstatat
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <kernel_stat.h>
#include <sysdep.h>
#include <time.h>
#include <kstat_cp.h>
#include <stat_t64_cp.h>
#include <sys/sysmacros.h>
#if __TIMESIZE == 64 \
&& (__WORDSIZE == 32 \
&& (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32))
/* Sanity check to avoid newer 32-bit ABI to support non-LFS calls. */
_Static_assert (sizeof (__off_t) == sizeof (__off64_t),
"__blkcnt_t and __blkcnt64_t must match");
_Static_assert (sizeof (__ino_t) == sizeof (__ino64_t),
"__blkcnt_t and __blkcnt64_t must match");
_Static_assert (sizeof (__blkcnt_t) == sizeof (__blkcnt64_t),
"__blkcnt_t and __blkcnt64_t must match");
#endif
#if (__WORDSIZE == 32 \
&& (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) \
|| defined STAT_HAS_TIME32 \
|| (!defined __NR_newfstatat && !defined __NR_fstatat64)
# define FSTATAT_USE_STATX 1
static inline int
fstatat64_time64_statx (int fd, const char *file, struct __stat64_t64 *buf,
int flag)
{
/* 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;
int r = INTERNAL_SYSCALL_CALL (statx, fd, file, AT_NO_AUTOMOUNT | flag,
STATX_BASIC_STATS, &tmp);
if (r != 0)
return r;
*buf = (struct __stat64_t64) {
.st_dev = __gnu_dev_makedev (tmp.stx_dev_major, tmp.stx_dev_minor),
.st_rdev = __gnu_dev_makedev (tmp.stx_rdev_major, tmp.stx_rdev_minor),
.st_ino = tmp.stx_ino,
.st_mode = tmp.stx_mode,
.st_nlink = tmp.stx_nlink,
.st_uid = tmp.stx_uid,
.st_gid = tmp.stx_gid,
.st_atime = tmp.stx_atime.tv_sec,
.st_atim.tv_nsec = tmp.stx_atime.tv_nsec,
.st_mtime = tmp.stx_mtime.tv_sec,
.st_mtim.tv_nsec = tmp.stx_mtime.tv_nsec,
.st_ctime = tmp.stx_ctime.tv_sec,
.st_ctim.tv_nsec = tmp.stx_ctime.tv_nsec,
.st_size = tmp.stx_size,
.st_blocks = tmp.stx_blocks,
.st_blksize = tmp.stx_blksize,
};
return r;
}
#else
# define FSTATAT_USE_STATX 0
#endif
/* Only statx supports 64-bit timestamps for 32-bit architectures with
__ASSUME_STATX, so there is no point in building the fallback. */
#if !FSTATAT_USE_STATX || (FSTATAT_USE_STATX && !defined __ASSUME_STATX)
static inline int
fstatat64_time64_stat (int fd, const char *file, struct __stat64_t64 *buf,
int flag)
{
int r;
#if XSTAT_IS_XSTAT64
# ifdef __NR_newfstatat
/* 64-bit kABI, e.g. aarch64, ia64, powerpc64*, s390x, riscv64, and
x86_64. */
r = INTERNAL_SYSCALL_CALL (newfstatat, fd, file, buf, flag);
# elif defined __NR_fstatat64
# if STAT64_IS_KERNEL_STAT64
/* 64-bit kABI outlier, e.g. alpha */
r = INTERNAL_SYSCALL_CALL (fstatat64, fd, file, buf, flag);
# else
/* 64-bit kABI outlier, e.g. sparc64. */
struct kernel_stat64 kst64;
r = INTERNAL_SYSCALL_CALL (fstatat64, fd, file, &kst64, flag);
if (r == 0)
__cp_stat64_kstat64 (buf, &kst64);
# endif
# endif
#else
# ifdef __NR_fstatat64
/* 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 = INTERNAL_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;
r = INTERNAL_SYSCALL_CALL (newfstatat, fd, file, &kst, flag);
if (r == 0)
__cp_kstat_stat64_t64 (&kst, buf);
# endif
#endif
return r;
}
#endif
int
__fstatat64_time64 (int fd, const char *file, struct __stat64_t64 *buf,
int flag)
{
int r;
#if FSTATAT_USE_STATX
r = fstatat64_time64_statx (fd, file, buf, flag);
# ifndef __ASSUME_STATX
if (r == -ENOSYS)
r = fstatat64_time64_stat (fd, file, buf, flag);
# endif
#else
r = fstatat64_time64_stat (fd, file, buf, flag);
#endif
return INTERNAL_SYSCALL_ERROR_P (r)
? INLINE_SYSCALL_ERROR_RETURN_VALUE (-r)
: 0;
}
#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)
#if XSTAT_IS_XSTAT64
strong_alias (__fstatat64, __fstatat)
weak_alias (__fstatat64, fstatat)
strong_alias (__fstatat64, __GI___fstatat);
#endif