[libc] Add implementations of POSIX mkdir, mkdirat, rmdir, unlink and unlinkat.

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D118641
This commit is contained in:
Siva Chandra Reddy 2022-01-31 17:32:07 +00:00
parent 96fb7d059d
commit b8385162c2
30 changed files with 645 additions and 1 deletions

View File

@ -242,3 +242,7 @@ def ThreadsAPI : PublicAPI<"threads.h"> {
def UniStdAPI : PublicAPI<"unistd.h"> { def UniStdAPI : PublicAPI<"unistd.h"> {
let Types = ["size_t", "ssize_t"]; let Types = ["size_t", "ssize_t"];
} }
def SysStatAPI : PublicAPI<"sys/stat.h"> {
let Types = ["mode_t"];
}

View File

@ -85,10 +85,17 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.mman.mmap libc.src.sys.mman.mmap
libc.src.sys.mman.munmap libc.src.sys.mman.munmap
# sys/stat.h entrypoints
libc.src.sys.stat.mkdir
libc.src.sys.stat.mkdirat
# unistd.h entrypoints # unistd.h entrypoints
libc.src.unistd.close libc.src.unistd.close
libc.src.unistd.fsync libc.src.unistd.fsync
libc.src.unistd.read libc.src.unistd.read
libc.src.unistd.rmdir
libc.src.unistd.unlink
libc.src.unistd.unlinkat
libc.src.unistd.write libc.src.unistd.write
) )

View File

@ -167,6 +167,15 @@ add_gen_header(
.llvm-libc-types.ssize_t .llvm-libc-types.ssize_t
) )
add_gen_header(
sys_stat
DEF_FILE sys/stat.h.def
GEN_HDR sys/stat.h
DEPENDS
.llvm_libc_common_h
.llvm-libc-types.mode_t
)
add_gen_header( add_gen_header(
sys_syscall sys_syscall
DEF_FILE sys/syscall.h.def DEF_FILE sys/syscall.h.def

View File

@ -53,4 +53,8 @@
// openat is relative to the current directory. // openat is relative to the current directory.
#define AT_FDCWD -100 #define AT_FDCWD -100
// Special flag to the function unlinkat to indicate that it
// has to perform the equivalent of "rmdir" on the path argument.
#define AT_REMOVEDIR 0x200
#endif // __LLVM_LIBC_MACROS_LINUX_FCNTL_MACROS_H #endif // __LLVM_LIBC_MACROS_LINUX_FCNTL_MACROS_H

View File

@ -0,0 +1,16 @@
//===-- POSIX header stat.h -----------------------------------------------===//
//
// 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_SYS_STAT_H
#define LLVM_LIBC_SYS_STAT_H
#include <__llvm-libc-common.h>
%%public_api()
#endif // LLVM_LIBC_SYS_STAT_H

View File

@ -242,6 +242,21 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<SSizeTType>, RetValSpec<SSizeTType>,
[ArgSpec<IntType>, ArgSpec<VoidPtr>, ArgSpec<SizeTType>] [ArgSpec<IntType>, ArgSpec<VoidPtr>, ArgSpec<SizeTType>]
>, >,
FunctionSpec<
"rmdir",
RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>]
>,
FunctionSpec<
"unlink",
RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>]
>,
FunctionSpec<
"unlinkat",
RetValSpec<IntType>,
[ArgSpec<IntType>, ArgSpec<ConstCharPtr>, ArgSpec<IntType>]
>,
FunctionSpec< FunctionSpec<
"write", "write",
RetValSpec<SSizeTType>, RetValSpec<SSizeTType>,
@ -317,12 +332,32 @@ def POSIX : StandardSpec<"POSIX"> {
] ]
>; >;
HeaderSpec SysStat = HeaderSpec<
"sys/stat.h",
[], // Macros
[ModeTType], // Types
[], // Enumerations
[
FunctionSpec<
"mkdir",
RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>, ArgSpec<ModeTType>]
>,
FunctionSpec<
"mkdirat",
RetValSpec<IntType>,
[ArgSpec<IntType>, ArgSpec<ConstCharPtr>, ArgSpec<ModeTType>]
>,
]
>;
let Headers = [ let Headers = [
CType, CType,
Errno, Errno,
FCntl, FCntl,
SysMMan,
Signal, Signal,
SysMMan,
SysStat,
UniStd, UniStd,
String String
]; ];

View File

@ -1 +1,2 @@
add_subdirectory(mman) add_subdirectory(mman)
add_subdirectory(stat)

