diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -242,3 +242,7 @@ def UniStdAPI : PublicAPI<"unistd.h"> { let Types = ["size_t", "ssize_t"]; } + +def SysStatAPI : PublicAPI<"sys/stat.h"> { + let Types = ["mode_t"]; +} diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -85,10 +85,17 @@ libc.src.sys.mman.mmap libc.src.sys.mman.munmap + # sys/stat.h entrypoints + libc.src.sys.stat.mkdir + libc.src.sys.stat.mkdirat + # unistd.h entrypoints libc.src.unistd.close libc.src.unistd.fsync libc.src.unistd.read + libc.src.unistd.rmdir + libc.src.unistd.unlink + libc.src.unistd.unlinkat libc.src.unistd.write ) diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -167,6 +167,15 @@ .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( sys_syscall DEF_FILE sys/syscall.h.def diff --git a/libc/include/llvm-libc-macros/linux/fcntl-macros.h b/libc/include/llvm-libc-macros/linux/fcntl-macros.h --- a/libc/include/llvm-libc-macros/linux/fcntl-macros.h +++ b/libc/include/llvm-libc-macros/linux/fcntl-macros.h @@ -53,4 +53,8 @@ // openat is relative to the current directory. #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 diff --git a/libc/include/sys/stat.h.def b/libc/include/sys/stat.h.def new file mode 100644 --- /dev/null +++ b/libc/include/sys/stat.h.def @@ -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 diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -242,6 +242,21 @@ RetValSpec, [ArgSpec, ArgSpec, ArgSpec] >, + FunctionSpec< + "rmdir", + RetValSpec, + [ArgSpec] + >, + FunctionSpec< + "unlink", + RetValSpec, + [ArgSpec] + >, + FunctionSpec< + "unlinkat", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec] + >, FunctionSpec< "write", RetValSpec, @@ -317,12 +332,32 @@ ] >; + HeaderSpec SysStat = HeaderSpec< + "sys/stat.h", + [], // Macros + [ModeTType], // Types + [], // Enumerations + [ + FunctionSpec< + "mkdir", + RetValSpec, + [ArgSpec, ArgSpec] + >, + FunctionSpec< + "mkdirat", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec] + >, + ] + >; + let Headers = [ CType, Errno, FCntl, - SysMMan, Signal, + SysMMan, + SysStat, UniStd, String ]; diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt --- a/libc/src/sys/CMakeLists.txt +++ b/libc/src/sys/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(mman) +add_subdirectory(stat) diff --git a/libc/src/sys/stat/CMakeLists.txt b/libc/src/sys/stat/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/src/sys/stat/CMakeLists.txt @@ -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 +) diff --git a/libc/src/sys/stat/linux/CMakeLists.txt b/libc/src/sys/stat/linux/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/src/sys/stat/linux/CMakeLists.txt @@ -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 +) diff --git a/libc/src/sys/stat/linux/mkdir.cpp b/libc/src/sys/stat/linux/mkdir.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sys/stat/linux/mkdir.cpp @@ -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 +#include +#include // 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 diff --git a/libc/src/sys/stat/linux/mkdirat.cpp b/libc/src/sys/stat/linux/mkdirat.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sys/stat/linux/mkdirat.cpp @@ -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 +#include +#include // 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 diff --git a/libc/src/sys/stat/mkdir.h b/libc/src/sys/stat/mkdir.h new file mode 100644 --- /dev/null +++ b/libc/src/sys/stat/mkdir.h @@ -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 + +namespace __llvm_libc { + +int mkdir(const char *path, mode_t mode); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SYS_STAT_MKDIR_H diff --git a/libc/src/sys/stat/mkdirat.h b/libc/src/sys/stat/mkdirat.h new file mode 100644 --- /dev/null +++ b/libc/src/sys/stat/mkdirat.h @@ -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 + +namespace __llvm_libc { + +int mkdirat(int dfd, const char *path, mode_t mode); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SYS_STAT_MKDIRAT_H diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt --- a/libc/src/unistd/CMakeLists.txt +++ b/libc/src/unistd/CMakeLists.txt @@ -23,6 +23,27 @@ .${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( write ALIAS diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt --- a/libc/src/unistd/linux/CMakeLists.txt +++ b/libc/src/unistd/linux/CMakeLists.txt @@ -37,6 +37,45 @@ 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( write SRCS diff --git a/libc/src/unistd/linux/rmdir.cpp b/libc/src/unistd/linux/rmdir.cpp new file mode 100644 --- /dev/null +++ b/libc/src/unistd/linux/rmdir.cpp @@ -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 +#include // 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 diff --git a/libc/src/unistd/linux/unlink.cpp b/libc/src/unistd/linux/unlink.cpp new file mode 100644 --- /dev/null +++ b/libc/src/unistd/linux/unlink.cpp @@ -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 +#include // 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 diff --git a/libc/src/unistd/linux/unlinkat.cpp b/libc/src/unistd/linux/unlinkat.cpp new file mode 100644 --- /dev/null +++ b/libc/src/unistd/linux/unlinkat.cpp @@ -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 +#include // 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 diff --git a/libc/src/unistd/rmdir.h b/libc/src/unistd/rmdir.h new file mode 100644 --- /dev/null +++ b/libc/src/unistd/rmdir.h @@ -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 diff --git a/libc/src/unistd/unlink.h b/libc/src/unistd/unlink.h new file mode 100644 --- /dev/null +++ b/libc/src/unistd/unlink.h @@ -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 diff --git a/libc/src/unistd/unlinkat.h b/libc/src/unistd/unlinkat.h new file mode 100644 --- /dev/null +++ b/libc/src/unistd/unlinkat.h @@ -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 diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt --- a/libc/test/src/sys/CMakeLists.txt +++ b/libc/test/src/sys/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(mman) +add_subdirectory(stat) diff --git a/libc/test/src/sys/stat/CMakeLists.txt b/libc/test/src/sys/stat/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/test/src/sys/stat/CMakeLists.txt @@ -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 +) diff --git a/libc/test/src/sys/stat/mkdirat_test.cpp b/libc/test/src/sys/stat/mkdirat_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/sys/stat/mkdirat_test.cpp @@ -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 +#include + +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)); +} diff --git a/libc/test/src/sys/stat/testdata/CMakeLists.txt b/libc/test/src/sys/stat/testdata/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/test/src/sys/stat/testdata/CMakeLists.txt @@ -0,0 +1,2 @@ +# This directory will be used to create test files and delete them +# from tests. diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt --- a/libc/test/src/unistd/CMakeLists.txt +++ b/libc/test/src/unistd/CMakeLists.txt @@ -1,5 +1,7 @@ add_libc_testsuite(libc_unistd_unittests) +add_subdirectory(testdata) + add_libc_unittest( read_write_test SUITE @@ -16,3 +18,45 @@ libc.src.unistd.write 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 +) diff --git a/libc/test/src/unistd/rmdir_test.cpp b/libc/test/src/unistd/rmdir_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/unistd/rmdir_test.cpp @@ -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 +#include + +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)); +} diff --git a/libc/test/src/unistd/testdata/CMakeLists.txt b/libc/test/src/unistd/testdata/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/test/src/unistd/testdata/CMakeLists.txt @@ -0,0 +1,2 @@ +# This directory will be used to create test files and delete them +# from tests. diff --git a/libc/test/src/unistd/unlink_test.cpp b/libc/test/src/unistd/unlink_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/unistd/unlink_test.cpp @@ -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 + +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)); +} diff --git a/libc/test/src/unistd/unlinkat_test.cpp b/libc/test/src/unistd/unlinkat_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/unistd/unlinkat_test.cpp @@ -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 + +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)); +}