[libc-commits] [libc] e310f8b - [libc] Add implementation of functions stat, fstat and lstat.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Wed Sep 21 11:35:26 PDT 2022


Author: Siva Chandra Reddy
Date: 2022-09-21T18:35:02Z
New Revision: e310f8bddf6ab87459df3f1172e18543c86e23b7

URL: https://github.com/llvm/llvm-project/commit/e310f8bddf6ab87459df3f1172e18543c86e23b7
DIFF: https://github.com/llvm/llvm-project/commit/e310f8bddf6ab87459df3f1172e18543c86e23b7.diff

LOG: [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

Added: 
    libc/include/llvm-libc-types/blkcnt_t.h
    libc/include/llvm-libc-types/blksize_t.h
    libc/include/llvm-libc-types/dev_t.h
    libc/include/llvm-libc-types/gid_t.h
    libc/include/llvm-libc-types/nlink_t.h
    libc/include/llvm-libc-types/struct_stat.h
    libc/include/llvm-libc-types/struct_timespec.h
    libc/include/llvm-libc-types/uid_t.h
    libc/src/sys/stat/fstat.h
    libc/src/sys/stat/linux/fstat.cpp
    libc/src/sys/stat/linux/kernel_statx.h
    libc/src/sys/stat/linux/lstat.cpp
    libc/src/sys/stat/linux/stat.cpp
    libc/src/sys/stat/lstat.h
    libc/src/sys/stat/stat.h
    libc/test/src/sys/stat/fstat_test.cpp
    libc/test/src/sys/stat/lstat_test.cpp
    libc/test/src/sys/stat/stat_test.cpp

Modified: 
    libc/config/linux/api.td
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/CMakeLists.txt
    libc/include/llvm-libc-macros/linux/fcntl-macros.h
    libc/include/llvm-libc-types/CMakeLists.txt
    libc/include/llvm-libc-types/ino_t.h
    libc/include/llvm-libc-types/time_t.h
    libc/spec/posix.td
    libc/src/sys/stat/CMakeLists.txt
    libc/src/sys/stat/linux/CMakeLists.txt
    libc/test/src/sys/stat/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 97eed64c9f3a6..665620e8533be 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 187165a2b8a5e..5d5d73e9c6989 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 04354c7c185f5..30b4af0fd652d 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 92e4568e61a22..cdd1cf22d7b69 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 79d969d634160..432278e41f4c2 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 0000000000000..acd8d3467ec57
--- /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 0000000000000..99ddac56194a8
--- /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 0000000000000..9fbc41a49b898
--- /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 0000000000000..664aee020a4e7
--- /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 3531dd3829e9c..0f5abd96c2b74 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 0000000000000..1826144b3c88c
--- /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 0000000000000..baaef15d99649
--- /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 <llvm-libc-types/blkcnt_t.h>
+#include <llvm-libc-types/blksize_t.h>
+#include <llvm-libc-types/dev_t.h>
+#include <llvm-libc-types/gid_t.h>
+#include <llvm-libc-types/ino_t.h>
+#include <llvm-libc-types/mode_t.h>
+#include <llvm-libc-types/nlink_t.h>
+#include <llvm-libc-types/off_t.h>
+#include <llvm-libc-types/struct_timespec.h>
+#include <llvm-libc-types/uid_t.h>
+
+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 0000000000000..eb6e70bb578a4
--- /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 <llvm-libc-types/time_t.h>
+
+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 13c33b07c2238..d66ee371ccbab 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 0000000000000..ae9fac2a4288c
--- /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 1980b09996ed1..3c5e093b2b1de 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -16,6 +16,18 @@ def PThreadKeyT : NamedType<"pthread_key_t">;
 def PThreadKeyTPtr : PtrType<PThreadKeyT>;
 
 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<StatType>;
+def RestrictedStatTypePtr : RestrictedPtrType<StatType>;
+
 def DIR : NamedType<"DIR">;
 def DIRPtr : PtrType<DIR>;
 def DIRRestrictedPtr : RestrictedPtrType<DIR>;
@@ -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<IntType>,
           [ArgSpec<IntType>, ArgSpec<ConstCharPtr>, ArgSpec<ModeTType>, ArgSpec<IntType>]
         >,
+        FunctionSpec<
+            "fstat",
+            RetValSpec<IntType>,
+            [ArgSpec<IntType>, ArgSpec<StatTypePtr>]
+        >,
+        FunctionSpec<
+            "lstat",
+            RetValSpec<IntType>,
+            [ArgSpec<ConstRestrictedCharPtr>, ArgSpec<RestrictedStatTypePtr>]
+        >,
         FunctionSpec<
             "mkdir",
             RetValSpec<IntType>,
@@ -519,6 +541,11 @@ def POSIX : StandardSpec<"POSIX"> {
             RetValSpec<IntType>,
             [ArgSpec<IntType>, ArgSpec<ConstCharPtr>, ArgSpec<ModeTType>]
         >,
+        FunctionSpec<
+            "stat",
+            RetValSpec<IntType>,
+            [ArgSpec<ConstRestrictedCharPtr>, ArgSpec<RestrictedStatTypePtr>]
+        >,
     ]
   >;
 

diff  --git a/libc/src/sys/stat/CMakeLists.txt b/libc/src/sys/stat/CMakeLists.txt
index 9ffa219b86621..0775f882c6387 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 0000000000000..ec559a6bf225b
--- /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 <sys/stat.h>
+
+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 545758f0ede9e..6c8b1b6a8e599 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 0000000000000..6baf716157ee4
--- /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 <fcntl.h>
+#include <sys/stat.h>
+
+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 0000000000000..3f14f4dca8cc6
--- /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 <errno.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/syscall.h> // 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 <linux/kdev_t.h>
+
+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 0000000000000..816760a8c1452
--- /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 <fcntl.h>
+#include <sys/stat.h>
+
+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 0000000000000..92e661898aa33
--- /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 <fcntl.h>
+#include <sys/stat.h>
+
+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 0000000000000..7d5ffa23eece6
--- /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 <sys/stat.h>
+
+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 0000000000000..a272aa422439f
--- /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 <sys/stat.h>
+
+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 12df99bd255f4..ef2027dc29168 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 0000000000000..d05f31d35aa2e
--- /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 <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+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 0000000000000..e2eda0156af44
--- /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 <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+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 0000000000000..4e85a4a97ba94
--- /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 <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+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;
+}


        


More information about the libc-commits mailing list