[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