[libc] Implement fdopendir (#206590)
The fdopendir function takes a file descriptor opened on a directory, then opens a DIR* on it. Needed for #191075 Assisted-by: Automated tooling, human reviewed.
This commit is contained in:
parent
a4107d67f9
commit
7b9a58e6cf
21 changed files with 440 additions and 19 deletions
|
|
@ -1022,6 +1022,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
|||
libc.src.dirent.dirfd
|
||||
libc.src.dirent.opendir
|
||||
libc.src.dirent.readdir
|
||||
libc.src.dirent.fdopendir
|
||||
|
||||
# arpa/inet.h entrypoints
|
||||
libc.src.arpa.inet.htonl
|
||||
|
|
|
|||
|
|
@ -228,6 +228,13 @@ if(LLVM_LIBC_FULL_BUILD)
|
|||
libc.src.setjmp.setjmp
|
||||
libc.src.setjmp.siglongjmp
|
||||
libc.src.setjmp.sigsetjmp
|
||||
|
||||
# dirent.h entrypoints
|
||||
libc.src.dirent.closedir
|
||||
libc.src.dirent.dirfd
|
||||
libc.src.dirent.opendir
|
||||
libc.src.dirent.readdir
|
||||
libc.src.dirent.fdopendir
|
||||
)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -1155,6 +1155,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
|||
libc.src.dirent.dirfd
|
||||
libc.src.dirent.opendir
|
||||
libc.src.dirent.readdir
|
||||
libc.src.dirent.fdopendir
|
||||
|
||||
# arpa/inet.h entrypoints
|
||||
libc.src.arpa.inet.htonl
|
||||
|
|
|
|||
|
|
@ -1226,6 +1226,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
|||
libc.src.dirent.dirfd
|
||||
libc.src.dirent.opendir
|
||||
libc.src.dirent.readdir
|
||||
libc.src.dirent.fdopendir
|
||||
|
||||
# pthread.h entrypoints
|
||||
libc.src.pthread.pthread_atfork
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ add_proxy_header_library(
|
|||
libc.include.llvm-libc-macros.stdlib_macros
|
||||
)
|
||||
|
||||
add_header_library(dirent_overlay HDRS dirent_overlay.h)
|
||||
add_header_library(stdio_overlay HDRS stdio_overlay.h)
|
||||
|
||||
add_proxy_header_library(
|
||||
|
|
|
|||
23
libc/hdr/dirent_overlay.h
Normal file
23
libc/hdr/dirent_overlay.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Overlay header for dirent.h in overlay build mode.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_HDR_DIRENT_OVERLAY_H
|
||||
#define LLVM_LIBC_HDR_DIRENT_OVERLAY_H
|
||||
|
||||
#ifdef LIBC_FULL_BUILD
|
||||
#error "This header should only be included in overlay mode"
|
||||
#endif
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#endif // LLVM_LIBC_HDR_DIRENT_OVERLAY_H
|
||||
|
|
@ -87,6 +87,16 @@ add_proxy_header_library(
|
|||
libc.include.llvm-libc-types.siginfo_t
|
||||
)
|
||||
|
||||
add_proxy_header_library(
|
||||
struct_dirent
|
||||
HDRS
|
||||
struct_dirent.h
|
||||
DEPENDS
|
||||
libc.hdr.dirent_overlay
|
||||
FULL_BUILD_DEPENDS
|
||||
libc.include.llvm-libc-types.struct_dirent
|
||||
)
|
||||
|
||||
add_proxy_header_library(
|
||||
struct_epoll_event
|
||||
HDRS
|
||||
|
|
@ -343,6 +353,16 @@ add_proxy_header_library(
|
|||
libc.include.stdio
|
||||
)
|
||||
|
||||
add_proxy_header_library(
|
||||
DIR
|
||||
HDRS
|
||||
DIR.h
|
||||
DEPENDS
|
||||
libc.hdr.dirent_overlay
|
||||
FULL_BUILD_DEPENDS
|
||||
libc.include.llvm-libc-types.DIR
|
||||
)
|
||||
|
||||
add_proxy_header_library(
|
||||
off_t
|
||||
HDRS
|
||||
|
|
|
|||
27
libc/hdr/types/DIR.h
Normal file
27
libc/hdr/types/DIR.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Proxy for DIR.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_HDR_TYPES_DIR_H
|
||||
#define LLVM_LIBC_HDR_TYPES_DIR_H
|
||||
|
||||
#ifdef LIBC_FULL_BUILD
|
||||
|
||||
#include "include/llvm-libc-types/DIR.h"
|
||||
|
||||
#else // Overlay mode
|
||||
|
||||
#include "hdr/dirent_overlay.h"
|
||||
|
||||
#endif // LIBC_FULL_BUILD
|
||||
|
||||
#endif // LLVM_LIBC_HDR_TYPES_DIR_H
|
||||
27
libc/hdr/types/struct_dirent.h
Normal file
27
libc/hdr/types/struct_dirent.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Proxy for struct dirent.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_DIRENT_H
|
||||
#define LLVM_LIBC_HDR_TYPES_STRUCT_DIRENT_H
|
||||
|
||||
#ifdef LIBC_FULL_BUILD
|
||||
|
||||
#include "include/llvm-libc-types/struct_dirent.h"
|
||||
|
||||
#else // Overlay mode
|
||||
|
||||
#include "hdr/dirent_overlay.h"
|
||||
|
||||
#endif // LIBC_FULL_BUILD
|
||||
|
||||
#endif // LLVM_LIBC_HDR_TYPES_STRUCT_DIRENT_H
|
||||
|
|
@ -17,19 +17,23 @@
|
|||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
ErrorOr<Dir *> Dir::open(const char *path) {
|
||||
auto fd = platform_opendir(path);
|
||||
if (!fd)
|
||||
return LIBC_NAMESPACE::Error(fd.error());
|
||||
|
||||
ErrorOr<Dir *> Dir::fdopen(int fd) {
|
||||
LIBC_NAMESPACE::AllocChecker ac;
|
||||
Dir *dir = new (ac) Dir(fd.value());
|
||||
Dir *dir = new (ac) Dir(fd);
|
||||
if (!ac)
|
||||
return LIBC_NAMESPACE::Error(ENOMEM);
|
||||
return dir;
|
||||
}
|
||||
|
||||
ErrorOr<struct ::dirent *> Dir::read() {
|
||||
ErrorOr<Dir *> Dir::open(const char *path) {
|
||||
auto fd = platform_opendir(path);
|
||||
if (!fd)
|
||||
return LIBC_NAMESPACE::Error(fd.error());
|
||||
|
||||
return Dir::fdopen(fd.value());
|
||||
}
|
||||
|
||||
ErrorOr<struct dirent *> Dir::read() {
|
||||
cpp::lock_guard lock(mutex);
|
||||
if (readptr >= fillsize) {
|
||||
auto readsize = platform_fetch_dirents(fd, buffer);
|
||||
|
|
@ -41,7 +45,7 @@ ErrorOr<struct ::dirent *> Dir::read() {
|
|||
if (fillsize == 0)
|
||||
return nullptr;
|
||||
|
||||
struct ::dirent *d = reinterpret_cast<struct ::dirent *>(buffer + readptr);
|
||||
struct dirent *d = reinterpret_cast<struct dirent *>(buffer + readptr);
|
||||
#ifdef __linux__
|
||||
// The d_reclen field is available on Linux but not required by POSIX.
|
||||
readptr += d->d_reclen;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ int platform_closedir(int fd);
|
|||
// failure.
|
||||
ErrorOr<size_t> platform_fetch_dirents(int fd, cpp::span<uint8_t> buffer);
|
||||
|
||||
// Platform specific function which checks if |fd| is a valid file descriptor
|
||||
// open for reading, and refers to a directory. Returns 0 on success, or the
|
||||
// error number on failure.
|
||||
int platform_check_dir(int fd);
|
||||
|
||||
// This class is designed to allow implementation of the POSIX dirent.h API.
|
||||
// By itself, it is platform independent but calls platform specific
|
||||
// functions to perform OS operations.
|
||||
|
|
@ -63,8 +68,9 @@ class Dir {
|
|||
|
||||
public:
|
||||
static ErrorOr<Dir *> open(const char *path);
|
||||
static ErrorOr<Dir *> fdopen(int fd);
|
||||
|
||||
ErrorOr<struct ::dirent *> read();
|
||||
ErrorOr<struct dirent *> read();
|
||||
|
||||
// Returns 0 on success or the error number on failure. If an error number
|
||||
// was returned, then the resources associated with the directory are not
|
||||
|
|
|
|||
|
|
@ -25,10 +25,15 @@ add_object_library(
|
|||
SRCS
|
||||
dir.cpp
|
||||
DEPENDS
|
||||
libc.src.__support.common
|
||||
libc.src.__support.macros.config
|
||||
libc.hdr.fcntl_macros
|
||||
libc.include.sys_syscall
|
||||
libc.hdr.sys_stat_macros
|
||||
libc.src.__support.OSUtil.linux.stat.kernel_statx_types
|
||||
libc.src.__support.OSUtil.osutil
|
||||
libc.src.__support.OSUtil.linux.syscall_wrappers.open
|
||||
libc.src.__support.OSUtil.linux.syscall_wrappers.statx
|
||||
libc.src.__support.OSUtil.linux.syscall_wrappers.fcntl
|
||||
libc.src.__support.error_or
|
||||
libc.src.errno.errno
|
||||
libc.src.__support.File.dir
|
||||
|
|
|
|||
|
|
@ -1,21 +1,27 @@
|
|||
//===--- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Linux implementation of the Dir helpers.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "src/__support/File/dir.h"
|
||||
|
||||
#include "hdr/fcntl_macros.h" // For open flags
|
||||
#include "hdr/sys_stat_macros.h" // For S_ISDIR
|
||||
#include "src/__support/OSUtil/linux/stat/kernel_statx_types.h"
|
||||
#include "src/__support/OSUtil/linux/syscall_wrappers/fcntl.h"
|
||||
#include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
|
||||
#include "src/__support/OSUtil/linux/syscall_wrappers/statx.h"
|
||||
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
|
||||
#include "src/__support/error_or.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
#include "hdr/fcntl_macros.h" // For open flags
|
||||
#include <sys/syscall.h> // For syscall numbers
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
ErrorOr<int> platform_opendir(const char *name) {
|
||||
|
|
@ -30,17 +36,38 @@ ErrorOr<size_t> platform_fetch_dirents(int fd, cpp::span<uint8_t> buffer) {
|
|||
#error "getdents64 syscalls not available to perform a fetch dirents operation."
|
||||
#endif
|
||||
|
||||
if (size < 0) {
|
||||
if (size < 0)
|
||||
return LIBC_NAMESPACE::Error(static_cast<int>(-size));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int platform_closedir(int fd) {
|
||||
int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_close, fd);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
return static_cast<int>(-ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int platform_check_dir(int fd) {
|
||||
// 1. Verify fd is valid and open for reading.
|
||||
auto flags = linux_syscalls::fcntl(fd, F_GETFL);
|
||||
if (!flags)
|
||||
return flags.error();
|
||||
|
||||
// Check if open for reading.
|
||||
if ((flags.value() & O_PATH) || ((flags.value() & O_ACCMODE) == O_WRONLY))
|
||||
return EBADF;
|
||||
|
||||
// 2. Verify fd refers to a directory.
|
||||
internal::kernel_statx_buf xbuf;
|
||||
auto result = linux_syscalls::statx(fd, "", AT_EMPTY_PATH,
|
||||
internal::KERNEL_STATX_TYPE_MASK, &xbuf);
|
||||
if (!result)
|
||||
return result.error();
|
||||
|
||||
if (!S_ISDIR(xbuf.stx_mode))
|
||||
return ENOTDIR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@ struct kernel_statx_buf {
|
|||
// stx_btime field will be filled in.
|
||||
constexpr unsigned int KERNEL_STATX_BASIC_STATS_MASK = 0x7FF;
|
||||
|
||||
// This mask is used to check the type of the file descriptor.
|
||||
constexpr unsigned int KERNEL_STATX_TYPE_MASK = 0x008;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
|
|
|||
|
|
@ -631,6 +631,18 @@ add_header_library(
|
|||
libc.include.sys_syscall
|
||||
)
|
||||
|
||||
add_header_library(
|
||||
fcntl
|
||||
HDRS
|
||||
fcntl.h
|
||||
DEPENDS
|
||||
libc.src.__support.OSUtil.osutil
|
||||
libc.src.__support.common
|
||||
libc.src.__support.error_or
|
||||
libc.src.__support.macros.config
|
||||
libc.include.sys_syscall
|
||||
)
|
||||
|
||||
add_header_library(
|
||||
fsync
|
||||
HDRS
|
||||
|
|
|
|||
43
libc/src/__support/OSUtil/linux/syscall_wrappers/fcntl.h
Normal file
43
libc/src/__support/OSUtil/linux/syscall_wrappers/fcntl.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// ErrorOr-returning syscall wrapper for fcntl.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCNTL_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCNTL_H
|
||||
|
||||
#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
|
||||
#include "src/__support/common.h"
|
||||
#include "src/__support/error_or.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
#include <sys/syscall.h> // For syscall numbers
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace linux_syscalls {
|
||||
|
||||
LIBC_INLINE ErrorOr<int> fcntl(int fd, int cmd, void *arg) {
|
||||
int ret = syscall_impl<int>(SYS_fcntl, fd, cmd, arg);
|
||||
if (ret < 0)
|
||||
return Error(-ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
LIBC_INLINE ErrorOr<int> fcntl(int fd, int cmd, long arg = 0) {
|
||||
int ret = syscall_impl<int>(SYS_fcntl, fd, cmd, arg);
|
||||
if (ret < 0)
|
||||
return Error(-ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace linux_syscalls
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCNTL_H
|
||||
|
|
@ -48,3 +48,18 @@ add_entrypoint_object(
|
|||
libc.src.__support.File.platform_dir
|
||||
libc.src.errno.errno
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
fdopendir
|
||||
SRCS
|
||||
fdopendir.cpp
|
||||
HDRS
|
||||
fdopendir.h
|
||||
DEPENDS
|
||||
libc.src.__support.common
|
||||
libc.src.__support.macros.config
|
||||
libc.hdr.types.DIR
|
||||
libc.src.__support.File.dir
|
||||
libc.src.errno.errno
|
||||
)
|
||||
|
||||
|
|
|
|||
37
libc/src/dirent/fdopendir.cpp
Normal file
37
libc/src/dirent/fdopendir.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Implementation of the POSIX fdopendir function.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "fdopendir.h"
|
||||
|
||||
#include "src/__support/File/dir.h"
|
||||
#include "src/__support/common.h"
|
||||
#include "src/__support/libc_errno.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
LLVM_LIBC_FUNCTION(DIR *, fdopendir, (int fd)) {
|
||||
int check = platform_check_dir(fd);
|
||||
if (check != 0) {
|
||||
libc_errno = check;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto dir = Dir::fdopen(fd);
|
||||
if (!dir) {
|
||||
libc_errno = dir.error();
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<DIR *>(dir.value());
|
||||
}
|
||||
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
26
libc/src/dirent/fdopendir.h
Normal file
26
libc/src/dirent/fdopendir.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Declaration of the POSIX fdopendir function.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC_DIRENT_FDOPENDIR_H
|
||||
#define LLVM_LIBC_SRC_DIRENT_FDOPENDIR_H
|
||||
|
||||
#include "hdr/types/DIR.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
DIR *fdopendir(int fd);
|
||||
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
#endif // LLVM_LIBC_SRC_DIRENT_FDOPENDIR_H
|
||||
|
|
@ -17,3 +17,25 @@ add_libc_unittest(
|
|||
libc.test.UnitTest.ErrnoCheckingTest
|
||||
)
|
||||
|
||||
add_libc_unittest(
|
||||
fdopendir_test
|
||||
SUITE
|
||||
libc_dirent_unittests
|
||||
SRCS
|
||||
fdopendir_test.cpp
|
||||
DEPENDS
|
||||
libc.src.__support.CPP.string_view
|
||||
libc.src.dirent.fdopendir
|
||||
libc.src.dirent.closedir
|
||||
libc.src.dirent.readdir
|
||||
libc.src.fcntl.open
|
||||
libc.src.unistd.close
|
||||
libc.src.fcntl.fcntl
|
||||
libc.src.errno.errno
|
||||
libc.test.UnitTest.ErrnoCheckingTest
|
||||
libc.test.UnitTest.ErrnoSetterMatcher
|
||||
libc.hdr.types.DIR
|
||||
libc.hdr.types.struct_dirent
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
113
libc/test/src/dirent/fdopendir_test.cpp
Normal file
113
libc/test/src/dirent/fdopendir_test.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Unit tests for the POSIX fdopendir function.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "hdr/types/DIR.h"
|
||||
#include "hdr/types/struct_dirent.h"
|
||||
#include "src/dirent/closedir.h"
|
||||
#include "src/dirent/dirfd.h"
|
||||
#include "src/dirent/fdopendir.h"
|
||||
#include "src/dirent/readdir.h"
|
||||
#include "src/fcntl/fcntl.h"
|
||||
#include "src/fcntl/open.h"
|
||||
#include "src/unistd/close.h"
|
||||
|
||||
#include "src/__support/CPP/string_view.h"
|
||||
#include "test/UnitTest/ErrnoCheckingTest.h"
|
||||
#include "test/UnitTest/ErrnoSetterMatcher.h"
|
||||
#include "test/UnitTest/Test.h"
|
||||
|
||||
#include "hdr/fcntl_macros.h"
|
||||
|
||||
using LlvmLibcFdopendirTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
|
||||
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
|
||||
|
||||
TEST_F(LlvmLibcFdopendirTest, SuccessCase) {
|
||||
int fd = LIBC_NAMESPACE::open("testdata", O_RDONLY | O_DIRECTORY);
|
||||
ASSERT_GT(fd, 0);
|
||||
ASSERT_ERRNO_SUCCESS();
|
||||
|
||||
DIR *dir = LIBC_NAMESPACE::fdopendir(fd);
|
||||
ASSERT_TRUE(dir != nullptr);
|
||||
ASSERT_ERRNO_SUCCESS();
|
||||
|
||||
struct dirent *file1 = nullptr, *file2 = nullptr;
|
||||
while (true) {
|
||||
struct dirent *d = LIBC_NAMESPACE::readdir(dir);
|
||||
if (d == nullptr)
|
||||
break;
|
||||
if (LIBC_NAMESPACE::cpp::string_view(d->d_name) == "file1.txt")
|
||||
file1 = d;
|
||||
if (LIBC_NAMESPACE::cpp::string_view(d->d_name) == "file2.txt")
|
||||
file2 = d;
|
||||
}
|
||||
ASSERT_ERRNO_SUCCESS();
|
||||
ASSERT_TRUE(file1 != nullptr);
|
||||
ASSERT_TRUE(file2 != nullptr);
|
||||
|
||||
ASSERT_EQ(LIBC_NAMESPACE::closedir(dir), 0);
|
||||
|
||||
// Verify fd is closed
|
||||
int fcntl_res = LIBC_NAMESPACE::fcntl(fd, F_GETFD);
|
||||
ASSERT_EQ(fcntl_res, -1);
|
||||
ASSERT_ERRNO_EQ(EBADF);
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcFdopendirTest, InvalidFd) {
|
||||
DIR *dir = LIBC_NAMESPACE::fdopendir(-1);
|
||||
ASSERT_TRUE(dir == nullptr);
|
||||
ASSERT_ERRNO_EQ(EBADF);
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcFdopendirTest, ClosedFd) {
|
||||
int fd = LIBC_NAMESPACE::open("testdata", O_RDONLY | O_DIRECTORY);
|
||||
ASSERT_GT(fd, 0);
|
||||
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
|
||||
|
||||
DIR *dir = LIBC_NAMESPACE::fdopendir(fd);
|
||||
ASSERT_TRUE(dir == nullptr);
|
||||
ASSERT_ERRNO_EQ(EBADF);
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcFdopendirTest, NotADirectory) {
|
||||
int fd = LIBC_NAMESPACE::open("testdata/file1.txt", O_RDONLY);
|
||||
ASSERT_GT(fd, 0);
|
||||
|
||||
DIR *dir = LIBC_NAMESPACE::fdopendir(fd);
|
||||
ASSERT_TRUE(dir == nullptr);
|
||||
ASSERT_ERRNO_EQ(ENOTDIR);
|
||||
|
||||
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcFdopendirTest, OPathFd) {
|
||||
int fd = LIBC_NAMESPACE::open("testdata", O_PATH);
|
||||
ASSERT_GT(fd, 0);
|
||||
|
||||
DIR *dir = LIBC_NAMESPACE::fdopendir(fd);
|
||||
ASSERT_TRUE(dir == nullptr);
|
||||
ASSERT_ERRNO_EQ(EBADF);
|
||||
|
||||
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcFdopendirTest, WriteOnlyFd) {
|
||||
int fd = LIBC_NAMESPACE::open("testdata/file1.txt", O_WRONLY);
|
||||
ASSERT_GT(fd, 0);
|
||||
|
||||
DIR *dir = LIBC_NAMESPACE::fdopendir(fd);
|
||||
ASSERT_TRUE(dir == nullptr);
|
||||
ASSERT_TRUE(libc_errno == EBADF || libc_errno == ENOTDIR);
|
||||
libc_errno = 0;
|
||||
|
||||
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
|
||||
}
|
||||
Loading…
Reference in a new issue