View File

@ -0,0 +1,17 @@
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()
add_entrypoint_object(
mkdir
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.mkdir
)
add_entrypoint_object(
mkdirat
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.mkdirat
)

View File

@ -0,0 +1,25 @@
add_entrypoint_object(
mkdir
SRCS
mkdir.cpp
HDRS
../mkdir.h
DEPENDS
libc.include.sys_stat
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.__errno_location
)
add_entrypoint_object(
mkdirat
SRCS
mkdirat.cpp
HDRS
../mkdirat.h
DEPENDS
libc.include.sys_stat
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.__errno_location
)

View File

@ -0,0 +1,36 @@
//===-- Linux implementation of mkdir -------------------------------------===//
//
// 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/mkdir.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, mkdir, (const char *path, mode_t mode)) {
#ifdef SYS_mkdir
long ret = __llvm_libc::syscall(SYS_mkdir, path, mode);
#elif defined(SYS_unlinkat)
long ret = __llvm_libc::syscall(SYS_mkdirat, AT_FDCWD, path, mode);
#else
#error "mkdir and mkdirat syscalls not available."
#endif
if (ret < 0) {
errno = -ret;
return -1;
}
return 0;
}
} // namespace __llvm_libc

View File

@ -0,0 +1,34 @@
//===-- Linux implementation of mkdirat -----------------------------------===//
//
// 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/mkdirat.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, mkdirat, (int dfd, const char *path, mode_t mode)) {
#ifdef SYS_unlinkat
long ret = __llvm_libc::syscall(SYS_mkdirat, dfd, path, mode);
#else
#error "mkdirat syscalls not available."
#endif
if (ret < 0) {
errno = -ret;
return -1;
}
return 0;
}
} // namespace __llvm_libc

20
libc/src/sys/stat/mkdir.h Normal file
View File

@ -0,0 +1,20 @@
//===-- Implementation header for mkdir -------------------------*- 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_MKDIR_H
#define LLVM_LIBC_SRC_SYS_STAT_MKDIR_H
#include <sys/stat.h>
namespace __llvm_libc {
int mkdir(const char *path, mode_t mode);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_SYS_STAT_MKDIR_H

View File

@ -0,0 +1,20 @@
//===-- Implementation header for mkdirat -----------------------*- 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_MKDIRAT_H
#define LLVM_LIBC_SRC_SYS_STAT_MKDIRAT_H
#include <sys/stat.h>
namespace __llvm_libc {
int mkdirat(int dfd, const char *path, mode_t mode);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_SYS_STAT_MKDIRAT_H

View File

@ -23,6 +23,27 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.read .${LIBC_TARGET_OS}.read
) )
add_entrypoint_object(
rmdir
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.rmdir
)
add_entrypoint_object(
unlink
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.unlink
)
add_entrypoint_object(
unlinkat
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.unlinkat
)
add_entrypoint_object( add_entrypoint_object(
write write
ALIAS ALIAS

View File

@ -37,6 +37,45 @@ add_entrypoint_object(
libc.src.errno.__errno_location libc.src.errno.__errno_location
) )
add_entrypoint_object(
rmdir
SRCS
rmdir.cpp
HDRS
../rmdir.h
DEPENDS
libc.include.unistd
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.__errno_location
)
add_entrypoint_object(
unlink
SRCS
unlink.cpp
HDRS
../unlink.h
DEPENDS
libc.include.unistd
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.__errno_location
)
add_entrypoint_object(
unlinkat
SRCS
unlinkat.cpp
HDRS
../unlinkat.h
DEPENDS
libc.include.unistd
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.__errno_location
)
add_entrypoint_object( add_entrypoint_object(
write write
SRCS SRCS

View File

@ -0,0 +1,35 @@
//===-- Linux implementation of rmdir -------------------------------------===//
//
// 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/unistd/rmdir.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include <errno.h>
#include <sys/syscall.h> // For syscall numbers.
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(int, rmdir, (const char *path)) {
#ifdef SYS_rmdir
long ret = __llvm_libc::syscall(SYS_rmdir, path);
#elif defined(SYS_unlinkat)
long ret = __llvm_libc::syscall(SYS_unlinkat, AT_FDCWD, path, 0);
#else
#error "rmdir and unlinkat syscalls not available."
#endif
if (ret < 0) {
errno = -ret;
return -1;
}
return 0;
}
} // namespace __llvm_libc

View File

@ -0,0 +1,35 @@
//===-- Linux implementation of unlink ------------------------------------===//
//
// 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/unistd/unlink.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include <errno.h>
#include <sys/syscall.h> // For syscall numbers.
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(int, unlink, (const char *path)) {
#ifdef SYS_unlink
long ret = __llvm_libc::syscall(SYS_unlink, path);
#elif defined(SYS_unlinkat)
long ret = __llvm_libc::syscall(SYS_unlinkat, AT_FDCWD, path, 0);
#else
#error "Unlink syscalls not available."
#endif
if (ret < 0) {
errno = -ret;
return -1;
}
return 0;
}
} // namespace __llvm_libc

View File

@ -0,0 +1,33 @@
//===-- Linux implementation of unlinkat ----------------------------------===//
//
// 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/unistd/unlinkat.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include <errno.h>
#include <sys/syscall.h> // For syscall numbers.
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(int, unlinkat, (int dfd, const char *path, int flags)) {
#ifdef SYS_unlinkat
long ret = __llvm_libc::syscall(SYS_unlinkat, dfd, path, flags);
#else
#error "unlinkat syscall not available."
#endif
if (ret < 0) {
errno = -ret;
return -1;
}
return 0;
}
} // namespace __llvm_libc

