| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| //===--- Linux implementation of the Dir helpers --------------------------===// | ||
| // | ||
| // 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 "dir.h" | ||
|
|
||
| #include "src/__support/OSUtil/syscall.h" // For internal syscall function. | ||
|
|
||
| #include <errno.h> | ||
| #include <fcntl.h> // For open flags | ||
| #include <sys/syscall.h> // For syscall numbers | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| int platform_opendir(const char *name) { | ||
| int open_flags = O_RDONLY | O_DIRECTORY | O_CLOEXEC; | ||
| #ifdef SYS_open | ||
| int fd = __llvm_libc::syscall(SYS_open, name, open_flags); | ||
| #elif defined(SYS_openat) | ||
| int fd = __llvm_libc::syscall(SYS_openat, AT_FDCWD, name, open_flags); | ||
| #else | ||
| #error \ | ||
| "SYS_open and SYS_openat syscalls not available to perform an open operation." | ||
| #endif | ||
|
|
||
| if (fd < 0) { | ||
| errno = -fd; | ||
| return -1; | ||
| } | ||
| return fd; | ||
| } | ||
|
|
||
| size_t platform_fetch_dirents(int fd, cpp::MutableArrayRef<uint8_t> buffer) { | ||
| long size = | ||
| __llvm_libc::syscall(SYS_getdents, fd, buffer.data(), buffer.size()); | ||
| if (size < 0) { | ||
| errno = -size; | ||
| return 0; | ||
| } | ||
| return size; | ||
| } | ||
|
|
||
| bool platform_closedir(int fd) { | ||
| long ret = __llvm_libc::syscall(SYS_close, fd); | ||
| if (ret < 0) { | ||
| errno = -ret; | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| } // namespace __llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| add_entrypoint_object( | ||
| opendir | ||
| SRCS | ||
| opendir.cpp | ||
| HDRS | ||
| opendir.h | ||
| DEPENDS | ||
| libc.include.dirent | ||
| libc.src.__support.File.dir | ||
| libc.src.__support.File.platform_dir | ||
| ) | ||
|
|
||
| add_entrypoint_object( | ||
| dirfd | ||
| SRCS | ||
| dirfd.cpp | ||
| HDRS | ||
| dirfd.h | ||
| DEPENDS | ||
| libc.include.dirent | ||
| libc.src.__support.File.dir | ||
| libc.src.__support.File.platform_dir | ||
| ) | ||
|
|
||
| add_entrypoint_object( | ||
| closedir | ||
| SRCS | ||
| closedir.cpp | ||
| HDRS | ||
| closedir.h | ||
| DEPENDS | ||
| libc.include.dirent | ||
| libc.src.__support.File.dir | ||
| libc.src.__support.File.platform_dir | ||
| ) | ||
|
|
||
| add_entrypoint_object( | ||
| readdir | ||
| SRCS | ||
| readdir.cpp | ||
| HDRS | ||
| readdir.h | ||
| DEPENDS | ||
| libc.include.dirent | ||
| libc.src.__support.File.dir | ||
| libc.src.__support.File.platform_dir | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| //===-- Implementation of closedir ----------------------------------------===// | ||
| // | ||
| // 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 "closedir.h" | ||
|
|
||
| #include "src/__support/File/dir.h" | ||
| #include "src/__support/common.h" | ||
|
|
||
| #include <dirent.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| LLVM_LIBC_FUNCTION(int, closedir, (::DIR * dir)) { | ||
| auto *d = reinterpret_cast<__llvm_libc::Dir *>(dir); | ||
| return d->close(); | ||
| } | ||
|
|
||
| } // namespace __llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //===-- Implementation header of closedir -----------------------*- 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_DIRENT_CLOSEDIR_H | ||
| #define LLVM_LIBC_SRC_DIRENT_CLOSEDIR_H | ||
|
|
||
| #include <dirent.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| int closedir(::DIR *dir); | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_SRC_DIRENT_CLOSEDIR_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| //===-- Implementation of dirfd -------------------------------------------===// | ||
| // | ||
| // 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 "dirfd.h" | ||
|
|
||
| #include "src/__support/File/dir.h" | ||
| #include "src/__support/common.h" | ||
|
|
||
| #include <dirent.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| LLVM_LIBC_FUNCTION(int, dirfd, (::DIR * dir)) { | ||
| auto *d = reinterpret_cast<__llvm_libc::Dir *>(dir); | ||
| return d->getfd(); | ||
| } | ||
|
|
||
| } // namespace __llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //===-- Implementation header of dirfd --------------------------*- 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_DIRENT_DIRFD_H | ||
| #define LLVM_LIBC_SRC_DIRENT_DIRFD_H | ||
|
|
||
| #include <dirent.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| int dirfd(::DIR *dir); | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_SRC_DIRENT_DIRFD_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| //===-- Implementation of opendir -----------------------------------------===// | ||
| // | ||
| // 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 "opendir.h" | ||
|
|
||
| #include "src/__support/File/dir.h" | ||
| #include "src/__support/common.h" | ||
|
|
||
| #include <dirent.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| LLVM_LIBC_FUNCTION(::DIR *, opendir, (const char *name)) { | ||
| return reinterpret_cast<::DIR *>(Dir::open(name)); | ||
| } | ||
|
|
||
| } // namespace __llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //===-- Implementation header of opendir ------------------------*- 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_DIRENT_OPENDIR_H | ||
| #define LLVM_LIBC_SRC_DIRENT_OPENDIR_H | ||
|
|
||
| #include <dirent.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| ::DIR *opendir(const char *name); | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_SRC_DIRENT_OPENDIR_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| //===-- Implementation of readdir -----------------------------------------===// | ||
| // | ||
| // 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 "readdir.h" | ||
|
|
||
| #include "src/__support/File/dir.h" | ||
| #include "src/__support/common.h" | ||
|
|
||
| #include <dirent.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| LLVM_LIBC_FUNCTION(struct ::dirent *, readdir, (::DIR * dir)) { | ||
| auto *d = reinterpret_cast<__llvm_libc::Dir *>(dir); | ||
| return d->read(); | ||
| } | ||
|
|
||
| } // namespace __llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //===-- Implementation header of readdir ------------------------*- 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_DIRENT_READDIR_H | ||
| #define LLVM_LIBC_SRC_DIRENT_READDIR_H | ||
|
|
||
| #include <dirent.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| struct ::dirent *readdir(DIR *dir); | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_SRC_DIRENT_READDIR_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| add_subdirectory(testdata) | ||
| add_libc_testsuite(libc_dirent_unittests) | ||
|
|
||
| add_libc_unittest( | ||
| dirent_test | ||
| SUITE | ||
| libc_dirent_unittests | ||
| SRCS | ||
| dirent_test.cpp | ||
| DEPENDS | ||
| libc.include.dirent | ||
| libc.src.__support.CPP.string_view | ||
| libc.src.dirent.closedir | ||
| libc.src.dirent.dirfd | ||
| libc.src.dirent.opendir | ||
| libc.src.dirent.readdir | ||
| ) | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| //===-- Unittests for functions from POSIX dirent.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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/__support/CPP/StringView.h" | ||
| #include "src/dirent/closedir.h" | ||
| #include "src/dirent/dirfd.h" | ||
| #include "src/dirent/opendir.h" | ||
| #include "src/dirent/readdir.h" | ||
|
|
||
| #include "utils/UnitTest/Test.h" | ||
|
|
||
| #include <dirent.h> | ||
| #include <errno.h> | ||
|
|
||
| using StringView = __llvm_libc::cpp::StringView; | ||
|
|
||
| TEST(LlvmLibcDirentTest, SimpleOpenAndRead) { | ||
| ::DIR *dir = __llvm_libc::opendir("testdata"); | ||
| ASSERT_TRUE(dir != nullptr); | ||
| // The file descriptors 0, 1 and 2 are reserved for standard streams. | ||
| // So, the file descriptor for the newly opened directory should be | ||
| // greater than 2. | ||
| ASSERT_GT(__llvm_libc::dirfd(dir), 2); | ||
|
|
||
| struct ::dirent *file1, *file2, *dir1, *dir2; | ||
| while (true) { | ||
| struct ::dirent *d = __llvm_libc::readdir(dir); | ||
| if (d == nullptr) | ||
| break; | ||
| if (StringView(d->d_name).equals("file1.txt")) | ||
| file1 = d; | ||
| if (StringView(d->d_name).equals("file2.txt")) | ||
| file2 = d; | ||
| if (StringView(d->d_name).equals("dir1")) | ||
| dir1 = d; | ||
| if (StringView(d->d_name).equals("dir2.txt")) | ||
| dir2 = d; | ||
| } | ||
|
|
||
| // Verify that we don't break out of the above loop in error. | ||
| ASSERT_EQ(errno, 0); | ||
|
|
||
| ASSERT_TRUE(file1 != nullptr); | ||
| ASSERT_TRUE(file2 != nullptr); | ||
| ASSERT_TRUE(dir1 != nullptr); | ||
| ASSERT_TRUE(dir2 != nullptr); | ||
|
|
||
| ASSERT_EQ(__llvm_libc::closedir(dir), 0); | ||
| } | ||
|
|
||
| TEST(LlvmLibcDirentTest, OpenNonExistentDir) { | ||
| errno = 0; | ||
| ::DIR *dir = __llvm_libc::opendir("___xyz123__.non_existent__"); | ||
| ASSERT_TRUE(dir == nullptr); | ||
| ASSERT_EQ(errno, ENOENT); | ||
| errno = 0; | ||
| } | ||
|
|
||
| TEST(LlvmLibcDirentTest, OpenFile) { | ||
| errno = 0; | ||
| ::DIR *dir = __llvm_libc::opendir("testdata/file1.txt"); | ||
| ASSERT_TRUE(dir == nullptr); | ||
| ASSERT_EQ(errno, ENOTDIR); | ||
| errno = 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/file1.txt) | ||
| file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/file2.txt) | ||
| file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dir1) | ||
| file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dir2) |