[libc] Add <sys/statfs.h> header and entrypoints. (#213108)

Implement `statfs` and `fstatfs` functions on Linux.

We already have `struct statfs` and syscall wrappers defined (to
implement POSIX `<sys/statvfs.h>`). Use them to provide Linux-specific
functions as well.
This commit is contained in:
Alexey Samsonov 2026-07-31 07:29:27 -07:00 committed by GitHub
parent c325d6fcb6
commit fd7993ea2d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 416 additions and 3 deletions

View file

@ -334,7 +334,11 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.stat.stat
libc.src.sys.stat.utimensat
# sys/statvfs.h
# sys/statfs.h entrypoints
libc.src.sys.statfs.fstatfs
libc.src.sys.statfs.statfs
# sys/statvfs.h entrypoints
libc.src.sys.statvfs.fstatvfs
libc.src.sys.statvfs.statvfs

View file

@ -62,6 +62,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.sys_signal
libc.include.sys_socket
libc.include.sys_stat
libc.include.sys_statfs
libc.include.sys_statvfs
libc.include.sys_syscall
libc.include.sys_time

View file

@ -365,7 +365,11 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.stat.stat
libc.src.sys.stat.utimensat
# sys/statvfs.h
# sys/statfs.h entrypoints
libc.src.sys.statfs.fstatfs
libc.src.sys.statfs.statfs
# sys/statvfs.h entrypoints
libc.src.sys.statvfs.fstatvfs
libc.src.sys.statvfs.statvfs

View file

@ -63,6 +63,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.sys_signal
libc.include.sys_socket
libc.include.sys_stat
libc.include.sys_statfs
libc.include.sys_statvfs
libc.include.sys_syscall
libc.include.sys_time

View file

@ -370,7 +370,11 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.stat.stat
libc.src.sys.stat.utimensat
# sys/statvfs.h
# sys/statfs.h entrypoints
libc.src.sys.statfs.fstatfs
libc.src.sys.statfs.statfs
# sys/statvfs.h entrypoints
libc.src.sys.statvfs.fstatvfs
libc.src.sys.statvfs.statvfs

View file

@ -65,6 +65,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.sys_signal
libc.include.sys_socket
libc.include.sys_stat
libc.include.sys_statfs
libc.include.sys_statvfs
libc.include.sys_syscall
libc.include.sys_time

View file

@ -861,6 +861,16 @@ add_header_macro(
.llvm-libc-types.struct_ucred
)
add_header_macro(
sys_statfs
../libc/include/sys/statfs.yaml
sys/statfs.h
DEPENDS
.llvm_libc_common_h
.llvm-libc-macros.sys_statfs_macros
.llvm-libc-types.struct_statfs
)
add_header_macro(
sys_statvfs
../libc/include/sys/statvfs.yaml

View file

@ -267,6 +267,12 @@ add_macro_header(
sys-stat-macros.h
)
add_macro_header(
sys_statfs_macros
HDR
sys-statfs-macros.h
)
add_macro_header(
sys_mman_macros
HDR

View file

@ -100,6 +100,12 @@ add_header(
sys-stat-macros.h
)
add_header(
sys_statfs_macros
HDR
sys-statfs-macros.h
)
add_header(
sys_time_macros
HDR

View file

@ -0,0 +1,21 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Linux specific declarations of macros from sys/statfs.h.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_MACROS_LINUX_SYS_STATFS_MACROS_H
#define LLVM_LIBC_MACROS_LINUX_SYS_STATFS_MACROS_H
// There are numerous possible values for f_type field, defined in
// the Linux kernel header. Include it directly.
#include <linux/magic.h>
#endif // LLVM_LIBC_MACROS_LINUX_SYS_STATFS_MACROS_H

View file

@ -0,0 +1,21 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Macros defined in sys/statfs.h header file.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_MACROS_SYS_STATFS_MACROS_H
#define LLVM_LIBC_MACROS_SYS_STATFS_MACROS_H
#ifdef __linux__
#include "linux/sys-statfs-macros.h"
#endif
#endif // LLVM_LIBC_MACROS_SYS_STATFS_MACROS_H

View file

@ -0,0 +1,19 @@
header: sys/statfs.h
standards:
- linux
macros:
- macro_name: ADFS_SUPER_MAGIC
macro_header: sys-statfs-macros.h
types:
- type_name: struct_statfs
functions:
- name: fstatfs
return_type: int
arguments:
- type: int
- type: struct statfs *
- name: statfs
return_type: int
arguments:
- type: const char *
- type: struct statfs *

View file

@ -10,6 +10,7 @@ add_subdirectory(socket)
add_subdirectory(sem)
add_subdirectory(sendfile)
add_subdirectory(stat)
add_subdirectory(statfs)
add_subdirectory(statvfs)
add_subdirectory(time)
add_subdirectory(utsname)

View file

@ -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(
statfs
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.statfs
)
add_entrypoint_object(
fstatfs
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.fstatfs
)

View file

@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Implementation header for fstatfs.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_SYS_STATFS_FSTATFS_H
#define LLVM_LIBC_SRC_SYS_STATFS_FSTATFS_H
#include "hdr/types/struct_statfs.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
int fstatfs(int fd, struct statfs *buf);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_SYS_STATFS_FSTATFS_H

View file

@ -0,0 +1,23 @@
add_entrypoint_object(
statfs
SRCS
statfs.cpp
HDRS
../statfs.h
DEPENDS
libc.src.errno.errno
libc.src.__support.OSUtil.linux.syscall_wrappers.statfs
libc.hdr.types.struct_statfs
)
add_entrypoint_object(
fstatfs
SRCS
fstatfs.cpp
HDRS
../fstatfs.h
DEPENDS
libc.src.errno.errno
libc.src.__support.OSUtil.linux.syscall_wrappers.fstatfs
libc.hdr.types.struct_statfs
)

View file

@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Linux implementation of fstatfs.
///
//===----------------------------------------------------------------------===//
#include "src/sys/statfs/fstatfs.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/fstatfs.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, fstatfs, (int fd, struct statfs *buf)) {
auto error_or_ret = linux_syscalls::fstatfs(fd, buf);
if (!error_or_ret) {
libc_errno = error_or_ret.error();
return -1;
}
return 0;
}
} // namespace LIBC_NAMESPACE_DECL

View file

@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Linux implementation of statfs.
///
//===----------------------------------------------------------------------===//
#include "src/sys/statfs/statfs.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/statfs.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, statfs, (const char *path, struct statfs *buf)) {
auto error_or_ret = linux_syscalls::statfs(path, buf);
if (!error_or_ret) {
libc_errno = error_or_ret.error();
return -1;
}
return 0;
}
} // namespace LIBC_NAMESPACE_DECL

