[libc-commits] [libc] [libc] Add support for SYS_fchmodat2 in fchmodat (PR #223997)

Aman Maurya via libc-commits libc-commits at lists.llvm.org
Thu Sep 17 01:06:58 PDT 2026


https://github.com/amanmaurya92 updated https://github.com/llvm/llvm-project/pull/223997

>From 175097f9f5f61db71a7993221d93dbf35257dfec Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Wed, 16 Sep 2026 18:11:59 +0530
Subject: [PATCH 1/5] [libc] Add support for SYS_fchmodat2 in fchmodat

Diagnosed using Antigravity.

Fixes #223953
---
 .../linux/syscall_wrappers/CMakeLists.txt     |  5 ++-
 .../OSUtil/linux/syscall_wrappers/fchmodat.h  | 19 +++++++-
 libc/src/sys/stat/linux/CMakeLists.txt        |  1 -
 libc/src/sys/stat/linux/fchmodat.cpp          |  7 +--
 libc/test/src/sys/stat/fchmodat_test.cpp      | 45 ++++++++++++++++---
 5 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 17665f87dfcd84..8455b5f4050064 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -649,12 +649,13 @@ add_header_library(
   HDRS
     fchmodat.h
   DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.types.mode_t
+    libc.include.sys_syscall
     libc.src.__support.OSUtil.osutil
     libc.src.__support.common
     libc.src.__support.error_or
     libc.src.__support.macros.config
-    libc.hdr.types.mode_t
-    libc.include.sys_syscall
 )
 
 add_header_library(
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
index b62a040e9fe54f..558f097687a272 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCHMODAT_H
 #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCHMODAT_H
 
+#include "hdr/errno_macros.h"
 #include "hdr/types/mode_t.h"
 #include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
 #include "src/__support/common.h"
@@ -24,8 +25,24 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace linux_syscalls {
 
-LIBC_INLINE ErrorOr<int> fchmodat(int fd, const char *path, mode_t mode) {
+LIBC_INLINE ErrorOr<int> fchmodat(int fd, const char *path, mode_t mode,
+                                  int flags) {
+#ifdef SYS_fchmodat2
+  int ret = syscall_impl<int>(SYS_fchmodat2, fd, path, mode, flags);
+#if defined(SYS_fchmodat)
+  if (ret == -ENOSYS) {
+    if (flags != 0)
+      return Error(ENOTSUP);
+    ret = syscall_impl<int>(SYS_fchmodat, fd, path, mode);
+  }
+#endif
+#elif defined(SYS_fchmodat)
+  if (flags != 0)
+    return Error(ENOTSUP);
   int ret = syscall_impl<int>(SYS_fchmodat, fd, path, mode);
+#else
+#error "fchmodat2 and fchmodat syscalls not available."
+#endif
   if (ret < 0)
     return Error(-ret);
   return ret;
diff --git a/libc/src/sys/stat/linux/CMakeLists.txt b/libc/src/sys/stat/linux/CMakeLists.txt
index b35cd11ea8da52..b087fc927459c7 100644
--- a/libc/src/sys/stat/linux/CMakeLists.txt
+++ b/libc/src/sys/stat/linux/CMakeLists.txt
@@ -30,7 +30,6 @@ add_entrypoint_object(
   HDRS
     ../fchmodat.h
   DEPENDS
-    libc.hdr.errno_macros
     libc.hdr.types.mode_t
     libc.src.__support.OSUtil.linux.syscall_wrappers.fchmodat
     libc.src.errno.errno
diff --git a/libc/src/sys/stat/linux/fchmodat.cpp b/libc/src/sys/stat/linux/fchmodat.cpp
index 29bee319ed0add..38e02b5d616176 100644
--- a/libc/src/sys/stat/linux/fchmodat.cpp
+++ b/libc/src/sys/stat/linux/fchmodat.cpp
@@ -8,7 +8,6 @@
 
 #include "src/sys/stat/fchmodat.h"
 
-#include "hdr/errno_macros.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_errno.h"
@@ -18,11 +17,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, fchmodat,
                    (int dirfd, const char *path, mode_t mode, int flags)) {
-  if (flags != 0) {
-    libc_errno = ENOTSUP;
-    return -1;
-  }
-  auto result = linux_syscalls::fchmodat(dirfd, path, mode);
+  auto result = linux_syscalls::fchmodat(dirfd, path, mode, flags);
   if (!result) {
     libc_errno = result.error();
     return -1;
diff --git a/libc/test/src/sys/stat/fchmodat_test.cpp b/libc/test/src/sys/stat/fchmodat_test.cpp
index 868cdb2bc817ac..f068ce131c6cd7 100644
--- a/libc/test/src/sys/stat/fchmodat_test.cpp
+++ b/libc/test/src/sys/stat/fchmodat_test.cpp
@@ -67,11 +67,42 @@ TEST_F(LlvmLibcFchmodatTest, NonExistentFile) {
       Fails(ENOENT));
 }
 
-TEST_F(LlvmLibcFchmodatTest, UnsupportedFlags) {
-  ASSERT_THAT(LIBC_NAMESPACE::fchmodat(AT_FDCWD, "non-existent-file", S_IRUSR,
-                                       AT_SYMLINK_NOFOLLOW),
-              Fails(ENOTSUP));
-  ASSERT_THAT(
-      LIBC_NAMESPACE::fchmodat(AT_FDCWD, "non-existent-file", S_IRUSR, -1),
-      Fails(ENOTSUP));
+TEST_F(LlvmLibcFchmodatTest, Flags) {
+  constexpr const char *TEST_FILE = "testdata/fchmodat_flags.test";
+  int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_WRONLY, S_IRWXU);
+  ASSERT_GT(fd, 0);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+  int ret = LIBC_NAMESPACE::fchmodat(AT_FDCWD, TEST_FILE, S_IRUSR,
+                                     AT_SYMLINK_NOFOLLOW);
+  if (ret == 0) {
+    // SYS_fchmodat2 is supported by the kernel.
+    ASSERT_ERRNO_SUCCESS();
+    ASSERT_THAT(LIBC_NAMESPACE::fchmodat(AT_FDCWD, "non-existent-file", S_IRUSR,
+                                         AT_SYMLINK_NOFOLLOW),
+                Fails(ENOENT));
+    // Test AT_EMPTY_PATH on an open file descriptor.
+    fd = LIBC_NAMESPACE::open(TEST_FILE, O_PATH);
+    ASSERT_GT(fd, 0);
+    ASSERT_ERRNO_SUCCESS();
+    EXPECT_THAT(LIBC_NAMESPACE::fchmodat(fd, "", S_IRWXU, AT_EMPTY_PATH),
+                Succeeds(0));
+    ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+    ASSERT_THAT(LIBC_NAMESPACE::fchmodat(AT_FDCWD, TEST_FILE, S_IRUSR, -1),
+                Fails(EINVAL));
+  } else {
+    // Kernel or compile-time headers do not support fchmodat2; non-zero flags
+    // fail with ENOTSUP.
+    ASSERT_ERRNO_EQ(ENOTSUP);
+    ASSERT_THAT(LIBC_NAMESPACE::fchmodat(AT_FDCWD, "non-existent-file", S_IRUSR,
+                                         AT_SYMLINK_NOFOLLOW),
+                Fails(ENOTSUP));
+    ASSERT_THAT(
+        LIBC_NAMESPACE::fchmodat(AT_FDCWD, TEST_FILE, S_IRUSR, AT_EMPTY_PATH),
+        Fails(ENOTSUP));
+    ASSERT_THAT(LIBC_NAMESPACE::fchmodat(AT_FDCWD, TEST_FILE, S_IRUSR, -1),
+                Fails(ENOTSUP));
+  }
 }

>From 106383244f747fbdb9b9cd48d17dd54cd01d0471 Mon Sep 17 00:00:00 2001
From: Aman Maurya <amanmaurya9209 at gmail.com>
Date: Wed, 16 Sep 2026 20:40:43 +0530
Subject: [PATCH 2/5] Update
 libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h

Co-authored-by: Pavel Labath <pavel at labath.sk>
---
 libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
index 558f097687a272..603aed5487e97c 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
@@ -27,7 +27,7 @@ namespace linux_syscalls {
 
 LIBC_INLINE ErrorOr<int> fchmodat(int fd, const char *path, mode_t mode,
                                   int flags) {
-#ifdef SYS_fchmodat2
+#if defined(SYS_fchmodat2)
   int ret = syscall_impl<int>(SYS_fchmodat2, fd, path, mode, flags);
 #if defined(SYS_fchmodat)
   if (ret == -ENOSYS) {

>From c789df27bce19b084a6de5a632479eb983708f41 Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Wed, 16 Sep 2026 20:53:32 +0530
Subject: [PATCH 3/5] [libc] Use syscall_checked in fchmodat and drop runtime
 ENOSYS fallback

---
 .../OSUtil/linux/syscall_wrappers/fchmodat.h     | 16 +++-------------
 1 file changed, 3 insertions(+), 13 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
index 603aed5487e97c..daeb4c1391b178 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
@@ -16,7 +16,7 @@
 
 #include "hdr/errno_macros.h"
 #include "hdr/types/mode_t.h"
-#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked
 #include "src/__support/common.h"
 #include "src/__support/error_or.h"
 #include "src/__support/macros/config.h"
@@ -28,24 +28,14 @@ namespace linux_syscalls {
 LIBC_INLINE ErrorOr<int> fchmodat(int fd, const char *path, mode_t mode,
                                   int flags) {
 #if defined(SYS_fchmodat2)
-  int ret = syscall_impl<int>(SYS_fchmodat2, fd, path, mode, flags);
-#if defined(SYS_fchmodat)
-  if (ret == -ENOSYS) {
-    if (flags != 0)
-      return Error(ENOTSUP);
-    ret = syscall_impl<int>(SYS_fchmodat, fd, path, mode);
-  }
-#endif
+  return syscall_checked<int>(SYS_fchmodat2, fd, path, mode, flags);
 #elif defined(SYS_fchmodat)
   if (flags != 0)
     return Error(ENOTSUP);
-  int ret = syscall_impl<int>(SYS_fchmodat, fd, path, mode);
+  return syscall_checked<int>(SYS_fchmodat, fd, path, mode);
 #else
 #error "fchmodat2 and fchmodat syscalls not available."
 #endif
-  if (ret < 0)
-    return Error(-ret);
-  return ret;
 }
 
 } // namespace linux_syscalls

>From c9b5287d4fae9f0d52076e1f42b7a508e42bd631 Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Wed, 16 Sep 2026 22:39:41 +0530
Subject: [PATCH 4/5] [libc] Restore runtime ENOSYS fallback for SYS_fchmodat2

---
 .../__support/OSUtil/linux/syscall_wrappers/fchmodat.h | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
index daeb4c1391b178..2af227895d1f0a 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
@@ -28,7 +28,15 @@ namespace linux_syscalls {
 LIBC_INLINE ErrorOr<int> fchmodat(int fd, const char *path, mode_t mode,
                                   int flags) {
 #if defined(SYS_fchmodat2)
-  return syscall_checked<int>(SYS_fchmodat2, fd, path, mode, flags);
+  auto ret = syscall_checked<int>(SYS_fchmodat2, fd, path, mode, flags);
+#if defined(SYS_fchmodat)
+  if (!ret && ret.error() == ENOSYS) {
+    if (flags != 0)
+      return Error(ENOTSUP);
+    return syscall_checked<int>(SYS_fchmodat, fd, path, mode);
+  }
+#endif
+  return ret;
 #elif defined(SYS_fchmodat)
   if (flags != 0)
     return Error(ENOTSUP);

>From 8956af172670ef3e425cf4232c77762c03292d9d Mon Sep 17 00:00:00 2001
From: Aman Maurya <amanmaurya9209 at gmail.com>
Date: Thu, 17 Sep 2026 13:36:45 +0530
Subject: [PATCH 5/5] Update
 libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h

Co-authored-by: Pavel Labath <pavel at labath.sk>
---
 .../OSUtil/linux/syscall_wrappers/fchmodat.h        | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
index 2af227895d1f0a..d294b9c36bdb0a 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
@@ -29,21 +29,12 @@ LIBC_INLINE ErrorOr<int> fchmodat(int fd, const char *path, mode_t mode,
                                   int flags) {
 #if defined(SYS_fchmodat2)
   auto ret = syscall_checked<int>(SYS_fchmodat2, fd, path, mode, flags);
-#if defined(SYS_fchmodat)
-  if (!ret && ret.error() == ENOSYS) {
-    if (flags != 0)
-      return Error(ENOTSUP);
-    return syscall_checked<int>(SYS_fchmodat, fd, path, mode);
-  }
+  if (ret || ret.error() != ENOSYS)
+    return ret;
 #endif
-  return ret;
-#elif defined(SYS_fchmodat)
   if (flags != 0)
     return Error(ENOTSUP);
   return syscall_checked<int>(SYS_fchmodat, fd, path, mode);
-#else
-#error "fchmodat2 and fchmodat syscalls not available."
-#endif
 }
 
 } // namespace linux_syscalls



More information about the libc-commits mailing list