[libc] Add linux implementation of POSIX fchmodat function.

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D132533
This commit is contained in:
Siva Chandra Reddy 2022-08-24 18:24:57 +00:00
parent 23245a914b
commit 85dff76416
10 changed files with 167 additions and 2 deletions

View File

@ -103,6 +103,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# sys/stat.h entrypoints # sys/stat.h entrypoints
libc.src.sys.stat.chmod libc.src.sys.stat.chmod
libc.src.sys.stat.fchmod libc.src.sys.stat.fchmod
libc.src.sys.stat.fchmodat
libc.src.sys.stat.mkdir libc.src.sys.stat.mkdir
libc.src.sys.stat.mkdirat libc.src.sys.stat.mkdirat

View File

@ -103,6 +103,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# sys/stat.h entrypoints # sys/stat.h entrypoints
libc.src.sys.stat.chmod libc.src.sys.stat.chmod
libc.src.sys.stat.fchmod libc.src.sys.stat.fchmod
libc.src.sys.stat.fchmodat
libc.src.sys.stat.mkdir libc.src.sys.stat.mkdir
libc.src.sys.stat.mkdirat libc.src.sys.stat.mkdirat

View File

@ -406,12 +406,17 @@ def POSIX : StandardSpec<"POSIX"> {
FunctionSpec< FunctionSpec<
"chmod", "chmod",
RetValSpec<IntType>, RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>] [ArgSpec<ConstCharPtr>, ArgSpec<ModeTType>]
>, >,
FunctionSpec< FunctionSpec<
"fchmod", "fchmod",
RetValSpec<IntType>, RetValSpec<IntType>,
[ArgSpec<IntType>] [ArgSpec<IntType>, ArgSpec<ModeTType>]
>,
FunctionSpec<
"fchmodat",
RetValSpec<IntType>,
[ArgSpec<IntType>, ArgSpec<ConstCharPtr>, ArgSpec<ModeTType>, ArgSpec<IntType>]
>, >,
FunctionSpec< FunctionSpec<
"mkdir", "mkdir",

View File

@ -9,6 +9,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.chmod .${LIBC_TARGET_OS}.chmod
) )
add_entrypoint_object(
fchmodat
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.fchmodat
)
add_entrypoint_object( add_entrypoint_object(
fchmod fchmod
ALIAS ALIAS

View File

@ -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

View File

@ -25,6 +25,19 @@ add_entrypoint_object(
libc.src.errno.errno 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( add_entrypoint_object(
mkdir mkdir
SRCS SRCS

View File

@ -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

View File

@ -18,6 +18,22 @@ add_libc_unittest(
libc.src.unistd.write 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( add_libc_unittest(
fchmod_test fchmod_test
SUITE SUITE

View File

@ -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;
}

View File

@ -1,4 +1,5 @@
# This directory will be used to create test files. # This directory will be used to create test files.
file(GENERATE OUTPUT chmod.test CONTENT "chmod test") file(GENERATE OUTPUT chmod.test CONTENT "chmod test")
file(GENERATE OUTPUT fchmodat.test CONTENT "fchmodat test")
file(GENERATE OUTPUT fchmod.test CONTENT "fchmod test") file(GENERATE OUTPUT fchmod.test CONTENT "fchmod test")