[libc-commits] [libc] [libc] add statvfs (PR #86169)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Thu Mar 21 11:38:24 PDT 2024
https://github.com/SchrodingerZhu created https://github.com/llvm/llvm-project/pull/86169
None
>From 182ef6932ac2261749b8ed3eaebed8a88f91494c Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Wed, 20 Mar 2024 11:48:54 -0400
Subject: [PATCH] [libc] add statvfs
---
libc/config/linux/api.td | 4 +
libc/config/linux/x86_64/entrypoints.txt | 4 +
libc/include/CMakeLists.txt | 9 +++
libc/include/llvm-libc-types/CMakeLists.txt | 10 +++
libc/include/llvm-libc-types/fsblkcnt_t.h | 14 ++++
libc/include/llvm-libc-types/fsfilcnt_t.h | 14 ++++
libc/include/llvm-libc-types/struct_statvfs.h | 26 ++++++
libc/include/sys/statvfs.h.def | 16 ++++
libc/spec/posix.td | 30 +++++++
libc/src/sys/CMakeLists.txt | 1 +
libc/src/sys/statvfs/CMakeLists.txt | 17 ++++
libc/src/sys/statvfs/fstatvfs.h | 20 +++++
libc/src/sys/statvfs/linux/CMakeLists.txt | 34 ++++++++
libc/src/sys/statvfs/linux/fstatvfs.cpp | 24 ++++++
libc/src/sys/statvfs/linux/statfs_utils.h | 80 +++++++++++++++++++
libc/src/sys/statvfs/linux/statvfs.cpp | 26 ++++++
libc/src/sys/statvfs/statvfs.h | 20 +++++
libc/test/src/sys/CMakeLists.txt | 1 +
libc/test/src/sys/statvfs/CMakeLists.txt | 3 +
.../test/src/sys/statvfs/linux/CMakeLists.txt | 30 +++++++
.../src/sys/statvfs/linux/fstatvfs_test.cpp | 47 +++++++++++
.../src/sys/statvfs/linux/statvfs_test.cpp | 51 ++++++++++++
22 files changed, 481 insertions(+)
create mode 100644 libc/include/llvm-libc-types/fsblkcnt_t.h
create mode 100644 libc/include/llvm-libc-types/fsfilcnt_t.h
create mode 100644 libc/include/llvm-libc-types/struct_statvfs.h
create mode 100644 libc/include/sys/statvfs.h.def
create mode 100644 libc/src/sys/statvfs/CMakeLists.txt
create mode 100644 libc/src/sys/statvfs/fstatvfs.h
create mode 100644 libc/src/sys/statvfs/linux/CMakeLists.txt
create mode 100644 libc/src/sys/statvfs/linux/fstatvfs.cpp
create mode 100644 libc/src/sys/statvfs/linux/statfs_utils.h
create mode 100644 libc/src/sys/statvfs/linux/statvfs.cpp
create mode 100644 libc/src/sys/statvfs/statvfs.h
create mode 100644 libc/test/src/sys/statvfs/CMakeLists.txt
create mode 100644 libc/test/src/sys/statvfs/linux/CMakeLists.txt
create mode 100644 libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp
create mode 100644 libc/test/src/sys/statvfs/linux/statvfs_test.cpp
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_cast<__kernel_long_t>(PROC_SUPER_MAGIC));
+ ASSERT_THAT(LIBC_NAMESPACE::statfs("/sys", buf), Succeeds());
+ ASSERT_EQ(buf->f_type, static_cast<__kernel_long_t>(SYSFS_MAGIC));
+}
+
+TEST(LlvmLibcSysStatfsTest, StatfsNullBuffer) {
+ ASSERT_THAT(LIBC_NAMESPACE::statfs("/", nullptr), Fails(EFAULT));
+}
+
+TEST(LlvmLibcSysStatfsTest, InvalidPath) {
+ statvfs buf[1];
+ ASSERT_THAT(LIBC_NAMESPACE::statvfs("", buf), Fails(ENOENT));
+ ASSERT_THAT(LIBC_NAMESPACE::statvfs("/nonexistent", buf), Fails(ENOENT));
+ ASSERT_THAT(LIBC_NAMESPACE::statvfs("/dev/null/whatever", buf),
+ Fails(ENOTDIR));
+ ASSERT_THAT(LIBC_NAMESPACE::statvfs(nullptr, buf), Fails(EFAULT));
+}
+
+TEST(LlvmLibcSysStatfsTest, NameTooLong) {
+ statvfs buf[1];
+ ASSERT_THAT(LIBC_NAMESPACE::statvfs("/", buf), Succeeds());
+ char *name = static_cast<char *>(__builtin_alloca(buf->f_namemax + 3));
+ name[0] = '/';
+ name[buf->f_namemax + 2] = '\0';
+ for (unsigned i = 1; i < buf->f_namemax + 2; ++i) {
+ name[i] = 'a';
+ }
+ ASSERT_THAT(LIBC_NAMESPACE::statvfs(name, buf), Fails(ENAMETOOLONG));
+}
More information about the libc-commits
mailing list