[libc-commits] [libc] 023687b - [libc] Implement mknodat in sys/stat (#225512)
via libc-commits
libc-commits at lists.llvm.org
Wed Sep 23 02:10:28 PDT 2026
Author: Aman Maurya
Date: 2026-09-23T11:10:20+02:00
New Revision: 023687b8531d12a8fa639dfce460839a60ea5d3a
URL: https://github.com/llvm/llvm-project/commit/023687b8531d12a8fa639dfce460839a60ea5d3a
DIFF: https://github.com/llvm/llvm-project/commit/023687b8531d12a8fa639dfce460839a60ea5d3a.diff
LOG: [libc] Implement mknodat in sys/stat (#225512)
Implement the standard POSIX.1-2008 / POSIX.1-2024 function `mknodat` in
`<sys/stat.h>`.
Fixes #225506
Added:
libc/src/sys/stat/linux/mknodat.cpp
libc/src/sys/stat/mknodat.h
libc/test/src/sys/stat/mknodat_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/include/sys/stat.yaml
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/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 6de6c4f83f879..479a70846714f 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -368,6 +368,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.stat.mkdirat
libc.src.sys.stat.mkfifo
libc.src.sys.stat.mkfifoat
+ libc.src.sys.stat.mknodat
libc.src.sys.stat.stat
libc.src.sys.stat.umask
libc.src.sys.stat.utimensat
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index e2297054248e0..c841b28d9e544 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -399,6 +399,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.stat.mkdirat
libc.src.sys.stat.mkfifo
libc.src.sys.stat.mkfifoat
+ libc.src.sys.stat.mknodat
libc.src.sys.stat.stat
libc.src.sys.stat.umask
libc.src.sys.stat.utimensat
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 72aeaab8c0d0b..786a1ea074305 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -404,6 +404,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.stat.mkdirat
libc.src.sys.stat.mkfifo
libc.src.sys.stat.mkfifoat
+ libc.src.sys.stat.mknodat
libc.src.sys.stat.stat
libc.src.sys.stat.umask
libc.src.sys.stat.utimensat
diff --git a/libc/include/sys/stat.yaml b/libc/include/sys/stat.yaml
index 4e4f197a7f19c..217e55f6e97bb 100644
--- a/libc/include/sys/stat.yaml
+++ b/libc/include/sys/stat.yaml
@@ -76,6 +76,13 @@ functions:
- type: int
- type: const char *
- type: mode_t
+ - name: mknodat
+ return_type: int
+ arguments:
+ - type: int
+ - type: const char *
+ - type: mode_t
+ - type: dev_t
- name: stat
return_type: int
arguments:
diff --git a/libc/src/sys/stat/CMakeLists.txt b/libc/src/sys/stat/CMakeLists.txt
index d08db2d9a3e08..7ff6effa56898 100644
--- a/libc/src/sys/stat/CMakeLists.txt
+++ b/libc/src/sys/stat/CMakeLists.txt
@@ -72,6 +72,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.mkfifoat
)
+add_entrypoint_object(
+ mknodat
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.mknodat
+)
+
add_entrypoint_object(
stat
ALIAS
diff --git a/libc/src/sys/stat/linux/CMakeLists.txt b/libc/src/sys/stat/linux/CMakeLists.txt
index 14b200c2ad49a..d763a0008af6a 100644
--- a/libc/src/sys/stat/linux/CMakeLists.txt
+++ b/libc/src/sys/stat/linux/CMakeLists.txt
@@ -88,6 +88,22 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ mknodat
+ SRCS
+ mknodat.cpp
+ HDRS
+ ../mknodat.h
+ DEPENDS
+ libc.hdr.types.dev_t
+ libc.hdr.types.mode_t
+ libc.src.__support.OSUtil.linux.syscall_wrappers.mknodat
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
stat
SRCS
diff --git a/libc/src/sys/stat/linux/mknodat.cpp b/libc/src/sys/stat/linux/mknodat.cpp
new file mode 100644
index 0000000000000..ccbe484e73e1e
--- /dev/null
+++ b/libc/src/sys/stat/linux/mknodat.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 mknodat.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/stat/mknodat.h"
+
+#include "hdr/types/dev_t.h"
+#include "hdr/types/mode_t.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/mknodat.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, mknodat,
+ (int dirfd, const char *path, mode_t mode, dev_t dev)) {
+ auto result = linux_syscalls::mknodat(dirfd, path, mode, dev);
+ if (!result) {
+ libc_errno = result.error();
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/stat/mknodat.h b/libc/src/sys/stat/mknodat.h
new file mode 100644
index 0000000000000..136f8690e3d15
--- /dev/null
+++ b/libc/src/sys/stat/mknodat.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 mknodat.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_STAT_MKNODAT_H
+#define LLVM_LIBC_SRC_SYS_STAT_MKNODAT_H
+
+#include "hdr/types/dev_t.h"
+#include "hdr/types/mode_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_STAT_MKNODAT_H
diff --git a/libc/test/src/sys/stat/CMakeLists.txt b/libc/test/src/sys/stat/CMakeLists.txt
index d5972c1357fee..42b5309d1c345 100644
--- a/libc/test/src/sys/stat/CMakeLists.txt
+++ b/libc/test/src/sys/stat/CMakeLists.txt
@@ -120,6 +120,31 @@ add_libc_test(
libc.test.UnitTest.ErrnoSetterMatcher
)
+add_libc_test(
+ mknodat_test
+ SUITE
+ libc_sys_stat_unittests
+ SRCS
+ mknodat_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.fcntl_macros
+ libc.hdr.sys_stat_macros
+ libc.hdr.types.dev_t
+ libc.hdr.types.mode_t
+ libc.hdr.types.struct_stat
+ libc.src.__support.CPP.scope
+ libc.src.errno.errno
+ libc.src.fcntl.open
+ libc.src.sys.stat.mknodat
+ libc.src.sys.stat.stat
+ libc.src.sys.stat.umask
+ libc.src.unistd.close
+ libc.src.unistd.unlink
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
add_libc_test(
stat_test
SUITE
diff --git a/libc/test/src/sys/stat/mknodat_test.cpp b/libc/test/src/sys/stat/mknodat_test.cpp
new file mode 100644
index 0000000000000..82549cf19cec7
--- /dev/null
+++ b/libc/test/src/sys/stat/mknodat_test.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 mknodat.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/fcntl_macros.h"
+#include "hdr/sys_stat_macros.h"
+#include "hdr/types/dev_t.h"
+#include "hdr/types/mode_t.h"
+#include "hdr/types/struct_stat.h"
+#include "src/__support/CPP/scope.h"
+#include "src/fcntl/open.h"
+#include "src/sys/stat/mknodat.h"
+#include "src/sys/stat/stat.h"
+#include "src/sys/stat/umask.h"
+#include "src/unistd/close.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcMknodatTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcMknodatTest, CreateAndRemoveRegularFileWithAtFdcwd) {
+ auto TEST_FILE = libc_make_test_file_path("mknodat_reg.test");
+ constexpr mode_t FILE_MODE = S_IRUSR | S_IWUSR;
+
+ mode_t old_mask = LIBC_NAMESPACE::umask(0);
+ ASSERT_THAT(
+ LIBC_NAMESPACE::mknodat(AT_FDCWD, TEST_FILE, S_IFREG | FILE_MODE, 0),
+ Succeeds(0));
+ LIBC_NAMESPACE::umask(old_mask);
+
+ LIBC_NAMESPACE::cpp::scope_exit cleanup(
+ [&] { EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0)); });
+
+ struct stat statbuf;
+ ASSERT_THAT(LIBC_NAMESPACE::stat(TEST_FILE, &statbuf), Succeeds(0));
+ ASSERT_TRUE(S_ISREG(statbuf.st_mode));
+ ASSERT_EQ(statbuf.st_mode & 07777, static_cast<mode_t>(FILE_MODE));
+}
+
+TEST_F(LlvmLibcMknodatTest, CreateAndRemoveFifoWithAtFdcwd) {
+ auto TEST_FIFO = libc_make_test_file_path("mknodat_fifo.test");
+ constexpr mode_t FIFO_MODE = S_IRUSR | S_IWUSR;
+
+ mode_t old_mask = LIBC_NAMESPACE::umask(0);
+ ASSERT_THAT(
+ LIBC_NAMESPACE::mknodat(AT_FDCWD, TEST_FIFO, S_IFIFO | FIFO_MODE, 0),
+ Succeeds(0));
+ LIBC_NAMESPACE::umask(old_mask);
+
+ LIBC_NAMESPACE::cpp::scope_exit cleanup(
+ [&] { EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FIFO), Succeeds(0)); });
+
+ struct stat statbuf;
+ ASSERT_THAT(LIBC_NAMESPACE::stat(TEST_FIFO, &statbuf), Succeeds(0));
+ ASSERT_TRUE(S_ISFIFO(statbuf.st_mode));
+ ASSERT_EQ(statbuf.st_mode & 07777, static_cast<mode_t>(FIFO_MODE));
+}
+
+TEST_F(LlvmLibcMknodatTest, CreateAndRemoveWithDirFd) {
+ auto TEST_DIR = libc_make_test_file_path("testdata");
+ constexpr const char *TEST_FILE_BASENAME = "mknodat_dir.test";
+ auto TEST_FILE_PATH = libc_make_test_file_path("testdata/mknodat_dir.test");
+ constexpr mode_t FILE_MODE = S_IRUSR | S_IWUSR;
+
+ int dirfd = LIBC_NAMESPACE::open(TEST_DIR, O_DIRECTORY);
+ ASSERT_GT(dirfd, 0);
+ LIBC_NAMESPACE::cpp::scope_exit cleanup_dir(
+ [&] { EXPECT_THAT(LIBC_NAMESPACE::close(dirfd), Succeeds(0)); });
+
+ mode_t old_mask = LIBC_NAMESPACE::umask(0);
+ ASSERT_THAT(LIBC_NAMESPACE::mknodat(dirfd, TEST_FILE_BASENAME,
+ S_IFREG | FILE_MODE, 0),
+ Succeeds(0));
+ LIBC_NAMESPACE::umask(old_mask);
+
+ LIBC_NAMESPACE::cpp::scope_exit cleanup_file([&] {
+ EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_PATH), Succeeds(0));
+ });
+
+ struct stat statbuf;
+ ASSERT_THAT(LIBC_NAMESPACE::stat(TEST_FILE_PATH, &statbuf), Succeeds(0));
+ ASSERT_TRUE(S_ISREG(statbuf.st_mode));
+ ASSERT_EQ(statbuf.st_mode & 07777, static_cast<mode_t>(FILE_MODE));
+}
+
+TEST_F(LlvmLibcMknodatTest, BadDirFd) {
+ ASSERT_THAT(LIBC_NAMESPACE::mknodat(-1, "some-file", S_IFREG | 0644, 0),
+ Fails(EBADF));
+}
+
+TEST_F(LlvmLibcMknodatTest, NonExistentPath) {
+ auto BAD_PATH = libc_make_test_file_path("non-existent-dir/mknodat.test");
+ ASSERT_THAT(LIBC_NAMESPACE::mknodat(AT_FDCWD, BAD_PATH, S_IFREG | 0644, 0),
+ Fails(ENOENT));
+}
More information about the libc-commits
mailing list