From e310f8bddf6ab87459df3f1172e18543c86e23b7 Mon Sep 17 00:00:00 2001 From: Siva Chandra Reddy Date: Fri, 9 Sep 2022 19:02:28 +0000 Subject: [PATCH] [libc] Add implementation of functions stat, fstat and lstat. All supporting type and macro definitions have also been added. Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D134262 --- libc/config/linux/api.td | 3 +- libc/config/linux/x86_64/entrypoints.txt | 3 + libc/include/CMakeLists.txt | 1 + .../llvm-libc-macros/linux/fcntl-macros.h | 16 +++ libc/include/llvm-libc-types/CMakeLists.txt | 16 ++- libc/include/llvm-libc-types/blkcnt_t.h | 14 +++ libc/include/llvm-libc-types/blksize_t.h | 14 +++ libc/include/llvm-libc-types/dev_t.h | 14 +++ libc/include/llvm-libc-types/gid_t.h | 14 +++ libc/include/llvm-libc-types/ino_t.h | 4 +- libc/include/llvm-libc-types/nlink_t.h | 14 +++ libc/include/llvm-libc-types/struct_stat.h | 39 +++++++ .../include/llvm-libc-types/struct_timespec.h | 19 ++++ libc/include/llvm-libc-types/time_t.h | 2 +- libc/include/llvm-libc-types/uid_t.h | 14 +++ libc/spec/posix.td | 29 ++++- libc/src/sys/stat/CMakeLists.txt | 21 ++++ libc/src/sys/stat/fstat.h | 20 ++++ libc/src/sys/stat/linux/CMakeLists.txt | 47 ++++++++ libc/src/sys/stat/linux/fstat.cpp | 23 ++++ libc/src/sys/stat/linux/kernel_statx.h | 105 ++++++++++++++++++ libc/src/sys/stat/linux/lstat.cpp | 26 +++++ libc/src/sys/stat/linux/stat.cpp | 25 +++++ libc/src/sys/stat/lstat.h | 20 ++++ libc/src/sys/stat/stat.h | 20 ++++ libc/test/src/sys/stat/CMakeLists.txt | 48 ++++++++ libc/test/src/sys/stat/fstat_test.cpp | 51 +++++++++ libc/test/src/sys/stat/lstat_test.cpp | 51 +++++++++ libc/test/src/sys/stat/stat_test.cpp | 51 +++++++++ 29 files changed, 718 insertions(+), 6 deletions(-) create mode 100644 libc/include/llvm-libc-types/blkcnt_t.h create mode 100644 libc/include/llvm-libc-types/blksize_t.h create mode 100644 libc/include/llvm-libc-types/dev_t.h create mode 100644 libc/include/llvm-libc-types/gid_t.h create mode 100644 libc/include/llvm-libc-types/nlink_t.h create mode 100644 libc/include/llvm-libc-types/struct_stat.h create mode 100644 libc/include/llvm-libc-types/struct_timespec.h create mode 100644 libc/include/llvm-libc-types/uid_t.h create mode 100644 libc/src/sys/stat/fstat.h create mode 100644 libc/src/sys/stat/linux/fstat.cpp create mode 100644 libc/src/sys/stat/linux/kernel_statx.h create mode 100644 libc/src/sys/stat/linux/lstat.cpp create mode 100644 libc/src/sys/stat/linux/stat.cpp create mode 100644 libc/src/sys/stat/lstat.h create mode 100644 libc/src/sys/stat/stat.h create mode 100644 libc/test/src/sys/stat/fstat_test.cpp create mode 100644 libc/test/src/sys/stat/lstat_test.cpp create mode 100644 libc/test/src/sys/stat/stat_test.cpp diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td index 97eed64c9f3a..665620e8533b 100644 --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -277,7 +277,8 @@ def SysResourceAPI : PublicAPI<"sys/resource.h"> { } def SysStatAPI : PublicAPI<"sys/stat.h"> { - let Types = ["mode_t"]; + let Types = ["mode_t", "dev_t", "ino_t", "nlink_t", "uid_t", "gid_t", "off_t", + "struct timespec", "blksize_t", "blkcnt_t", "struct stat"]; } def SysSendfileAPI : PublicAPI<"sys/sendfile.h"> { diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 187165a2b8a5..5d5d73e9c698 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -113,8 +113,11 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.sys.stat.chmod libc.src.sys.stat.fchmod libc.src.sys.stat.fchmodat + libc.src.sys.stat.fstat + libc.src.sys.stat.lstat libc.src.sys.stat.mkdir libc.src.sys.stat.mkdirat + libc.src.sys.stat.stat # sys/utsname.h entrypoints libc.src.sys.utsname.uname diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 04354c7c185f..30b4af0fd652 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -222,6 +222,7 @@ add_gen_header( .llvm_libc_common_h .llvm-libc-macros.sys_stat_macros .llvm-libc-types.mode_t + .llvm-libc-types.struct_stat ) add_gen_header( diff --git a/libc/include/llvm-libc-macros/linux/fcntl-macros.h b/libc/include/llvm-libc-macros/linux/fcntl-macros.h index 92e4568e61a2..cdd1cf22d7b6 100644 --- a/libc/include/llvm-libc-macros/linux/fcntl-macros.h +++ b/libc/include/llvm-libc-macros/linux/fcntl-macros.h @@ -62,6 +62,15 @@ #define S_ISUID 04000 #define S_ISGID 02000 +// File type flags +#define S_IFMT 0170000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFBLK 0060000 +#define S_IFREG 0100000 +#define S_FIFO 0010000 +#define S_IFLNK 0120000 + // Special directory FD to indicate that the path argument to // openat is relative to the current directory. #define AT_FDCWD -100 @@ -70,6 +79,13 @@ // has to perform the equivalent of "rmdir" on the path argument. #define AT_REMOVEDIR 0x200 +// Special flag for functions like lstat to convey that symlinks +// should not be followed. +#define AT_SYMLINK_NOFOLLOW 0x100 + +// Allow empty relative pathname. +#define AT_EMPTY_PATH 0x1000 + // Values of SYS_fcntl commands. #define F_DUPFD 0 #define F_GETFD 1 diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt index 79d969d63416..432278e41f4c 100644 --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -9,10 +9,13 @@ add_header(__pthread_tss_dtor_t HDR __pthread_tss_dtor_t.h) add_header(__qsortcompare_t HDR __qsortcompare_t.h) add_header(__sighandler_t HDR __sighandler_t.h) add_header(__thread_type HDR __thread_type.h) +add_header(blkcnt_t HDR blkcnt_t.h) +add_header(blksize_t HDR blksize_t.h) add_header(cnd_t HDR cnd_t.h) add_header(cookie_io_functions_t HDR cookie_io_functions_t.h DEPENDS .off64_t) add_header(double_t HDR double_t.h) add_header(DIR HDR DIR.h) +add_header(dev_t HDR dev_t.h) add_header(div_t HDR div_t.h) add_header(ldiv_t HDR ldiv_t.h) add_header(lldiv_t HDR lldiv_t.h) @@ -20,10 +23,13 @@ add_header(FILE HDR FILE.h) add_header(fenv_t HDR fenv_t.h) add_header(fexcept_t HDR fexcept_t.h) add_header(float_t HDR float_t.h) +add_header(gid_t HDR gid_t.h) +add_header(uid_t HDR uid_t.h) add_header(imaxdiv_t HDR imaxdiv_t.h) add_header(ino_t HDR ino_t.h) add_header(mode_t HDR mode_t.h) add_header(mtx_t HDR mtx_t.h DEPENDS .__futex_word .__mutex_type) +add_header(nlink_t HDR nlink_t.h) add_header(off_t HDR off_t.h) add_header(once_flag HDR once_flag.h DEPENDS .__futex_word) add_header(pthread_attr_t HDR pthread_attr_t.h DEPENDS .size_t) @@ -36,11 +42,19 @@ add_header(struct_rlimit HDR struct_rlimit.h DEPENDS .rlim_t) add_header(ssize_t HDR ssize_t.h) add_header(struct_dirent HDR struct_dirent.h DEPENDS .ino_t .off_t) add_header(struct_sigaction HDR struct_sigaction.h) +add_header(time_t HDR time_t.h) +add_header(struct_timespec HDR struct_timespec.h DEPENDS .time_t) +add_header( + struct_stat + HDR struct_stat.h + DEPENDS + .dev_t .ino_t .mode_t .nlink_t .uid_t .gid_t .off_t .struct_timespec + .blksize_t .blkcnt_t +) add_header(struct_tm HDR struct_tm.h) add_header(struct_utsname HDR struct_utsname.h) add_header(thrd_start_t HDR thrd_start_t.h) add_header(thrd_t HDR thrd_t.h DEPENDS .__thread_type) -add_header(time_t HDR time_t.h) add_header(tss_t HDR tss_t.h) add_header(tss_dtor_t HDR tss_dtor_t.h) add_header(__atexithandler_t HDR __atexithandler_t.h) diff --git a/libc/include/llvm-libc-types/blkcnt_t.h b/libc/include/llvm-libc-types/blkcnt_t.h new file mode 100644 index 000000000000..acd8d3467ec5 --- /dev/null +++ b/libc/include/llvm-libc-types/blkcnt_t.h @@ -0,0 +1,14 @@ +//===-- Definition of blkcnt_t type ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_BLKCNT_T_H__ +#define __LLVM_LIBC_TYPES_BLKCNT_T_H__ + +typedef __INTPTR_TYPE__ blkcnt_t; + +#endif // __LLVM_LIBC_TYPES_BLKCNT_T_H__ diff --git a/libc/include/llvm-libc-types/blksize_t.h b/libc/include/llvm-libc-types/blksize_t.h new file mode 100644 index 000000000000..99ddac56194a --- /dev/null +++ b/libc/include/llvm-libc-types/blksize_t.h @@ -0,0 +1,14 @@ +//===-- Definition of blksize_t type --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_BLKSIZE_T_H__ +#define __LLVM_LIBC_TYPES_BLKSIZE_T_H__ + +typedef __INTPTR_TYPE__ blksize_t; + +#endif // __LLVM_LIBC_TYPES_BLKSIZE_T_H__ diff --git a/libc/include/llvm-libc-types/dev_t.h b/libc/include/llvm-libc-types/dev_t.h new file mode 100644 index 000000000000..9fbc41a49b89 --- /dev/null +++ b/libc/include/llvm-libc-types/dev_t.h @@ -0,0 +1,14 @@ +//===-- Definition of dev_t type ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_DEV_T_H__ +#define __LLVM_LIBC_TYPES_DEV_T_H__ + +typedef __UINT64_TYPE__ dev_t; + +#endif // __LLVM_LIBC_TYPES_DEV_T_H__ diff --git a/libc/include/llvm-libc-types/gid_t.h b/libc/include/llvm-libc-types/gid_t.h new file mode 100644 index 000000000000..664aee020a4e --- /dev/null +++ b/libc/include/llvm-libc-types/gid_t.h @@ -0,0 +1,14 @@ +//===-- Definition of gid_t type ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_GID_T_H__ +#define __LLVM_LIBC_TYPES_GID_T_H__ + +typedef __UINT32_TYPE__ gid_t; + +#endif // __LLVM_LIBC_TYPES_GID_T_H__ diff --git a/libc/include/llvm-libc-types/ino_t.h b/libc/include/llvm-libc-types/ino_t.h index 3531dd3829e9..0f5abd96c2b7 100644 --- a/libc/include/llvm-libc-types/ino_t.h +++ b/libc/include/llvm-libc-types/ino_t.h @@ -1,4 +1,4 @@ -//===-- Definition of type ino_t ------------------------------------------===// +//===-- Definition of ino_t type ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,6 +9,6 @@ #ifndef __LLVM_LIBC_TYPES_INO_T_H__ #define __LLVM_LIBC_TYPES_INO_T_H__ -typedef unsigned long ino_t; +typedef __UINTPTR_TYPE__ ino_t; #endif // __LLVM_LIBC_TYPES_INO_T_H__ diff --git a/libc/include/llvm-libc-types/nlink_t.h b/libc/include/llvm-libc-types/nlink_t.h new file mode 100644 index 000000000000..1826144b3c88 --- /dev/null +++ b/libc/include/llvm-libc-types/nlink_t.h @@ -0,0 +1,14 @@ +//===-- Definition of nlink_t type ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_NLINK_T_H__ +#define __LLVM_LIBC_TYPES_NLINK_T_H__ + +typedef __UINTPTR_TYPE__ nlink_t; + +#endif // __LLVM_LIBC_TYPES_NLINK_T_H__ diff --git a/libc/include/llvm-libc-types/struct_stat.h b/libc/include/llvm-libc-types/struct_stat.h new file mode 100644 index 000000000000..baaef15d9964 --- /dev/null +++ b/libc/include/llvm-libc-types/struct_stat.h @@ -0,0 +1,39 @@ +//===-- Definition of struct stat -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_STRUCT_STAT_H__ +#define __LLVM_LIBC_TYPES_STRUCT_STAT_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + blksize_t st_blksize; + blkcnt_t st_blocks; +}; + +#endif // __LLVM_LIBC_TYPES_STRUCT_STAT_H__ diff --git a/libc/include/llvm-libc-types/struct_timespec.h b/libc/include/llvm-libc-types/struct_timespec.h new file mode 100644 index 000000000000..eb6e70bb578a --- /dev/null +++ b/libc/include/llvm-libc-types/struct_timespec.h @@ -0,0 +1,19 @@ +//===-- Definition of struct timespec -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_TIMESPEC_H__ +#define __LLVM_LIBC_TYPES_TIMESPEC_H__ + +#include + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +#endif // __LLVM_LIBC_TYPES_TIMESPEC_H__ diff --git a/libc/include/llvm-libc-types/time_t.h b/libc/include/llvm-libc-types/time_t.h index 13c33b07c223..d66ee371ccba 100644 --- a/libc/include/llvm-libc-types/time_t.h +++ b/libc/include/llvm-libc-types/time_t.h @@ -9,6 +9,6 @@ #ifndef __LLVM_LIBC_TYPES_TIME_T_H__ #define __LLVM_LIBC_TYPES_TIME_T_H__ -typedef long time_t; +typedef __INTPTR_TYPE__ time_t; #endif // __LLVM_LIBC_TYPES_TIME_T_H__ diff --git a/libc/include/llvm-libc-types/uid_t.h b/libc/include/llvm-libc-types/uid_t.h new file mode 100644 index 000000000000..ae9fac2a4288 --- /dev/null +++ b/libc/include/llvm-libc-types/uid_t.h @@ -0,0 +1,14 @@ +//===-- Definition of uid_t type ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_UID_T_H__ +#define __LLVM_LIBC_TYPES_UID_T_H__ + +typedef __UINT32_TYPE__ uid_t; + +#endif // __LLVM_LIBC_TYPES_UID_T_H__ diff --git a/libc/spec/posix.td b/libc/spec/posix.td index 1980b09996ed..3c5e093b2b1d 100644 --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -16,6 +16,18 @@ def PThreadKeyT : NamedType<"pthread_key_t">; def PThreadKeyTPtr : PtrType; def InoT : NamedType<"ino_t">; +def UidT : NamedType<"uid_t">; +def GidT : NamedType<"gid_t">; +def DevT : NamedType<"dev_t">; +def BlkSizeT : NamedType<"blksize_t">; +def BlkCntT : NamedType<"blkcnt_t">; +def NLinkT : NamedType<"nlink_t">; +def TimeSpec : NamedType<"struct timespec">; + +def StatType : NamedType<"struct stat">; +def StatTypePtr : PtrType; +def RestrictedStatTypePtr : RestrictedPtrType; + def DIR : NamedType<"DIR">; def DIRPtr : PtrType; def DIRRestrictedPtr : RestrictedPtrType; @@ -491,7 +503,7 @@ def POSIX : StandardSpec<"POSIX"> { HeaderSpec SysStat = HeaderSpec< "sys/stat.h", [], // Macros - [ModeTType], // Types + [ModeTType, DevT, InoT, UidT, GidT, TimeSpec, BlkSizeT, BlkCntT, OffTType, NLinkT, StatType], // Types [], // Enumerations [ FunctionSpec< @@ -509,6 +521,16 @@ def POSIX : StandardSpec<"POSIX"> { RetValSpec, [ArgSpec, ArgSpec, ArgSpec, ArgSpec] >, + FunctionSpec< + "fstat", + RetValSpec, + [ArgSpec, ArgSpec] + >, + FunctionSpec< + "lstat", + RetValSpec, + [ArgSpec, ArgSpec] + >, FunctionSpec< "mkdir", RetValSpec, @@ -519,6 +541,11 @@ def POSIX : StandardSpec<"POSIX"> { RetValSpec, [ArgSpec, ArgSpec, ArgSpec] >, + FunctionSpec< + "stat", + RetValSpec, + [ArgSpec, ArgSpec] + >, ] >; diff --git a/libc/src/sys/stat/CMakeLists.txt b/libc/src/sys/stat/CMakeLists.txt index 9ffa219b8662..0775f882c638 100644 --- a/libc/src/sys/stat/CMakeLists.txt +++ b/libc/src/sys/stat/CMakeLists.txt @@ -23,6 +23,20 @@ add_entrypoint_object( .${LIBC_TARGET_OS}.fchmod ) +add_entrypoint_object( + fstat + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.fstat +) + +add_entrypoint_object( + lstat + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.lstat +) + add_entrypoint_object( mkdir ALIAS @@ -36,3 +50,10 @@ add_entrypoint_object( DEPENDS .${LIBC_TARGET_OS}.mkdirat ) + +add_entrypoint_object( + stat + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.stat +) diff --git a/libc/src/sys/stat/fstat.h b/libc/src/sys/stat/fstat.h new file mode 100644 index 000000000000..ec559a6bf225 --- /dev/null +++ b/libc/src/sys/stat/fstat.h @@ -0,0 +1,20 @@ +//===-- Implementation header for fstat -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_STAT_FSTAT_H +#define LLVM_LIBC_SRC_SYS_STAT_FSTAT_H + +#include + +namespace __llvm_libc { + +int fstat(int fd, struct stat *statbuf); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SYS_STAT_FSTAT_H diff --git a/libc/src/sys/stat/linux/CMakeLists.txt b/libc/src/sys/stat/linux/CMakeLists.txt index 545758f0ede9..6c8b1b6a8e59 100644 --- a/libc/src/sys/stat/linux/CMakeLists.txt +++ b/libc/src/sys/stat/linux/CMakeLists.txt @@ -64,3 +64,50 @@ add_entrypoint_object( libc.src.__support.OSUtil.osutil libc.src.errno.errno ) + +add_header_library( + kernel_statx + HDRS + kernel_statx.h + DEPENDS + libc.include.sys_stat + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_entrypoint_object( + stat + SRCS + stat.cpp + HDRS + ../stat.h + DEPENDS + .kernel_statx + libc.include.fcntl + libc.include.sys_stat +) + +add_entrypoint_object( + lstat + SRCS + lstat.cpp + HDRS + ../lstat.h + DEPENDS + .kernel_statx + libc.include.fcntl + libc.include.sys_stat +) + +add_entrypoint_object( + fstat + SRCS + fstat.cpp + HDRS + ../fstat.h + DEPENDS + .kernel_statx + libc.include.fcntl + libc.include.sys_stat +) diff --git a/libc/src/sys/stat/linux/fstat.cpp b/libc/src/sys/stat/linux/fstat.cpp new file mode 100644 index 000000000000..6baf716157ee --- /dev/null +++ b/libc/src/sys/stat/linux/fstat.cpp @@ -0,0 +1,23 @@ +//===-- Linux implementation of fstat -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/sys/stat/fstat.h" +#include "kernel_statx.h" + +#include "src/__support/common.h" + +#include +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, fstat, (int fd, struct stat *statbuf)) { + return statx(fd, "", AT_EMPTY_PATH, statbuf); +} + +} // namespace __llvm_libc diff --git a/libc/src/sys/stat/linux/kernel_statx.h b/libc/src/sys/stat/linux/kernel_statx.h new file mode 100644 index 000000000000..3f14f4dca8cc --- /dev/null +++ b/libc/src/sys/stat/linux/kernel_statx.h @@ -0,0 +1,105 @@ +//===-- Wrapper over SYS_statx syscall ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_STAT_LINUX_STATX_H +#define LLVM_LIBC_SRC_SYS_STAT_LINUX_STATX_H + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. + +#include +#include +#include +#include // For syscall numbers. + +// It is safe to include this kernel header as it is designed to be +// included from user programs without causing any name pollution. +#include + +namespace { + +// The type definitions in the internal namespace match kernel's definition of +// the statx_timestamp and statx types in linux/stat.h. We define equivalent +// types here instead of including that header file to avoid name mixup between +// linux/stat.h and the libc's stat.h. +struct statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t __reserved; +}; + +struct statx_buf { + uint32_t stx_mask; // What results were written + uint32_t stx_blksize; // Preferred general I/O size + uint64_t stx_attributes; // Flags conveying information about the file + uint32_t stx_nlink; // Number of hard links + uint32_t stx_uid; // User ID of owner + uint32_t stx_gid; // Group ID of owner + uint16_t stx_mode; // File mode + uint16_t __spare0[1]; + uint64_t stx_ino; // Inode number + uint64_t stx_size; // File size + uint64_t stx_blocks; // Number of 512-byte blocks allocated + uint64_t stx_attributes_mask; // Mask to show what's supported in + // stx_attributes + struct statx_timestamp stx_atime; // Last access time + struct statx_timestamp stx_btime; // File creation time + struct statx_timestamp stx_ctime; // Last attribute change time + struct statx_timestamp stx_mtime; // Last data modification time + uint32_t stx_rdev_major; // Device ID of special file + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; // ID of device containing file + uint32_t stx_dev_minor; + uint64_t stx_mnt_id; + uint64_t __spare2; + uint64_t __spare3[12]; // Spare space for future expansion +}; + +// The below mask value is based on the definition of a similarly +// named macro in linux/stat.h. When this flag is passed for the +// mask argument to the statx syscall, all fields except the +// stx_btime field will be filled in. +constexpr unsigned int STATX_BASIC_STATS_MASK = 0x7FF; + +} // Anonymous namespace + +namespace __llvm_libc { + +inline int statx(int dirfd, const char *__restrict path, int flags, + struct stat *__restrict statbuf) { + // We make a statx syscall and copy out the result into the |statbuf|. + ::statx_buf xbuf; + long ret = + syscall(SYS_statx, dirfd, path, flags, ::STATX_BASIC_STATS_MASK, &xbuf); + if (ret < 0) { + errno = -ret; + return -1; + } + + statbuf->st_dev = MKDEV(xbuf.stx_dev_major, xbuf.stx_dev_minor); + statbuf->st_ino = xbuf.stx_ino; + statbuf->st_mode = xbuf.stx_mode; + statbuf->st_nlink = xbuf.stx_nlink; + statbuf->st_uid = xbuf.stx_uid; + statbuf->st_gid = xbuf.stx_gid; + statbuf->st_rdev = MKDEV(xbuf.stx_rdev_major, xbuf.stx_rdev_minor); + statbuf->st_size = xbuf.stx_size; + statbuf->st_atim.tv_sec = xbuf.stx_atime.tv_sec; + statbuf->st_atim.tv_nsec = xbuf.stx_atime.tv_nsec; + statbuf->st_mtim.tv_sec = xbuf.stx_mtime.tv_sec; + statbuf->st_mtim.tv_nsec = xbuf.stx_mtime.tv_nsec; + statbuf->st_ctim.tv_sec = xbuf.stx_ctime.tv_sec; + statbuf->st_ctim.tv_nsec = xbuf.stx_ctime.tv_nsec; + statbuf->st_blksize = xbuf.stx_blksize; + statbuf->st_blocks = xbuf.stx_blocks; + + return 0; +} + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SYS_STAT_LINUX_STATX_H diff --git a/libc/src/sys/stat/linux/lstat.cpp b/libc/src/sys/stat/linux/lstat.cpp new file mode 100644 index 000000000000..816760a8c145 --- /dev/null +++ b/libc/src/sys/stat/linux/lstat.cpp @@ -0,0 +1,26 @@ +//===-- Linux implementation of lstat -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/sys/stat/lstat.h" +#include "kernel_statx.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" + +#include +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, lstat, + (const char *__restrict path, + struct stat *__restrict statbuf)) { + return statx(AT_FDCWD, path, AT_SYMLINK_NOFOLLOW, statbuf); +} + +} // namespace __llvm_libc diff --git a/libc/src/sys/stat/linux/stat.cpp b/libc/src/sys/stat/linux/stat.cpp new file mode 100644 index 000000000000..92e661898aa3 --- /dev/null +++ b/libc/src/sys/stat/linux/stat.cpp @@ -0,0 +1,25 @@ +//===-- Linux implementation of stat --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/sys/stat/stat.h" +#include "kernel_statx.h" + +#include "src/__support/common.h" + +#include +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, stat, + (const char *__restrict path, + struct stat *__restrict statbuf)) { + return statx(AT_FDCWD, path, 0, statbuf); +} + +} // namespace __llvm_libc diff --git a/libc/src/sys/stat/lstat.h b/libc/src/sys/stat/lstat.h new file mode 100644 index 000000000000..7d5ffa23eece --- /dev/null +++ b/libc/src/sys/stat/lstat.h @@ -0,0 +1,20 @@ +//===-- Implementation header for lstat -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_STAT_LSTAT_H +#define LLVM_LIBC_SRC_SYS_STAT_LSTAT_H + +#include + +namespace __llvm_libc { + +int lstat(const char *__restrict path, struct stat *__restrict statbuf); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SYS_STAT_LSTAT_H diff --git a/libc/src/sys/stat/stat.h b/libc/src/sys/stat/stat.h new file mode 100644 index 000000000000..a272aa422439 --- /dev/null +++ b/libc/src/sys/stat/stat.h @@ -0,0 +1,20 @@ +//===-- Implementation header for stat --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_STAT_STAT_H +#define LLVM_LIBC_SRC_SYS_STAT_STAT_H + +#include + +namespace __llvm_libc { + +int stat(const char *__restrict path, struct stat *__restrict statbuf); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SYS_STAT_STAT_H diff --git a/libc/test/src/sys/stat/CMakeLists.txt b/libc/test/src/sys/stat/CMakeLists.txt index 12df99bd255f..ef2027dc2916 100644 --- a/libc/test/src/sys/stat/CMakeLists.txt +++ b/libc/test/src/sys/stat/CMakeLists.txt @@ -63,3 +63,51 @@ add_libc_unittest( libc.src.sys.stat.mkdirat libc.src.unistd.rmdir ) + +add_libc_unittest( + stat_test + SUITE + libc_sys_stat_unittests + SRCS + stat_test.cpp + DEPENDS + libc.include.errno + libc.include.fcntl + libc.include.sys_stat + libc.src.sys.stat.stat + libc.src.fcntl.open + libc.src.unistd.close + libc.src.unistd.unlink +) + +add_libc_unittest( + lstat_test + SUITE + libc_sys_stat_unittests + SRCS + lstat_test.cpp + DEPENDS + libc.include.errno + libc.include.fcntl + libc.include.sys_stat + libc.src.sys.stat.lstat + libc.src.fcntl.open + libc.src.unistd.close + libc.src.unistd.unlink +) + +add_libc_unittest( + fstat_test + SUITE + libc_sys_stat_unittests + SRCS + fstat_test.cpp + DEPENDS + libc.include.errno + libc.include.fcntl + libc.include.sys_stat + libc.src.sys.stat.fstat + libc.src.fcntl.open + libc.src.unistd.close + libc.src.unistd.unlink +) diff --git a/libc/test/src/sys/stat/fstat_test.cpp b/libc/test/src/sys/stat/fstat_test.cpp new file mode 100644 index 000000000000..d05f31d35aa2 --- /dev/null +++ b/libc/test/src/sys/stat/fstat_test.cpp @@ -0,0 +1,51 @@ +//===-- Unittests for fstat -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/fcntl/open.h" +#include "src/sys/stat/fstat.h" +#include "src/unistd/close.h" +#include "src/unistd/unlink.h" +#include "test/ErrnoSetterMatcher.h" +#include "utils/UnitTest/Test.h" +#include "utils/testutils/FDReader.h" + +#include +#include +#include + +TEST(LlvmLibcFStatTest, CreatAndReadMode) { + using __llvm_libc::testing::ErrnoSetterMatcher::Fails; + using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; + + // The test file is initially writable. We open it for writing and ensure + // that it indeed can be opened for writing. Next, we close the file and + // make it readonly using chmod. We test that chmod actually succeeded by + // trying to open the file for writing and failing. + constexpr const char *TEST_FILE = "testdata/fstat.test"; + errno = 0; + + int fd = __llvm_libc::open(TEST_FILE, O_CREAT | O_WRONLY, S_IRWXU); + ASSERT_GT(fd, 0); + ASSERT_EQ(errno, 0); + + struct stat statbuf; + ASSERT_THAT(__llvm_libc::fstat(fd, &statbuf), Succeeds(0)); + + ASSERT_EQ(int(statbuf.st_mode), int(S_IRWXU | S_IFREG)); + + ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0)); + ASSERT_THAT(__llvm_libc::unlink(TEST_FILE), Succeeds(0)); +} + +TEST(LlvmLibcFStatTest, NonExistentFile) { + errno = 0; + using __llvm_libc::testing::ErrnoSetterMatcher::Fails; + struct stat statbuf; + ASSERT_THAT(__llvm_libc::fstat(-1, &statbuf), Fails(EBADF)); + errno = 0; +} diff --git a/libc/test/src/sys/stat/lstat_test.cpp b/libc/test/src/sys/stat/lstat_test.cpp new file mode 100644 index 000000000000..e2eda0156af4 --- /dev/null +++ b/libc/test/src/sys/stat/lstat_test.cpp @@ -0,0 +1,51 @@ +//===-- Unittests for lstat -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/fcntl/open.h" +#include "src/sys/stat/lstat.h" +#include "src/unistd/close.h" +#include "src/unistd/unlink.h" +#include "test/ErrnoSetterMatcher.h" +#include "utils/UnitTest/Test.h" +#include "utils/testutils/FDReader.h" + +#include +#include +#include + +TEST(LlvmLibcLStatTest, CreatAndReadMode) { + using __llvm_libc::testing::ErrnoSetterMatcher::Fails; + using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; + + // The test file is initially writable. We open it for writing and ensure + // that it indeed can be opened for writing. Next, we close the file and + // make it readonly using chmod. We test that chmod actually succeeded by + // trying to open the file for writing and failing. + constexpr const char *TEST_FILE = "testdata/lstat.test"; + errno = 0; + + int fd = __llvm_libc::open(TEST_FILE, O_CREAT | O_WRONLY, S_IRWXU); + ASSERT_GT(fd, 0); + ASSERT_EQ(errno, 0); + ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0)); + + struct stat statbuf; + ASSERT_THAT(__llvm_libc::lstat(TEST_FILE, &statbuf), Succeeds(0)); + + ASSERT_EQ(int(statbuf.st_mode), int(S_IRWXU | S_IFREG)); + + ASSERT_THAT(__llvm_libc::unlink(TEST_FILE), Succeeds(0)); +} + +TEST(LlvmLibcLStatTest, NonExistentFile) { + errno = 0; + using __llvm_libc::testing::ErrnoSetterMatcher::Fails; + struct stat statbuf; + ASSERT_THAT(__llvm_libc::lstat("non-existent-file", &statbuf), Fails(ENOENT)); + errno = 0; +} diff --git a/libc/test/src/sys/stat/stat_test.cpp b/libc/test/src/sys/stat/stat_test.cpp new file mode 100644 index 000000000000..4e85a4a97ba9 --- /dev/null +++ b/libc/test/src/sys/stat/stat_test.cpp @@ -0,0 +1,51 @@ +//===-- Unittests for stat ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/fcntl/open.h" +#include "src/sys/stat/stat.h" +#include "src/unistd/close.h" +#include "src/unistd/unlink.h" +#include "test/ErrnoSetterMatcher.h" +#include "utils/UnitTest/Test.h" +#include "utils/testutils/FDReader.h" + +#include +#include +#include + +TEST(LlvmLibcStatTest, CreatAndReadMode) { + using __llvm_libc::testing::ErrnoSetterMatcher::Fails; + using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; + + // The test file is initially writable. We open it for writing and ensure + // that it indeed can be opened for writing. Next, we close the file and + // make it readonly using chmod. We test that chmod actually succeeded by + // trying to open the file for writing and failing. + constexpr const char *TEST_FILE = "testdata/stat.test"; + errno = 0; + + int fd = __llvm_libc::open(TEST_FILE, O_CREAT | O_WRONLY, S_IRWXU); + ASSERT_GT(fd, 0); + ASSERT_EQ(errno, 0); + ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0)); + + struct stat statbuf; + ASSERT_THAT(__llvm_libc::stat(TEST_FILE, &statbuf), Succeeds(0)); + + ASSERT_EQ(int(statbuf.st_mode), int(S_IRWXU | S_IFREG)); + + ASSERT_THAT(__llvm_libc::unlink(TEST_FILE), Succeeds(0)); +} + +TEST(LlvmLibcStatTest, NonExistentFile) { + errno = 0; + using __llvm_libc::testing::ErrnoSetterMatcher::Fails; + struct stat statbuf; + ASSERT_THAT(__llvm_libc::stat("non-existent-file", &statbuf), Fails(ENOENT)); + errno = 0; +}