View file

@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Implementation header for statfs.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_SYS_STATFS_STATFS_H
#define LLVM_LIBC_SRC_SYS_STATFS_STATFS_H
#include "hdr/types/struct_statfs.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
int statfs(const char *path, struct statfs *buf);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_SYS_STATFS_STATFS_H

View file

@ -6,6 +6,7 @@ add_subdirectory(select)
add_subdirectory(sendfile)
add_subdirectory(socket)
add_subdirectory(stat)
add_subdirectory(statfs)
add_subdirectory(statvfs)
add_subdirectory(utsname)
add_subdirectory(wait)

View file

@ -0,0 +1,3 @@
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${LIBC_TARGET_OS})
endif()

View file

@ -0,0 +1,35 @@
add_custom_target(libc_sys_statfs_unittests)
add_libc_unittest(
statfs_test
SUITE
libc_sys_statfs_unittests
SRCS
statfs_test.cpp
DEPENDS
libc.hdr.sys_stat_macros
libc.src.errno.errno
libc.src.sys.statfs.statfs
libc.src.sys.stat.mkdirat
libc.src.unistd.rmdir
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
add_libc_unittest(
fstatfs_test
SUITE
libc_sys_statfs_unittests
SRCS
fstatfs_test.cpp
DEPENDS
libc.hdr.sys_stat_macros
libc.src.errno.errno
libc.src.sys.statfs.fstatfs
libc.src.sys.stat.mkdirat
libc.src.unistd.rmdir
libc.src.fcntl.open
libc.src.unistd.close
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)

View file

@ -0,0 +1,65 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Unittests for fstatfs.
///
//===----------------------------------------------------------------------===//
#include "hdr/fcntl_macros.h"
#include "hdr/sys_stat_macros.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/fcntl/open.h"
#include "src/sys/stat/mkdirat.h"
#include "src/sys/statfs/fstatfs.h"
#include "src/unistd/close.h"
#include "src/unistd/rmdir.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
using LlvmLibcSysFStatfsTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
TEST_F(LlvmLibcSysFStatfsTest, FStatfsBasic) {
struct statfs buf;
int fd = LIBC_NAMESPACE::open("/", O_PATH);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);
// The root of the file directory must always exist
ASSERT_THAT(LIBC_NAMESPACE::fstatfs(fd, &buf), Succeeds());
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
}
TEST_F(LlvmLibcSysFStatfsTest, FStatfsInvalidPath) {
struct statfs buf;
constexpr const char *FILENAME = "fstatfs.testdir";
auto TEST_DIR = libc_make_test_file_path(FILENAME);
// Always delete the folder so that we start in a consistent state.
LIBC_NAMESPACE::rmdir(TEST_DIR);
libc_errno = 0; // Reset errno
ASSERT_THAT(LIBC_NAMESPACE::mkdirat(AT_FDCWD, TEST_DIR, S_IRWXU),
Succeeds(0));
int fd = LIBC_NAMESPACE::open(TEST_DIR, O_PATH);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);
ASSERT_THAT(LIBC_NAMESPACE::fstatfs(fd, &buf), Succeeds());
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::rmdir(TEST_DIR), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::fstatfs(fd, &buf), Fails(EBADF));
}

View file

@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Unittests for statfs.
///
//===----------------------------------------------------------------------===//
#include "hdr/fcntl_macros.h"
#include "hdr/sys_stat_macros.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/sys/stat/mkdirat.h"
#include "src/sys/statfs/statfs.h"
#include "src/unistd/rmdir.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
using LlvmLibcSysStatfsTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
TEST_F(LlvmLibcSysStatfsTest, StatfsBasic) {
struct statfs buf;
// The root of the file directory must always exist
ASSERT_THAT(LIBC_NAMESPACE::statfs("/", &buf), Succeeds());
}
TEST_F(LlvmLibcSysStatfsTest, StatfsInvalidPath) {
struct statfs buf;
ASSERT_THAT(LIBC_NAMESPACE::statfs("", &buf), Fails(ENOENT));
// create the file, assert it exists, then delete it and assert it doesn't
// exist anymore.
constexpr const char *FILENAME = "statfs.testdir";
auto TEST_DIR = libc_make_test_file_path(FILENAME);
// Always delete the folder so that we start in a consistent state.
LIBC_NAMESPACE::rmdir(TEST_DIR);
libc_errno = 0; // Reset errno
ASSERT_THAT(LIBC_NAMESPACE::mkdirat(AT_FDCWD, TEST_DIR, S_IRWXU),
Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::statfs(TEST_DIR, &buf), Succeeds());
ASSERT_THAT(LIBC_NAMESPACE::rmdir(TEST_DIR), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::statfs(TEST_DIR, &buf), Fails(ENOENT));
}