35 changes: 35 additions & 0 deletions libc/src/unistd/linux/unlink.cpp
Original file line number Diff line number Diff line change
@@ -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
33 changes: 33 additions & 0 deletions libc/src/unistd/linux/unlinkat.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 18 additions & 0 deletions libc/src/unistd/rmdir.h
Original file line number Diff line number Diff line change
@@ -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 changes: 18 additions & 0 deletions libc/src/unistd/unlink.h
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions libc/src/unistd/unlinkat.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions libc/test/src/sys/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
add_subdirectory(mman)
add_subdirectory(stat)
17 changes: 17 additions & 0 deletions libc/test/src/sys/stat/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
29 changes: 29 additions & 0 deletions libc/test/src/sys/stat/mkdirat_test.cpp
Original file line number Diff line number Diff line change
@@ -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));
}
2 changes: 2 additions & 0 deletions libc/test/src/sys/stat/testdata/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This directory will be used to create test files and delete them
# from tests.
44 changes: 44 additions & 0 deletions libc/test/src/unistd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
add_libc_testsuite(libc_unistd_unittests)

add_subdirectory(testdata)

add_libc_unittest(
read_write_test
SUITE
Expand All @@ -16,3 +18,45 @@ add_libc_unittest(
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
)
28 changes: 28 additions & 0 deletions libc/test/src/unistd/rmdir_test.cpp
Original file line number Diff line number Diff line change
@@ -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));
}
2 changes: 2 additions & 0 deletions libc/test/src/unistd/testdata/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This directory will be used to create test files and delete them
# from tests.
31 changes: 31 additions & 0 deletions libc/test/src/unistd/unlink_test.cpp
Original file line number Diff line number Diff line change
@@ -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));
}
45 changes: 45 additions & 0 deletions libc/test/src/unistd/unlinkat_test.cpp
Original file line number Diff line number Diff line change
@@ -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));
}