[libc-commits] [libc] 85dff76 - [libc] Add linux implementation of POSIX fchmodat function.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Wed Aug 24 11:46:43 PDT 2022


Author: Siva Chandra Reddy
Date: 2022-08-24T18:46:29Z
New Revision: 85dff76416b2247bdf0357f0b40238dcd15043ee

URL: https://github.com/llvm/llvm-project/commit/85dff76416b2247bdf0357f0b40238dcd15043ee
DIFF: https://github.com/llvm/llvm-project/commit/85dff76416b2247bdf0357f0b40238dcd15043ee.diff

LOG: [libc] Add linux implementation of POSIX fchmodat function.

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D132533

Added: 
    libc/src/sys/stat/fchmodat.h
    libc/src/sys/stat/linux/fchmodat.cpp
    libc/test/src/sys/stat/fchmodat_test.cpp

Modified: 
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/spec/posix.td
    libc/src/sys/stat/CMakeLists.txt
    libc/src/sys/stat/linux/CMakeLists.txt
    libc/test/src/sys/stat/CMakeLists.txt
    libc/test/src/sys/stat/testdata/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 684fd0a4906a9..95d6fcb2d986d 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -103,6 +103,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     # sys/stat.h entrypoints
     libc.src.sys.stat.chmod
     libc.src.sys.stat.fchmod
+    libc.src.sys.stat.fchmodat
     libc.src.sys.stat.mkdir
     libc.src.sys.stat.mkdirat
 

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 37529b2b826f8..787f22b12eeac 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -103,6 +103,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     # sys/stat.h entrypoints
     libc.src.sys.stat.chmod
     libc.src.sys.stat.fchmod
+    libc.src.sys.stat.fchmodat
     libc.src.sys.stat.mkdir
     libc.src.sys.stat.mkdirat
 

