diff --git a/libc/config/linux/riscv64/entrypoints.txt b/libc/config/linux/riscv64/entrypoints.txt --- a/libc/config/linux/riscv64/entrypoints.txt +++ b/libc/config/linux/riscv64/entrypoints.txt @@ -341,6 +341,12 @@ # assert.h entrypoints libc.src.assert.__assert_fail + # dirent.h entrypoints + libc.src.dirent.closedir + libc.src.dirent.dirfd + libc.src.dirent.opendir + libc.src.dirent.readdir + # network.h entrypoints libc.src.network.htonl libc.src.network.htons diff --git a/libc/config/linux/riscv64/headers.txt b/libc/config/linux/riscv64/headers.txt --- a/libc/config/linux/riscv64/headers.txt +++ b/libc/config/linux/riscv64/headers.txt @@ -1,6 +1,7 @@ set(TARGET_PUBLIC_HEADERS libc.include.assert libc.include.ctype + libc.include.dirent libc.include.errno libc.include.fcntl libc.include.fenv diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -1,4 +1,4 @@ -add_header(off64_t HDR off64_t.h) +add_header(off_t HDR off_t.h) add_header(size_t HDR size_t.h) add_header(ssize_t HDR ssize_t.h) add_header(__atfork_callback_t HDR __atfork_callback_t.h) @@ -20,7 +20,7 @@ add_header(clock_t HDR clock_t.h) add_header(clockid_t HDR clockid_t.h) add_header(cnd_t HDR cnd_t.h) -add_header(cookie_io_functions_t HDR cookie_io_functions_t.h DEPENDS .off64_t .ssize_t) +add_header(cookie_io_functions_t HDR cookie_io_functions_t.h DEPENDS .off_t .ssize_t) add_header(cpu_set_t HDR cpu_set_t.h) add_header(double_t HDR double_t.h) add_header(DIR HDR DIR.h) @@ -41,7 +41,6 @@ add_header(mode_t HDR mode_t.h) add_header(mtx_t HDR mtx_t.h DEPENDS .__futex_word .__mutex_type) add_header(nlink_t HDR nlink_t.h) -add_header(off_t HDR off_t.h) add_header(once_flag HDR once_flag.h DEPENDS .__futex_word) add_header(pid_t HDR pid_t.h) add_header(posix_spawn_file_actions_t HDR posix_spawn_file_actions_t.h) @@ -60,6 +59,7 @@ add_header(struct_rlimit HDR struct_rlimit.h DEPENDS .rlim_t) add_header(struct_rusage HDR struct_rusage.h DEPENDS .struct_timeval) add_header(struct_dirent HDR struct_dirent.h DEPENDS .ino_t .off_t) +add_header(struct_linux_dirent HDR struct_linux_dirent.h DEPENDS .ino_t .off_t) add_header(struct_sched_param HDR struct_sched_param.h) add_header(union_sigval HDR union_sigval.h) add_header(siginfo_t HDR siginfo_t.h DEPENDS .union_sigval .pid_t .uid_t) diff --git a/libc/include/llvm-libc-types/cookie_io_functions_t.h b/libc/include/llvm-libc-types/cookie_io_functions_t.h --- a/libc/include/llvm-libc-types/cookie_io_functions_t.h +++ b/libc/include/llvm-libc-types/cookie_io_functions_t.h @@ -9,13 +9,13 @@ #ifndef __LLVM_LIBC_TYPES_COOKIE_IO_FUNCTIONS_T_H #define __LLVM_LIBC_TYPES_COOKIE_IO_FUNCTIONS_T_H -#include +#include #include #include typedef ssize_t cookie_read_function_t(void *, char *, size_t); typedef ssize_t cookie_write_function_t(void *, const char *, size_t); -typedef int cookie_seek_function_t(void *, off64_t *, int); +typedef int cookie_seek_function_t(void *, off_t *, int); typedef int cookie_close_function_t(void *); typedef struct { diff --git a/libc/include/llvm-libc-types/ino_t.h b/libc/include/llvm-libc-types/ino_t.h --- a/libc/include/llvm-libc-types/ino_t.h +++ b/libc/include/llvm-libc-types/ino_t.h @@ -9,6 +9,6 @@ #ifndef __LLVM_LIBC_TYPES_INO_T_H__ #define __LLVM_LIBC_TYPES_INO_T_H__ -typedef __UINTPTR_TYPE__ ino_t; +typedef __UINT64_TYPE__ ino_t; #endif // __LLVM_LIBC_TYPES_INO_T_H__ diff --git a/libc/include/llvm-libc-types/off64_t.h b/libc/include/llvm-libc-types/off64_t.h deleted file mode 100644 --- a/libc/include/llvm-libc-types/off64_t.h +++ /dev/null @@ -1,14 +0,0 @@ -//===-- Definition of off64_t type ----------------------------------------===// -// -// 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_TYPES_OFF64_T_H__ -#define __LLVM_LIBC_TYPES_OFF64_T_H__ - -typedef __INT64_TYPE__ off64_t; - -#endif // __LLVM_LIBC_TYPES_OFF64_T_H__ diff --git a/libc/include/llvm-libc-types/struct_dirent.h b/libc/include/llvm-libc-types/struct_dirent.h --- a/libc/include/llvm-libc-types/struct_dirent.h +++ b/libc/include/llvm-libc-types/struct_dirent.h @@ -18,6 +18,7 @@ off_t d_off; unsigned short d_reclen; #endif + unsigned char d_type; // The user code should use strlen to determine actual the size of d_name. // Likewise, it is incorrect and prohibited by the POSIX standard to detemine // the size of struct dirent type using sizeof. The size should be got using diff --git a/libc/src/__support/File/CMakeLists.txt b/libc/src/__support/File/CMakeLists.txt --- a/libc/src/__support/File/CMakeLists.txt +++ b/libc/src/__support/File/CMakeLists.txt @@ -11,7 +11,6 @@ HDRS file.h DEPENDS - libc.src.__support.CPP.new libc.src.__support.CPP.span libc.src.__support.threads.mutex @@ -37,7 +36,6 @@ ${LIBC_TARGET_OS}_file.cpp DEPENDS .file - libc.include.fcntl libc.include.stdio libc.include.sys_syscall diff --git a/libc/src/__support/File/dir.cpp b/libc/src/__support/File/dir.cpp --- a/libc/src/__support/File/dir.cpp +++ b/libc/src/__support/File/dir.cpp @@ -12,8 +12,6 @@ #include "src/__support/error_or.h" #include "src/errno/libc_errno.h" // For error macros -#include - namespace __llvm_libc { ErrorOr Dir::open(const char *path) { diff --git a/libc/src/__support/File/linux_dir.cpp b/libc/src/__support/File/linux_dir.cpp --- a/libc/src/__support/File/linux_dir.cpp +++ b/libc/src/__support/File/linux_dir.cpp @@ -8,8 +8,13 @@ #include "dir.h" +#include "src/__support/File/struct_linux_dirent.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/error_or.h" +#include "src/__support/libc_assert.h" +#include "src/string/memory_utils/memmove_implementations.h" +#include "src/string/memory_utils/memset_implementations.h" +#include "src/string/string_utils.h" // string_length #include // For open flags #include // For syscall numbers @@ -34,8 +39,50 @@ } ErrorOr platform_fetch_dirents(int fd, cpp::span buffer) { - long size = +#ifdef SYS_getdents64 + long size = __llvm_libc::syscall_impl(SYS_getdents64, fd, buffer.data(), + buffer.size()); +#elif defined(SYS_getdents) + size_t size = __llvm_libc::syscall_impl(SYS_getdents, fd, buffer.data(), buffer.size()); + + size_t readptr = 0; + while (readptr < size) { + struct LinuxDirent *ld = + reinterpret_cast(buffer.begin() + readptr); + + size_t struct_size = sizeof(ino_t) + sizeof(unsigned char) + + ::__llvm_libc::internal::string_length(ld->d_name) + + sizeof(off_t) + sizeof(unsigned short); + const size_t aligned_struct_size = + ((struct_size + (alignof(LinuxDirent) - 1)) & + ~(alignof(LinuxDirent) - 1)); + + LIBC_ASSERT(aligned_struct_size == ld->d_reclen); + + // d_type is a byte at the end of the structure that indicates the file + // type. + unsigned char d_type = buffer[readptr + aligned_struct_size - 1]; + + // Shift buffer by one + size_t d_name_offset = offsetof(LinuxDirent, d_name); + inline_memmove(buffer.begin() + readptr + d_name_offset + 1, + buffer.begin() + readptr + d_name_offset, + ::__llvm_libc::internal::string_length(ld->d_name)); + + // set d_type and clear its previous location + inline_memset(readptr + buffer.begin() + d_name_offset, d_type, + sizeof(unsigned char)); + inline_memset(readptr + buffer.begin() + aligned_struct_size - 1, 0, + sizeof(unsigned char)); + + readptr += aligned_struct_size; + } +#else +#error \ + "SYS_getdents and SYS_getdents64 syscalls not available to perform a fetch dirents operation." +#endif + if (size < 0) { return __llvm_libc::Error(static_cast(-size)); } diff --git a/libc/src/__support/File/struct_linux_dirent.h b/libc/src/__support/File/struct_linux_dirent.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/File/struct_linux_dirent.h @@ -0,0 +1,32 @@ +//===-- Definition of type struct linux dirent ----------------------------===// +// +// 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_TYPES_STRUCT_LINUX_DIRENT_H__ +#define __LLVM_LIBC_TYPES_STRUCT_LINUX_DIRENT_H__ + +#include +#include + +// Only used by SYS_getdents +struct LinuxDirent { + unsigned long d_ino; +#ifdef __unix__ + unsigned long d_off; + unsigned short d_reclen; +#endif + // This is the minimum width of the string. The user should use strlen + // to find the length of the string. + char d_name[1]; + /* + char pad; // Zero padding byte + char d_type; // File type (only since Linux + // 2.6.4); offset is (d_reclen - 1) + */ +}; + +#endif // __LLVM_LIBC_TYPES_STRUCT_LINUX_DIRENT_H__ diff --git a/libc/src/stdio/fopencookie.cpp b/libc/src/stdio/fopencookie.cpp --- a/libc/src/stdio/fopencookie.cpp +++ b/libc/src/stdio/fopencookie.cpp @@ -59,7 +59,7 @@ if (cookie_file->ops.seek == nullptr) { return Error(EINVAL); } - off64_t offset64 = offset; + off_t offset64 = offset; int result = cookie_file->ops.seek(cookie_file->cookie, &offset64, whence); if (result == 0) return offset64; diff --git a/libc/test/src/stdio/fopencookie_test.cpp b/libc/test/src/stdio/fopencookie_test.cpp --- a/libc/test/src/stdio/fopencookie_test.cpp +++ b/libc/test/src/stdio/fopencookie_test.cpp @@ -57,9 +57,9 @@ return copysize; } -int seek_ss(void *cookie, off64_t *offset, int whence) { +int seek_ss(void *cookie, off_t *offset, int whence) { auto *ss = reinterpret_cast(cookie); - off64_t new_offset; + off_t new_offset; if (whence == SEEK_SET) { new_offset = *offset; } else if (whence == SEEK_CUR) {