[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