18
libc/src/unistd/rmdir.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for rmdir -------------------------*- 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_UNISTD_RMDIR_H
#define LLVM_LIBC_SRC_UNISTD_RMDIR_H
namespace __llvm_libc {
int rmdir(const char *path);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_UNISTD_RMDIR_H

18
libc/src/unistd/unlink.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for unlink ------------------------*- 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_UNISTD_UNLINK_H
#define LLVM_LIBC_SRC_UNISTD_UNLINK_H
namespace __llvm_libc {
int unlink(const char *path);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_UNISTD_UNLINK_H

View File

@ -0,0 +1,18 @@
//===-- Implementation header for unlinkat ----------------------*- 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_UNISTD_UNLINKAT_H
#define LLVM_LIBC_SRC_UNISTD_UNLINKAT_H
namespace __llvm_libc {
int unlinkat(int dfd, const char *path, int flags);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_UNISTD_UNLINKAT_H

View File

@ -1 +1,2 @@
add_subdirectory(mman) add_subdirectory(mman)
add_subdirectory(stat)

View File

@ -0,0 +1,17 @@
add_libc_testsuite(libc_sys_stat_unittests)
add_subdirectory(testdata)
add_libc_unittest(
mkdirat_test
SUITE
libc_sys_stat_unittests
SRCS
mkdirat_test.cpp
DEPENDS
libc.include.errno
libc.include.fcntl
libc.include.sys_stat
libc.src.sys.stat.mkdirat
libc.src.unistd.rmdir
)

View File

@ -0,0 +1,29 @@
//===-- Unittests for mkdirat ---------------------------------------------===//
//
// 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/mkdirat.h"
#include "src/unistd/rmdir.h"
#include "test/ErrnoSetterMatcher.h"
#include "utils/UnitTest/Test.h"
#include "utils/testutils/FDReader.h"
#include <errno.h>
#include <fcntl.h>
TEST(LlvmLibcMkdiratTest, CreateAndRemove) {
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_DIR = "testdata/rmdir.testdir";
ASSERT_THAT(__llvm_libc::mkdirat(AT_FDCWD, TEST_DIR, S_IRWXU), Succeeds(0));
ASSERT_THAT(__llvm_libc::rmdir(TEST_DIR), Succeeds(0));
}
TEST(LlvmLibcMkdiratTest, BadPath) {
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
ASSERT_THAT(__llvm_libc::mkdirat(AT_FDCWD, "non-existent-dir/test", S_IRWXU),
Fails(ENOENT));
}

View File

@ -0,0 +1,2 @@
# This directory will be used to create test files and delete them
# from tests.

View File

@ -1,5 +1,7 @@
add_libc_testsuite(libc_unistd_unittests) add_libc_testsuite(libc_unistd_unittests)
add_subdirectory(testdata)
add_libc_unittest( add_libc_unittest(
read_write_test read_write_test
SUITE SUITE
@ -16,3 +18,45 @@ add_libc_unittest(
libc.src.unistd.write libc.src.unistd.write
libc.test.errno_setter_matcher libc.test.errno_setter_matcher
) )
add_libc_unittest(
rmdir_test
SUITE
libc_unistd_unittests
SRCS
rmdir_test.cpp
DEPENDS
libc.include.errno
libc.include.fcntl
libc.src.sys.stat.mkdir
libc.src.unistd.rmdir
)
add_libc_unittest(
unlink_test
SUITE
libc_unistd_unittests
SRCS
unlink_test.cpp
DEPENDS
libc.include.errno
libc.include.unistd
libc.src.fcntl.open
libc.src.unistd.close
libc.src.unistd.unlink
)
add_libc_unittest(
unlinkat_test
SUITE
libc_unistd_unittests
SRCS
unlinkat_test.cpp
DEPENDS
libc.include.errno
libc.include.unistd
libc.src.fcntl.open
libc.src.fcntl.openat
libc.src.unistd.close
libc.src.unistd.unlinkat
)

View File

@ -0,0 +1,28 @@
//===-- Unittests for rmdir -----------------------------------------------===//
//
// 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/mkdir.h"
#include "src/unistd/rmdir.h"
#include "test/ErrnoSetterMatcher.h"
#include "utils/UnitTest/Test.h"
#include "utils/testutils/FDReader.h"
#include <errno.h>
#include <fcntl.h>
TEST(LlvmLibcRmdirTest, CreateAndRemove) {
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_DIR = "testdata/rmdir.testdir";
ASSERT_THAT(__llvm_libc::mkdir(TEST_DIR, S_IRWXU), Succeeds(0));
ASSERT_THAT(__llvm_libc::rmdir(TEST_DIR), Succeeds(0));
}
TEST(LlvmLibcRmdirTest, RemoveNonExistentDir) {
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
ASSERT_THAT(__llvm_libc::rmdir("testdata/non-existent-dir"), Fails(ENOENT));
}

View File

@ -0,0 +1,2 @@
# This directory will be used to create test files and delete them
# from tests.

View File

@ -0,0 +1,31 @@
//===-- Unittests for unlink ----------------------------------------------===//
//
// 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/unistd/close.h"
#include "src/unistd/unlink.h"
#include "test/ErrnoSetterMatcher.h"
#include "utils/UnitTest/Test.h"
#include "utils/testutils/FDReader.h"
#include <errno.h>
TEST(LlvmLibcUnlinkTest, CreateAndUnlink) {
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_FILE = "testdata/unlink.test";
int write_fd = __llvm_libc::open(TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
ASSERT_EQ(errno, 0);
ASSERT_GT(write_fd, 0);
ASSERT_THAT(__llvm_libc::close(write_fd), Succeeds(0));
ASSERT_THAT(__llvm_libc::unlink(TEST_FILE), Succeeds(0));
}
TEST(LlvmLibcUnlinkTest, UnlinkNonExistentFile) {
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
ASSERT_THAT(__llvm_libc::unlink("testdata/non-existent-file"), Fails(ENOENT));
}

View File

@ -0,0 +1,45 @@
//===-- Unittests for unlinkat --------------------------------------------===//
//
// 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/fcntl/openat.h"
#include "src/unistd/close.h"
#include "src/unistd/unlinkat.h"
#include "test/ErrnoSetterMatcher.h"
#include "utils/UnitTest/Test.h"
#include "utils/testutils/FDReader.h"
#include <errno.h>
TEST(LlvmLibcUnlinkatTest, CreateAndDeleteTest) {
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_DIR = "testdata";
constexpr const char *TEST_FILE = "openat.test";
int dir_fd = __llvm_libc::open(TEST_DIR, O_DIRECTORY);
ASSERT_EQ(errno, 0);
ASSERT_GT(dir_fd, 0);
int write_fd =
__llvm_libc::openat(dir_fd, TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
ASSERT_EQ(errno, 0);
ASSERT_GT(write_fd, 0);
ASSERT_THAT(__llvm_libc::close(write_fd), Succeeds(0));
ASSERT_THAT(__llvm_libc::unlinkat(dir_fd, TEST_FILE, 0), Succeeds(0));
ASSERT_THAT(__llvm_libc::close(dir_fd), Succeeds(0));
}
TEST(LlvmLibcUnlinkatTest, UnlinkatNonExistentFile) {
constexpr const char *TEST_DIR = "testdata";
int dir_fd = __llvm_libc::open(TEST_DIR, O_DIRECTORY);
ASSERT_EQ(errno, 0);
ASSERT_GT(dir_fd, 0);
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
ASSERT_THAT(__llvm_libc::unlinkat(dir_fd, "non-existent-file", 0),
Fails(ENOENT));
ASSERT_THAT(__llvm_libc::close(dir_fd), Succeeds(0));
}