diff  --git a/libc/spec/posix.td b/libc/spec/posix.td
index 0acbb63f2c678..c4ab8efc4dda1 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -406,12 +406,17 @@ def POSIX : StandardSpec<"POSIX"> {
         FunctionSpec<
           "chmod",
           RetValSpec<IntType>,
-          [ArgSpec<ConstCharPtr>]
+          [ArgSpec<ConstCharPtr>, ArgSpec<ModeTType>]
         >,
         FunctionSpec<
           "fchmod",
           RetValSpec<IntType>,
-          [ArgSpec<IntType>]
+          [ArgSpec<IntType>, ArgSpec<ModeTType>]
+        >,
+        FunctionSpec<
+          "fchmodat",
+          RetValSpec<IntType>,
+          [ArgSpec<IntType>, ArgSpec<ConstCharPtr>, ArgSpec<ModeTType>, ArgSpec<IntType>]
         >,
         FunctionSpec<
             "mkdir",

diff  --git a/libc/src/sys/stat/CMakeLists.txt b/libc/src/sys/stat/CMakeLists.txt
index b6ca26de9d350..9ffa219b86621 100644
--- a/libc/src/sys/stat/CMakeLists.txt
+++ b/libc/src/sys/stat/CMakeLists.txt
@@ -9,6 +9,13 @@ add_entrypoint_object(
     .${LIBC_TARGET_OS}.chmod
 )
 
+add_entrypoint_object(
+  fchmodat
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.fchmodat
+)
+
 add_entrypoint_object(
   fchmod
   ALIAS

diff  --git a/libc/src/sys/stat/fchmodat.h b/libc/src/sys/stat/fchmodat.h
new file mode 100644
index 0000000000000..3ad9af1b185ad
--- /dev/null
+++ b/libc/src/sys/stat/fchmodat.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for fchmodat ----------------------*- 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_STAT_FCHMODAT_H
+#define LLVM_LIBC_SRC_SYS_STAT_FCHMODAT_H
+
+#include <sys/stat.h>
+
+namespace __llvm_libc {
+
+int fchmodat(int dirfd, const char *path, mode_t mode, int flags);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SYS_STAT_FCHMODAT_H

diff  --git a/libc/src/sys/stat/linux/CMakeLists.txt b/libc/src/sys/stat/linux/CMakeLists.txt
index 1c86a8782d09d..545758f0ede9e 100644
--- a/libc/src/sys/stat/linux/CMakeLists.txt
+++ b/libc/src/sys/stat/linux/CMakeLists.txt
@@ -25,6 +25,19 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
+add_entrypoint_object(
+  fchmodat
+  SRCS
+    fchmodat.cpp
+  HDRS
+    ../fchmod.h
+  DEPENDS
+    libc.include.sys_stat
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
+
 add_entrypoint_object(
   mkdir
   SRCS

diff  --git a/libc/src/sys/stat/linux/fchmodat.cpp b/libc/src/sys/stat/linux/fchmodat.cpp
new file mode 100644
index 0000000000000..6c880bda6e404
--- /dev/null
+++ b/libc/src/sys/stat/linux/fchmodat.cpp
@@ -0,0 +1,30 @@
+//===-- Linux implementation of fchmodat ----------------------------------===//
+//
+// 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/stat/fchmodat.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, fchmodat,
+                   (int dirfd, const char *path, mode_t mode, int flags)) {
+  long ret = __llvm_libc::syscall(SYS_fchmodat, dirfd, path, mode, flags);
+  if (ret < 0) {
+    errno = -ret;
+    return -1;
+  }
+  return 0;
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/test/src/sys/stat/CMakeLists.txt b/libc/test/src/sys/stat/CMakeLists.txt
index c67ba395ee783..12df99bd255f4 100644
--- a/libc/test/src/sys/stat/CMakeLists.txt
+++ b/libc/test/src/sys/stat/CMakeLists.txt
@@ -18,6 +18,22 @@ add_libc_unittest(
     libc.src.unistd.write
 )
 
+add_libc_unittest(
+  fchmodat_test
+  SUITE
+    libc_sys_stat_unittests
+  SRCS
+    fchmodat_test.cpp
+  DEPENDS
+    libc.include.errno
+    libc.include.fcntl
+    libc.include.sys_stat
+    libc.src.fcntl.open
+    libc.src.sys.stat.fchmodat
+    libc.src.unistd.close
+    libc.src.unistd.write
+)
+
 add_libc_unittest(
   fchmod_test
   SUITE

diff  --git a/libc/test/src/sys/stat/fchmodat_test.cpp b/libc/test/src/sys/stat/fchmodat_test.cpp
new file mode 100644
index 0000000000000..c9d031a48e794
--- /dev/null
+++ b/libc/test/src/sys/stat/fchmodat_test.cpp
@@ -0,0 +1,71 @@
+//===-- Unittests for fchmodat --------------------------------------------===//
+//
+// 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/fcntl/open.h"
+#include "src/sys/stat/fchmodat.h"
+#include "src/unistd/close.h"
+#include "src/unistd/write.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+#include "utils/testutils/FDReader.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+TEST(LlvmLibcFchmodatTest, ChangeAndOpen) {
+  using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+  using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+
+  // The test file is initially writable. We open it for writing and ensure
+  // that it indeed can be opened for writing. Next, we close the file and
+  // make it readonly using chmod. We test that chmod actually succeeded by
+  // trying to open the file for writing and failing.
+  constexpr const char *TEST_FILE = "testdata/fchmodat.test";
+  constexpr const char *TEST_DIR = "testdata";
+  constexpr const char *TEST_FILE_BASENAME = "fchmodat.test";
+  const char WRITE_DATA[] = "fchmodat test";
+  constexpr ssize_t WRITE_SIZE = ssize_t(sizeof(WRITE_DATA));
+  errno = 0;
+
+  int fd = __llvm_libc::open(TEST_FILE, O_CREAT | O_WRONLY, S_IRWXU);
+  ASSERT_GT(fd, 0);
+  ASSERT_EQ(errno, 0);
+  ASSERT_EQ(__llvm_libc::write(fd, WRITE_DATA, sizeof(WRITE_DATA)), WRITE_SIZE);
+  ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));
+
+  int dirfd = __llvm_libc::open(TEST_DIR, O_DIRECTORY);
+  ASSERT_GT(dirfd, 0);
+  ASSERT_EQ(errno, 0);
+
+  EXPECT_THAT(__llvm_libc::fchmodat(dirfd, TEST_FILE_BASENAME, S_IRUSR, 0),
+              Succeeds(0));
+
+  // Opening for writing should fail.
+  EXPECT_EQ(__llvm_libc::open(TEST_FILE, O_APPEND | O_WRONLY), -1);
+  EXPECT_NE(errno, 0);
+  errno = 0;
+  // But opening for reading should succeed.
+  fd = __llvm_libc::open(TEST_FILE, O_APPEND | O_RDONLY);
+  EXPECT_GT(fd, 0);
+  EXPECT_EQ(errno, 0);
+
+  EXPECT_THAT(__llvm_libc::close(fd), Succeeds(0));
+  EXPECT_THAT(__llvm_libc::fchmodat(dirfd, TEST_FILE_BASENAME, S_IRWXU, 0),
+              Succeeds(0));
+
+  EXPECT_THAT(__llvm_libc::close(dirfd), Succeeds(0));
+}
+
+TEST(LlvmLibcFchmodatTest, NonExistentFile) {
+  errno = 0;
+  using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+  ASSERT_THAT(__llvm_libc::fchmodat(AT_FDCWD, "non-existent-file", S_IRUSR, 0),
+              Fails(ENOENT));
+  errno = 0;
+}

diff  --git a/libc/test/src/sys/stat/testdata/CMakeLists.txt b/libc/test/src/sys/stat/testdata/CMakeLists.txt
index 5a5c5c6754896..5ecdb4b10e83f 100644
--- a/libc/test/src/sys/stat/testdata/CMakeLists.txt
+++ b/libc/test/src/sys/stat/testdata/CMakeLists.txt
@@ -1,4 +1,5 @@
 # This directory will be used to create test files.
 
 file(GENERATE OUTPUT chmod.test CONTENT "chmod test")
+file(GENERATE OUTPUT fchmodat.test CONTENT "fchmodat test")
 file(GENERATE OUTPUT fchmod.test CONTENT "fchmod test")


        


More information about the libc-commits mailing list