Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc] add statvfs/fstatvfs #86169

Merged
merged 10 commits into from
Mar 25, 2024
Merged

Conversation

SchrodingerZhu
Copy link
Contributor

@SchrodingerZhu SchrodingerZhu commented Mar 21, 2024

fixes #86449

@llvmbot llvmbot added the libc label Mar 21, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Mar 21, 2024

@llvm/pr-subscribers-libc

Author: Schrodinger ZHU Yifan (SchrodingerZhu)

Changes

Patch is 21.07 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/86169.diff

22 Files Affected:

  • (modified) libc/config/linux/api.td (+4)
  • (modified) libc/config/linux/x86_64/entrypoints.txt (+4)
  • (modified) libc/include/CMakeLists.txt (+9)
  • (modified) libc/include/llvm-libc-types/CMakeLists.txt (+10)
  • (added) libc/include/llvm-libc-types/fsblkcnt_t.h (+14)
  • (added) libc/include/llvm-libc-types/fsfilcnt_t.h (+14)
  • (added) libc/include/llvm-libc-types/struct_statvfs.h (+26)
  • (added) libc/include/sys/statvfs.h.def (+16)
  • (modified) libc/spec/posix.td (+30)
  • (modified) libc/src/sys/CMakeLists.txt (+1)
  • (added) libc/src/sys/statvfs/CMakeLists.txt (+17)
  • (added) libc/src/sys/statvfs/fstatvfs.h (+20)
  • (added) libc/src/sys/statvfs/linux/CMakeLists.txt (+34)
  • (added) libc/src/sys/statvfs/linux/fstatvfs.cpp (+24)
  • (added) libc/src/sys/statvfs/linux/statfs_utils.h (+80)
  • (added) libc/src/sys/statvfs/linux/statvfs.cpp (+26)
  • (added) libc/src/sys/statvfs/statvfs.h (+20)
  • (modified) libc/test/src/sys/CMakeLists.txt (+1)
  • (added) libc/test/src/sys/statvfs/CMakeLists.txt (+3)
  • (added) libc/test/src/sys/statvfs/linux/CMakeLists.txt (+30)
  • (added) libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp (+47)
  • (added) libc/test/src/sys/statvfs/linux/statvfs_test.cpp (+51)
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index e9e82c5d478945..f4d4164d4d1986 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -262,3 +262,7 @@ def SetJmpAPI : PublicAPI<"setjmp.h"> {
 def SearchAPI : PublicAPI<"search.h"> {
   let Types = ["ACTION", "ENTRY", "struct hsearch_data"];
 }
+
+def SysStatvfsAPI : PublicAPI<"sys/statvfs.h"> {
+  let Types = ["struct statvfs"];
+}
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index e8cf11266624a7..482f444677f608 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -253,6 +253,10 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.stat.mkdirat
     libc.src.sys.stat.stat
 
+    # sys/statvfs.h
+    libc.src.sys.statvfs.statvfs
+    libc.src.sys.statvfs.fstatvfs
+
     # sys/utsname.h entrypoints
     libc.src.sys.utsname.uname
 
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index b2cb10459c53e3..4203f0bc901b22 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -498,6 +498,15 @@ add_gen_header(
     .llvm-libc-types.struct_sockaddr_un
 )
 
+add_gen_header(
+  sys_statvfs
+  DEF_FILE sys/statvfs.h.def
+  GEN_HDR sys/statvfs.h
+  DEPENDS
+    .llvm_libc_common_h
+    .llvm-libc-types.struct_statvfs
+)
+
 add_gen_header(
   sys_syscall
   DEF_FILE sys/syscall.h.def
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 7fef976d7b3250..93a79e1477b337 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -106,3 +106,13 @@ add_header(
   DEPENDS
     libc.include.llvm-libc-macros.float_macros
 )
+add_header(fsblkcnt_t HDR fsblkcnt_t.h)
+add_header(fsfilcnt_t HDR fsfilcnt_t.h)
+add_header(
+  struct_statvfs 
+HDR 
+  struct_statvfs.h
+DEPENDS
+  .fsblkcnt_t
+  .fsfilcnt_t
+)
diff --git a/libc/include/llvm-libc-types/fsblkcnt_t.h b/libc/include/llvm-libc-types/fsblkcnt_t.h
new file mode 100644
index 00000000000000..88a53d38cb1b3c
--- /dev/null
+++ b/libc/include/llvm-libc-types/fsblkcnt_t.h
@@ -0,0 +1,14 @@
+//===-- Definition of fsblkcnt_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_FSBLKCNT_T_H
+#define LLVM_LIBC_TYPES_FSBLKCNT_T_H
+
+typedef __SIZE_TYPE__ fsblkcnt_t;
+
+#endif // LLVM_LIBC_TYPES_FSBLKCNT_T_H
diff --git a/libc/include/llvm-libc-types/fsfilcnt_t.h b/libc/include/llvm-libc-types/fsfilcnt_t.h
new file mode 100644
index 00000000000000..c5693591907ab7
--- /dev/null
+++ b/libc/include/llvm-libc-types/fsfilcnt_t.h
@@ -0,0 +1,14 @@
+//===-- Definition of fsfilcnt_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_FSFILCNT_T_H
+#define LLVM_LIBC_TYPES_FSFILCNT_T_H
+
+typedef __SIZE_TYPE__ fsfilcnt_t;
+
+#endif // LLVM_LIBC_TYPES_FSFILCNT_T_H
diff --git a/libc/include/llvm-libc-types/struct_statvfs.h b/libc/include/llvm-libc-types/struct_statvfs.h
new file mode 100644
index 00000000000000..265896e9b3a469
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_statvfs.h
@@ -0,0 +1,26 @@
+//===-- Definition of type struct statvfs ---------------------------------===//
+//
+// 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_STATVFS_H
+#define LLVM_LIBC_TYPES_STRUCT_STATVFS_H
+#include <llvm-libc-types/fsblkcnt_t.h>
+#include <llvm-libc-types/fsfilcnt_t.h>
+struct statvfs {
+  unsigned long f_bsize;   /* Filesystem block size */
+  unsigned long f_frsize;  /* Fragment size */
+  fsblkcnt_t f_blocks;     /* Size of fs in f_frsize units */
+  fsblkcnt_t f_bfree;      /* Number of free blocks */
+  fsblkcnt_t f_bavail;     /* Number of free blocks for unprivileged users */
+  fsfilcnt_t f_files;      /* Number of inodes */
+  fsfilcnt_t f_ffree;      /* Number of free inodes */
+  fsfilcnt_t f_favail;     /* Number of free inodes for unprivileged users */
+  unsigned long f_fsid;    /* Filesystem ID */
+  unsigned long f_flag;    /* Mount flags */
+  unsigned long f_namemax; /* Maximum filename length */
+};
+#endif // LLVM_LIBC_TYPES_STRUCT_STATVFS_H
diff --git a/libc/include/sys/statvfs.h.def b/libc/include/sys/statvfs.h.def
new file mode 100644
index 00000000000000..f23c9a3d5b1f93
--- /dev/null
+++ b/libc/include/sys/statvfs.h.def
@@ -0,0 +1,16 @@
+//===-- POSIX header statvfs.h --------------------------------------------===//
+//
+// 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_SYS_STATVFS_H
+#define LLVM_LIBC_SYS_STATVFS_H
+
+#include <__llvm-libc-common.h>
+
+%%public_api()
+
+#endif // LLVM_LIBC_SYS_STATVFS_H
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 3b793ea90ffd32..8444a449ebe5be 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -86,6 +86,10 @@ def ConstStructSockAddrPtr : ConstType<StructSockAddrPtr>;
 
 def StructSockAddrUn : NamedType<"struct sockaddr_un">;
 
+def StructStatvfs : NamedType<"struct statvfs">;
+def StructStatvfsPtr : PtrType<StructStatvfs>;
+def RestrictedStructStatvfsPtr : RestrictedPtrType<StructStatvfs>;
+
 def POSIX : StandardSpec<"POSIX"> {
   PtrType CharPtr = PtrType<CharType>;
   RestrictedPtrType RestrictedCharPtr = RestrictedPtrType<CharType>;
@@ -888,6 +892,31 @@ def POSIX : StandardSpec<"POSIX"> {
     ]
   >;
 
+  HeaderSpec SysStatvfs = HeaderSpec<
+      "sys/statvfs.h",
+      [], // Macros
+      [StructStatvfs], // Types
+      [], // Enumerations
+      [
+        FunctionSpec<
+          "statvfs",
+          RetValSpec<IntType>,
+          [
+            ArgSpec<ConstRestrictedCharPtr>,
+            ArgSpec<RestrictedStructStatvfsPtr>
+          ]
+        >,
+        FunctionSpec<
+          "fstatvfs",
+          RetValSpec<IntType>,
+          [
+            ArgSpec<IntType>,
+            ArgSpec<StructStatvfsPtr>
+          ]
+        >,
+      ]  // Functions
+    >;
+
   NamedType StructUtsName = NamedType<"struct utsname">;
   PtrType StructUtsNamePtr = PtrType<StructUtsName>;
   HeaderSpec SysUtsName = HeaderSpec<
@@ -1505,6 +1534,7 @@ def POSIX : StandardSpec<"POSIX"> {
     SysSelect,
     SysSocket,
     SysStat,
+    SysStatvfs,
     SysTypes,
     SysUtsName,
     SysWait,
diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt
index 57ea7b4beaca1b..adc666b94202f7 100644
--- a/libc/src/sys/CMakeLists.txt
+++ b/libc/src/sys/CMakeLists.txt
@@ -7,6 +7,7 @@ add_subdirectory(select)
 add_subdirectory(socket)
 add_subdirectory(sendfile)
 add_subdirectory(stat)
+add_subdirectory(statvfs)
 add_subdirectory(utsname)
 add_subdirectory(wait)
 add_subdirectory(prctl)
diff --git a/libc/src/sys/statvfs/CMakeLists.txt b/libc/src/sys/statvfs/CMakeLists.txt
new file mode 100644
index 00000000000000..6a10187a135a5c
--- /dev/null
+++ b/libc/src/sys/statvfs/CMakeLists.txt
@@ -0,0 +1,17 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
+add_entrypoint_object(
+  statvfs
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.statvfs
+)
+
+add_entrypoint_object(
+  fstatvfs
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.fstatvfs
+)
diff --git a/libc/src/sys/statvfs/fstatvfs.h b/libc/src/sys/statvfs/fstatvfs.h
new file mode 100644
index 00000000000000..6ca76a459ae5bc
--- /dev/null
+++ b/libc/src/sys/statvfs/fstatvfs.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for fstatvfs ----------------------*- 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_STATVFS_FSTATVFS_H
+#define LLVM_LIBC_SRC_SYS_STATVFS_FSTATVFS_H
+
+#include "llvm-libc-types/struct_statvfs.h"
+
+namespace LIBC_NAMESPACE {
+
+int fstatvfs(int fd, struct statvfs *buf);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_STATVFS_FSTATVFS_H
diff --git a/libc/src/sys/statvfs/linux/CMakeLists.txt b/libc/src/sys/statvfs/linux/CMakeLists.txt
new file mode 100644
index 00000000000000..c481b07005728a
--- /dev/null
+++ b/libc/src/sys/statvfs/linux/CMakeLists.txt
@@ -0,0 +1,34 @@
+add_header_library(
+  statfs_utils
+  HDRS
+    statfs_utils.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.common
+    libc.src.__support.CPP.optional
+    libc.include.sys.syscall
+)
+
+add_entrypoint_object(
+  statvfs
+  SRCS
+    statvfs.cpp
+  HDRS
+    ../statvfs.h
+  DEPENDS
+    libc.include.llvm-libc-types.struct_statvfs
+    .statfs_utils
+)
+
+add_entrypoint_object(
+  fstatvfs
+  SRCS
+    fstatvfs.cpp
+  HDRS
+    ../fstatvfs.h
+  DEPENDS
+    libc.include.llvm-libc-types.struct_statvfs
+    .statfs_utils
+)
+
diff --git a/libc/src/sys/statvfs/linux/fstatvfs.cpp b/libc/src/sys/statvfs/linux/fstatvfs.cpp
new file mode 100644
index 00000000000000..03543f68f1efe3
--- /dev/null
+++ b/libc/src/sys/statvfs/linux/fstatvfs.cpp
@@ -0,0 +1,24 @@
+//===-- Linux implementation of fstatvfs ----------------------------------===//
+//
+// 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/statvfs/fstatvfs.h"
+#include "src/__support/common.h"
+#include "src/sys/statvfs/linux/statfs_utils.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, fstatvfs, (int fd, struct statvfs *buf)) {
+  using namespace statfs_utils;
+  if (cpp::optional<LinuxStatFs> result = linux_fstatfs(fd)) {
+    *buf = statfs_to_statvfs(*result);
+    return 0;
+  }
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/sys/statvfs/linux/statfs_utils.h b/libc/src/sys/statvfs/linux/statfs_utils.h
new file mode 100644
index 00000000000000..67e026cf8103d9
--- /dev/null
+++ b/libc/src/sys/statvfs/linux/statfs_utils.h
@@ -0,0 +1,80 @@
+//===-- Convert Statfs to Statvfs -------------------------------*- 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_STATVFS_LINUX_STATFS_TO_STATVFS_H
+#define LLVM_LIBC_SRC_SYS_STATVFS_LINUX_STATFS_TO_STATVFS_H
+
+#include "llvm-libc-types/struct_statvfs.h"
+#include "src/__support/CPP/optional.h"
+#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/macros/attributes.h"
+#include "src/errno/libc_errno.h"
+#include <asm/statfs.h>
+#include <sys/syscall.h>
+namespace LIBC_NAMESPACE {
+
+namespace statfs_utils {
+#ifdef SYS_statfs64
+using LinuxStatFs = statfs64;
+#else
+using LinuxStatFs = statfs;
+#endif
+
+LIBC_INLINE cpp::optional<LinuxStatFs> linux_statfs(const char *path) {
+  LinuxStatFs result;
+  // On 32-bit platforms, original statfs cannot handle large file systems.
+  // In such cases, SYS_statfs64 is defined and should be used.
+#ifdef SYS_statfs64
+  int ret = syscall_impl<int>(SYS_statfs64, path, sizeof(result), &result);
+#else
+  int ret = syscall_impl<int>(SYS_statfs, path, &result);
+#endif
+  if (ret < 0) {
+    libc_errno = -ret;
+    return cpp::nullopt;
+  }
+  return result;
+}
+
+LIBC_INLINE cpp::optional<LinuxStatFs> linux_fstatfs(int fd) {
+  LinuxStatFs result;
+  // On 32-bit platforms, original fstatfs cannot handle large file systems.
+  // In such cases, SYS_fstatfs64 is defined and should be used.
+#ifdef SYS_fstatfs64
+  int ret = syscall_impl<int>(SYS_fstatfs64, fd, sizeof(result), &result);
+#else
+  int ret = syscall_impl<int>(SYS_fstatfs, fd, &result);
+#endif
+  if (ret < 0) {
+    libc_errno = -ret;
+    return cpp::nullopt;
+  }
+  return result;
+}
+
+// use struct stat(v)fs to avoid conflicts with the function names.
+LIBC_INLINE struct statvfs statfs_to_statvfs(const LinuxStatFs &in) {
+  struct statvfs out;
+  out.f_bsize = in.f_bsize;
+  out.f_frsize = in.f_frsize;
+  out.f_blocks = in.f_blocks;
+  out.f_bfree = in.f_bfree;
+  out.f_bavail = in.f_bavail;
+  out.f_files = in.f_files;
+  out.f_ffree = in.f_ffree;
+  out.f_favail = in.f_ffree;
+  out.f_fsid = in.f_fsid.val[0] |
+               static_cast<decltype(out.f_fsid)>(in.f_fsid.val[1]) << 32;
+  out.f_flag = in.f_flags;
+  out.f_namemax = in.f_namelen;
+  return out;
+}
+} // namespace statfs_utils
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_STATVFS_LINUX_STATFS_TO_STATVFS_H
diff --git a/libc/src/sys/statvfs/linux/statvfs.cpp b/libc/src/sys/statvfs/linux/statvfs.cpp
new file mode 100644
index 00000000000000..c71065930766f2
--- /dev/null
+++ b/libc/src/sys/statvfs/linux/statvfs.cpp
@@ -0,0 +1,26 @@
+//===-- Linux implementation of statvfs -----------------------------------===//
+//
+// 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/statvfs/statvfs.h"
+#include "src/__support/common.h"
+#include "src/sys/statvfs/linux/statfs_utils.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, statvfs,
+                   (const char *__restrict path,
+                    struct statvfs *__restrict buf)) {
+  using namespace statfs_utils;
+  if (cpp::optional<LinuxStatFs> result = linux_statfs(path)) {
+    *buf = statfs_to_statvfs(*result);
+    return 0;
+  }
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/sys/statvfs/statvfs.h b/libc/src/sys/statvfs/statvfs.h
new file mode 100644
index 00000000000000..792c7ddd0164ec
--- /dev/null
+++ b/libc/src/sys/statvfs/statvfs.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for statvfs -----------------------*- 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_STATVFS_STATVFS_H
+#define LLVM_LIBC_SRC_SYS_STATVFS_STATVFS_H
+
+#include "llvm-libc-types/struct_statvfs.h"
+
+namespace LIBC_NAMESPACE {
+
+int statvfs(const char *__restrict path, struct statvfs *__restrict buf);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_STATVFS_STATVFS_H
diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt
index 7f228e709046d0..dc0aa8bf7b75dc 100644
--- a/libc/test/src/sys/CMakeLists.txt
+++ b/libc/test/src/sys/CMakeLists.txt
@@ -5,6 +5,7 @@ add_subdirectory(select)
 add_subdirectory(sendfile)
 add_subdirectory(socket)
 add_subdirectory(stat)
+add_subdirectory(statvfs)
 add_subdirectory(utsname)
 add_subdirectory(wait)
 add_subdirectory(prctl)
diff --git a/libc/test/src/sys/statvfs/CMakeLists.txt b/libc/test/src/sys/statvfs/CMakeLists.txt
new file mode 100644
index 00000000000000..b4bbe81c92ff2e
--- /dev/null
+++ b/libc/test/src/sys/statvfs/CMakeLists.txt
@@ -0,0 +1,3 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${LIBC_TARGET_OS})
+endif()
diff --git a/libc/test/src/sys/statvfs/linux/CMakeLists.txt b/libc/test/src/sys/statvfs/linux/CMakeLists.txt
new file mode 100644
index 00000000000000..0a695bce968435
--- /dev/null
+++ b/libc/test/src/sys/statvfs/linux/CMakeLists.txt
@@ -0,0 +1,30 @@
+add_custom_target(libc_sys_statvfs_unittests)
+
+add_libc_unittest(
+  statvfs_test
+  SUITE
+    libc_sys_statvfs_unittests
+  SRCS
+    statvfs_test.cpp
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.sys.statvfs.linux.statfs_utils
+    libc.src.sys.statvfs.statvfs
+    libc.test.UnitTest.ErrnoSetterMatcher
+)
+
+add_libc_unittest(
+  fstatvfs_test
+  SUITE
+    libc_sys_statvfs_unittests
+  SRCS
+    fstatvfs_test.cpp
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.sys.statvfs.linux.statfs_utils
+    libc.src.sys.statvfs.fstatvfs
+    libc.src.fcntl.open
+    libc.src.unistd.close
+    libc.src.__support.CPP.string_view
+    libc.test.UnitTest.ErrnoSetterMatcher
+)
diff --git a/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp b/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp
new file mode 100644
index 00000000000000..7a8ca8680978a2
--- /dev/null
+++ b/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp
@@ -0,0 +1,47 @@
+#include "src/__support/CPP/string_view.h"
+#include "src/fcntl/open.h"
+#include "src/sys/statvfs/fstatvfs.h"
+#include "src/sys/statvfs/linux/statfs_utils.h"
+#include "src/unistd/close.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/LibcTest.h"
+#include <linux/magic.h>
+#include <llvm-libc-macros/linux/fcntl-macros.h>
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+
+namespace LIBC_NAMESPACE {
+static int fstatfs(int fd, struct statfs *buf) {
+  using namespace statfs_utils;
+  if (cpp::optional<LinuxStatFs> result = linux_fstatfs(fd)) {
+    *buf = *result;
+    return 0;
+  }
+  return -1;
+}
+} // namespace LIBC_NAMESPACE
+
+struct PathFD {
+  int fd;
+  explicit PathFD(LIBC_NAMESPACE::cpp::string_view path)
+      : fd(LIBC_NAMESPACE::open(path.data(), O_CLOEXEC | O_PATH)) {}
+  ~PathFD() { LIBC_NAMESPACE::close(fd); }
+  operator int() const { return fd; }
+};
+
+TEST(LlvmLibcSysStatfsTest, FstatfsBasic) {
+  statfs buf[1];
+  ASSERT_THAT(LIBC_NAMESPACE::fstatfs(PathFD("/"), buf), Succeeds());
+  ASSERT_THAT(LIBC_NAMESPACE::fstatfs(PathFD("/proc"), buf), Succeeds());
+  ASSERT_EQ(buf->f_type, static_cast<decltype(buf->f_type)>(PROC_SUPER_MAGIC));
+  ASSERT_THAT(LIBC_NAMESPACE::fstatfs(PathFD("/sys"), buf), Succeeds());
+  ASSERT_EQ(buf->f_type, static_cast<decltype(buf->f_type)>(SYSFS_MAGIC));
+}
+
+TEST(LlvmLibcSysStatfsTest, FstatfsNullBuffer) {
+  ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(PathFD("/"), nullptr), Fails(EFAULT));
+}
+
+TEST(LlvmLibcSysStatfsTest, FstatfsInvalidFD) {
+  statvfs buf[1];
+  ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(-1, buf), Fails(EBADF));
+}
diff --git a/libc/test/src/sys/statvfs/linux/statvfs_test.cpp b/libc/test/src/sys/statvfs/linux/statvfs_test.cpp
new file mode 100644
index 00000000000000..116d32ecb09db6
--- /dev/null
+++ b/libc/test/src/sys/statvfs/linux/statvfs_test.cpp
@@ -0,0 +1,51 @@
+#include "src/sys/statvfs/linux/statfs_utils.h"
+#include "src/sys/statvfs/statvfs.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/LibcTest.h"
+#include <linux/magic.h>
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+
+namespace LIBC_NAMESPACE {
+static int statfs(const char *path, struct statfs *buf) {
+  using namespace statfs_utils;
+  if (cpp::optional<LinuxStatFs> result = linux_statfs(path)) {
+    *buf = *result;
+    return 0;
+  }
+  return -1;
+}
+} // namespace LIBC_NAMESPACE
+
+TEST(LlvmLibcSysStatfsTest, StatfsBasic) {
+  statfs buf[1];
+  ASSERT_THAT(LIBC_NAMESPACE::statfs("/", buf), Succeeds());
+  ASSERT_THAT(LIBC_NAMESPACE::statfs("/proc", buf), Succeeds());
+  ASSERT_EQ(buf->f_type, static_...
[truncated]

@SchrodingerZhu SchrodingerZhu changed the title [libc] add statvfs [libc] add statvfs/fstatvfs Mar 21, 2024
libc/include/llvm-libc-types/struct_statvfs.h Outdated Show resolved Hide resolved
Comment on lines 29 to 33
#ifdef __clang__
// Disable pattern filling for result buffer: this struct is to be populated
// by the syscall.
[[clang::uninitialized]]
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to read through linux/fs/statfs.c to verify that the kernel shouldn't return early.

I would like the ensure we don't end up returning uninitialized memory to our caller.

cc @thejh

libc/src/sys/statvfs/linux/statfs_utils.h Show resolved Hide resolved
libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp Outdated Show resolved Hide resolved
libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp Outdated Show resolved Hide resolved
libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp Outdated Show resolved Hide resolved
libc/src/sys/statvfs/linux/fstatvfs.cpp Outdated Show resolved Hide resolved
libc/src/sys/statvfs/linux/statfs_utils.h Show resolved Hide resolved
libc/test/src/sys/statvfs/linux/statvfs_test.cpp Outdated Show resolved Hide resolved
Copy link

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link

✅ With the latest revision this PR passed the Python code formatter.

Copy link
Member

@nickdesaulniers nickdesaulniers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the patch!

@SchrodingerZhu SchrodingerZhu merged commit 05dc5d9 into llvm:main Mar 25, 2024
3 of 4 checks passed
@SchrodingerZhu SchrodingerZhu deleted the libc/posix-statvfs branch March 25, 2024 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

statvfs/fstatvfs (POSIX API)
3 participants