[libc-commits] [libc] [libc] Implement scandir and its unit tests (PR #223198)
Vadim Kotov via libc-commits
libc-commits at lists.llvm.org
Wed Sep 16 11:55:14 PDT 2026
https://github.com/vadimkotov updated https://github.com/llvm/llvm-project/pull/223198
>From 4de87f420ff5aa0ad15ff8f4f851281dd368ffa1 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Thu, 3 Sep 2026 15:17:45 -0700
Subject: [PATCH 01/15] Create boilerplate code for scandir and its unittest.
---
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/include/dirent.yaml | 9 +++++++
libc/src/dirent/CMakeLists.txt | 12 +++++++++
libc/src/dirent/scandir.cpp | 34 ++++++++++++++++++++++++
libc/src/dirent/scandir.h | 28 +++++++++++++++++++
libc/test/src/dirent/CMakeLists.txt | 11 ++++++++
libc/test/src/dirent/scandir_test.cpp | 21 +++++++++++++++
7 files changed, 116 insertions(+)
create mode 100644 libc/src/dirent/scandir.cpp
create mode 100644 libc/src/dirent/scandir.h
create mode 100644 libc/test/src/dirent/scandir_test.cpp
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 42cbcd02513eb..5fb75675352cf 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1314,6 +1314,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.dirent.dirfd
libc.src.dirent.opendir
libc.src.dirent.readdir
+ libc.src.dirent.scandir
libc.src.dirent.fdopendir
# pthread.h entrypoints
diff --git a/libc/include/dirent.yaml b/libc/include/dirent.yaml
index e752b564d8d44..8dc939fa1158a 100644
--- a/libc/include/dirent.yaml
+++ b/libc/include/dirent.yaml
@@ -64,3 +64,12 @@ functions:
return_type: struct dirent *
arguments:
- type: DIR *
+ - name: scandir
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: const char *
+ - type: struct dirent ***
+ - type: int (*)(const struct dirent *)
+ - type: int (*)(const struct dirent **, const struct dirent **)
diff --git a/libc/src/dirent/CMakeLists.txt b/libc/src/dirent/CMakeLists.txt
index d0ec22e1cc75b..8b8c09b661b32 100644
--- a/libc/src/dirent/CMakeLists.txt
+++ b/libc/src/dirent/CMakeLists.txt
@@ -49,6 +49,18 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ scandir
+ SRCS
+ scandir.cpp
+ HDRS
+ scandir.h
+ DEPENDS
+ libc.hdr.types.struct_dirent
+ libc.src.__support.common
+ libc.src.__support.macros.config
+)
+
add_entrypoint_object(
fdopendir
SRCS
diff --git a/libc/src/dirent/scandir.cpp b/libc/src/dirent/scandir.cpp
new file mode 100644
index 0000000000000..18b7779a3e260
--- /dev/null
+++ b/libc/src/dirent/scandir.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 getpriority.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/dirent/scandir.h"
+
+#include "hdr/types/struct_dirent.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, scandir,
+ (const char *dir, struct dirent ***namelist,
+ int (*sel)(const struct dirent *),
+ int (*compar)(const struct dirent **,
+ const struct dirent **))) {
+ (void)dir;
+ (void)namelist;
+ (void)sel;
+ (void)compar;
+ return -1;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/dirent/scandir.h b/libc/src/dirent/scandir.h
new file mode 100644
index 0000000000000..03ffe076c781f
--- /dev/null
+++ b/libc/src/dirent/scandir.h
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 header of scandir
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_DIRENT_SCANDIR_H
+#define LLVM_LIBC_SRC_DIRENT_SCANDIR_H
+
+#include "hdr/types/struct_dirent.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int scandir(const char *dir, struct dirent ***namelist,
+ int (*sel)(const struct dirent *),
+ int (*compar)(const struct dirent **, const struct dirent **));
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_DIRENT_SCANDIR_H
diff --git a/libc/test/src/dirent/CMakeLists.txt b/libc/test/src/dirent/CMakeLists.txt
index 1d7a3caf790dd..fd56b23d2c4ed 100644
--- a/libc/test/src/dirent/CMakeLists.txt
+++ b/libc/test/src/dirent/CMakeLists.txt
@@ -37,3 +37,14 @@ add_libc_test(
libc.hdr.types.DIR
libc.hdr.types.struct_dirent
)
+
+add_libc_test(
+ scandir_test
+ SUITE
+ libc_dirent_unittests
+ SRCS
+ scandir_test.cpp
+ DEPENDS
+ libc.hdr.types.struct_dirent
+ libc.src.dirent.scandir
+)
diff --git a/libc/test/src/dirent/scandir_test.cpp b/libc/test/src/dirent/scandir_test.cpp
new file mode 100644
index 0000000000000..34e5e83c598a0
--- /dev/null
+++ b/libc/test/src/dirent/scandir_test.cpp
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Unittests for scandir.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/types/struct_dirent.h"
+#include "src/dirent/scandir.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcScandirTest, DummyTest) {
+ struct dirent **namelist;
+ ASSERT_NE(LIBC_NAMESPACE::scandir(".", &namelist, NULL, NULL), -1);
+}
>From cfce0c7ea992aabd77eb2133dc3556def7601c29 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Tue, 8 Sep 2026 10:15:51 -0700
Subject: [PATCH 02/15] Fix a stray change after rebase
---
libc/config/linux/x86_64/entrypoints.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 5fb75675352cf..a7654fea58ba7 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -614,7 +614,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.fenv.fesetexceptflag
libc.src.fenv.fesetround
libc.src.fenv.fetestexcept
- libc.src.fenv.fetestexceptflag
+ libc.src.fenv.fegestexceptflag
libc.src.fenv.feupdateenv
# math.h entrypoints
>From f08f635087b15dbcd1ac47855166421926d34933 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Tue, 8 Sep 2026 11:19:50 -0700
Subject: [PATCH 03/15] Mid-work commit due to a post-renase issue
---
libc/src/dirent/CMakeLists.txt | 1 +
libc/src/dirent/scandir.cpp | 12 ++++++++++--
libc/test/src/dirent/CMakeLists.txt | 2 ++
libc/test/src/dirent/scandir_test.cpp | 9 +++++++--
4 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/libc/src/dirent/CMakeLists.txt b/libc/src/dirent/CMakeLists.txt
index 8b8c09b661b32..4ad2a8b286a03 100644
--- a/libc/src/dirent/CMakeLists.txt
+++ b/libc/src/dirent/CMakeLists.txt
@@ -59,6 +59,7 @@ add_entrypoint_object(
libc.hdr.types.struct_dirent
libc.src.__support.common
libc.src.__support.macros.config
+ libc.src.dirent.opendir
)
add_entrypoint_object(
diff --git a/libc/src/dirent/scandir.cpp b/libc/src/dirent/scandir.cpp
index 18b7779a3e260..45351d7aad034 100644
--- a/libc/src/dirent/scandir.cpp
+++ b/libc/src/dirent/scandir.cpp
@@ -16,6 +16,7 @@
#include "hdr/types/struct_dirent.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
+#include "src/dirent/opendir.h"
namespace LIBC_NAMESPACE_DECL {
@@ -24,11 +25,18 @@ LLVM_LIBC_FUNCTION(int, scandir,
int (*sel)(const struct dirent *),
int (*compar)(const struct dirent **,
const struct dirent **))) {
- (void)dir;
(void)namelist;
(void)sel;
(void)compar;
- return -1;
+
+ DIR *dir_fd = opendir(dir);
+ if (dir_fd == nullptr) {
+ // opendir set errno
+ return -1;
+ }
+
+
+ return 0;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/dirent/CMakeLists.txt b/libc/test/src/dirent/CMakeLists.txt
index fd56b23d2c4ed..309045f8a9536 100644
--- a/libc/test/src/dirent/CMakeLists.txt
+++ b/libc/test/src/dirent/CMakeLists.txt
@@ -47,4 +47,6 @@ add_libc_test(
DEPENDS
libc.hdr.types.struct_dirent
libc.src.dirent.scandir
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
)
diff --git a/libc/test/src/dirent/scandir_test.cpp b/libc/test/src/dirent/scandir_test.cpp
index 34e5e83c598a0..5be2c9c636bdb 100644
--- a/libc/test/src/dirent/scandir_test.cpp
+++ b/libc/test/src/dirent/scandir_test.cpp
@@ -13,9 +13,14 @@
#include "hdr/types/struct_dirent.h"
#include "src/dirent/scandir.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
-TEST(LlvmLibcScandirTest, DummyTest) {
+using LlvmLibcScandirTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+
+TEST_F(LlvmLibcScandirTest, TestBadDirname) {
struct dirent **namelist;
- ASSERT_NE(LIBC_NAMESPACE::scandir(".", &namelist, NULL, NULL), -1);
+ ASSERT_THAT(LIBC_NAMESPACE::scandir("", &namelist, NULL, NULL), Fails(ENOTDIR, -1));
}
>From c683663013952e7b25f34ac0d47feae3a2dbd02c Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Tue, 8 Sep 2026 11:29:21 -0700
Subject: [PATCH 04/15] Fix a rebase typo
---
libc/config/linux/x86_64/entrypoints.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a7654fea58ba7..5fb75675352cf 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -614,7 +614,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.fenv.fesetexceptflag
libc.src.fenv.fesetround
libc.src.fenv.fetestexcept
- libc.src.fenv.fegestexceptflag
+ libc.src.fenv.fetestexceptflag
libc.src.fenv.feupdateenv
# math.h entrypoints
>From f169cbac4c2f61f7424db5765fa06c173ff72402 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Tue, 8 Sep 2026 14:39:06 -0700
Subject: [PATCH 05/15] Create type headers for scandir filter and compare
function pointers and update the unit test.
---
libc/include/CMakeLists.txt | 2 ++
libc/include/dirent.yaml | 6 ++++--
libc/include/llvm-libc-types/CMakeLists.txt | 2 ++
.../llvm-libc-types/__scandir_compare_t.h | 21 +++++++++++++++++++
.../llvm-libc-types/__scandir_filter_t.h | 21 +++++++++++++++++++
libc/test/src/dirent/scandir_test.cpp | 4 ++--
6 files changed, 52 insertions(+), 4 deletions(-)
create mode 100644 libc/include/llvm-libc-types/__scandir_compare_t.h
create mode 100644 libc/include/llvm-libc-types/__scandir_filter_t.h
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index b6a059e67c355..06ee9b1b1f230 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -47,6 +47,8 @@ add_header_macro(
dirent.h
DEPENDS
.llvm_libc_common_h
+ .llvm-libc-types.__scandir_filter_t
+ .llvm-libc-types.__scandir_compare_t
.llvm-libc-types.ino_t
.llvm-libc-types.DIR
.llvm-libc-types.struct_dirent
diff --git a/libc/include/dirent.yaml b/libc/include/dirent.yaml
index 8dc939fa1158a..95957303270ab 100644
--- a/libc/include/dirent.yaml
+++ b/libc/include/dirent.yaml
@@ -26,6 +26,8 @@ types:
- type_name: reclen_t
- type_name: size_t
- type_name: ssize_t
+ - type_name: __scandir_filter_t
+ - type_name: __scandir_compare_t
functions:
- name: alphasort
standards:
@@ -71,5 +73,5 @@ functions:
arguments:
- type: const char *
- type: struct dirent ***
- - type: int (*)(const struct dirent *)
- - type: int (*)(const struct dirent **, const struct dirent **)
+ - type: __scandir_filter_t
+ - type: __scandir_compare_t
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index cc7b4df1202ff..6464fdffa696b 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -761,3 +761,5 @@ add_header(__action_fn_t
.VISIT
)
add_header(__free_fn_t HDR __free_fn_t.h)
+add_header(__scandir_filter_t HDR __scandir_filter_t.h DEPENDS .struct_dirent)
+add_header(__scandir_compare_t HDR __scandir_compare_t.h DEPENDS .struct_dirent)
diff --git a/libc/include/llvm-libc-types/__scandir_compare_t.h b/libc/include/llvm-libc-types/__scandir_compare_t.h
new file mode 100644
index 0000000000000..0039188ee6470
--- /dev/null
+++ b/libc/include/llvm-libc-types/__scandir_compare_t.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Definition of __scandir_compare_t type.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES___SCANDIR_COMPARE_T_H
+#define LLVM_LIBC_TYPES___SCANDIR_COMPARE_T_H
+
+#include "struct_dirent.h"
+
+typedef int (*__scandir_compare_t)(const struct dirent **, const struct dirent **);
+
+#endif // LLVM_LIBC_TYPES___SCANDIR_COMPARE_T_H
diff --git a/libc/include/llvm-libc-types/__scandir_filter_t.h b/libc/include/llvm-libc-types/__scandir_filter_t.h
new file mode 100644
index 0000000000000..204c950ee1e2c
--- /dev/null
+++ b/libc/include/llvm-libc-types/__scandir_filter_t.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Definition of __scandir_filter type.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES___SCANDIR_FILTER_T_H
+#define LLVM_LIBC_TYPES___SCANDIR_FILTER_T_H
+
+#include "struct_dirent.h"
+
+typedef int (*__scandir_filter_t)(const struct dirent *);
+
+#endif // LLVM_LIBC_TYPES___SCANDIR_FILTER_H
diff --git a/libc/test/src/dirent/scandir_test.cpp b/libc/test/src/dirent/scandir_test.cpp
index 5be2c9c636bdb..0284da9270eb7 100644
--- a/libc/test/src/dirent/scandir_test.cpp
+++ b/libc/test/src/dirent/scandir_test.cpp
@@ -17,10 +17,10 @@
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
using LlvmLibcScandirTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
TEST_F(LlvmLibcScandirTest, TestBadDirname) {
struct dirent **namelist;
- ASSERT_THAT(LIBC_NAMESPACE::scandir("", &namelist, NULL, NULL), Fails(ENOTDIR, -1));
+ ASSERT_THAT(LIBC_NAMESPACE::scandir("", &namelist, NULL, NULL), Fails(ENOENT, -1));
}
>From 6da7c73526179c47e64d3984205dd938803832a5 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Wed, 9 Sep 2026 17:04:19 -0700
Subject: [PATCH 06/15] Implement readdir loop.
---
libc/src/dirent/CMakeLists.txt | 3 +++
libc/src/dirent/scandir.cpp | 25 ++++++++++++++++++++++---
libc/test/src/dirent/scandir_test.cpp | 5 +++++
3 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/libc/src/dirent/CMakeLists.txt b/libc/src/dirent/CMakeLists.txt
index 4ad2a8b286a03..6fe1d23ac702b 100644
--- a/libc/src/dirent/CMakeLists.txt
+++ b/libc/src/dirent/CMakeLists.txt
@@ -59,7 +59,10 @@ add_entrypoint_object(
libc.hdr.types.struct_dirent
libc.src.__support.common
libc.src.__support.macros.config
+ libc.src.dirent.closedir
libc.src.dirent.opendir
+ libc.src.dirent.readdir
+ libc.src.errno.errno
)
add_entrypoint_object(
diff --git a/libc/src/dirent/scandir.cpp b/libc/src/dirent/scandir.cpp
index 45351d7aad034..b8f720930801d 100644
--- a/libc/src/dirent/scandir.cpp
+++ b/libc/src/dirent/scandir.cpp
@@ -16,7 +16,10 @@
#include "hdr/types/struct_dirent.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
+#include "src/__support/libc_errno.h"
+#include "src/dirent/closedir.h"
#include "src/dirent/opendir.h"
+#include "src/dirent/readdir.h"
namespace LIBC_NAMESPACE_DECL {
@@ -26,15 +29,31 @@ LLVM_LIBC_FUNCTION(int, scandir,
int (*compar)(const struct dirent **,
const struct dirent **))) {
(void)namelist;
- (void)sel;
(void)compar;
- DIR *dir_fd = opendir(dir);
+ DIR *dir_fd = LIBC_NAMESPACE::opendir(dir);
if (dir_fd == nullptr) {
- // opendir set errno
+ // errno set by opendir
return -1;
}
+ struct dirent *entry = nullptr;
+ do {
+ libc_errno = 0;
+ entry = LIBC_NAMESPACE::readdir(dir_fd);
+ if (libc_errno != 0) {
+ // errno set by readdir
+ return -1;
+ }
+
+ if (sel != nullptr && !sel(entry)) {
+ continue;
+ }
+
+ } while (entry != nullptr);
+
+
+ LIBC_NAMESPACE::closedir(dir_fd);
return 0;
}
diff --git a/libc/test/src/dirent/scandir_test.cpp b/libc/test/src/dirent/scandir_test.cpp
index 0284da9270eb7..a7da06c9853de 100644
--- a/libc/test/src/dirent/scandir_test.cpp
+++ b/libc/test/src/dirent/scandir_test.cpp
@@ -20,6 +20,11 @@
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
using LlvmLibcScandirTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+TEST_F(LlvmLibcScandirTest, TestDummy) {
+ struct dirent **namelist;
+ ASSERT_THAT(LIBC_NAMESPACE::scandir("/tmp", &namelist, NULL, NULL), Succeeds());
+}
+
TEST_F(LlvmLibcScandirTest, TestBadDirname) {
struct dirent **namelist;
ASSERT_THAT(LIBC_NAMESPACE::scandir("", &namelist, NULL, NULL), Fails(ENOENT, -1));
>From d1c97077001f4d48c07bb6d26ca138cd37710dd2 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Fri, 11 Sep 2026 12:29:18 -0700
Subject: [PATCH 07/15] Minor changes and fixes, commit before sync.
---
libc/include/CMakeLists.txt | 2 +-
libc/include/dirent.yaml | 2 +-
libc/src/dirent/CMakeLists.txt | 1 +
libc/src/dirent/scandir.cpp | 19 ++++++++++++++-----
4 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 06ee9b1b1f230..9e4039cd1a68a 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -47,8 +47,8 @@ add_header_macro(
dirent.h
DEPENDS
.llvm_libc_common_h
- .llvm-libc-types.__scandir_filter_t
.llvm-libc-types.__scandir_compare_t
+ .llvm-libc-types.__scandir_filter_t
.llvm-libc-types.ino_t
.llvm-libc-types.DIR
.llvm-libc-types.struct_dirent
diff --git a/libc/include/dirent.yaml b/libc/include/dirent.yaml
index 95957303270ab..ca8d6c6619127 100644
--- a/libc/include/dirent.yaml
+++ b/libc/include/dirent.yaml
@@ -26,8 +26,8 @@ types:
- type_name: reclen_t
- type_name: size_t
- type_name: ssize_t
- - type_name: __scandir_filter_t
- type_name: __scandir_compare_t
+ - type_name: __scandir_filter_t
functions:
- name: alphasort
standards:
diff --git a/libc/src/dirent/CMakeLists.txt b/libc/src/dirent/CMakeLists.txt
index 6fe1d23ac702b..e81d16e83bb6f 100644
--- a/libc/src/dirent/CMakeLists.txt
+++ b/libc/src/dirent/CMakeLists.txt
@@ -63,6 +63,7 @@ add_entrypoint_object(
libc.src.dirent.opendir
libc.src.dirent.readdir
libc.src.errno.errno
+ libc.src.stdlib.qsort_util
)
add_entrypoint_object(
diff --git a/libc/src/dirent/scandir.cpp b/libc/src/dirent/scandir.cpp
index b8f720930801d..9c1d5c2ff8245 100644
--- a/libc/src/dirent/scandir.cpp
+++ b/libc/src/dirent/scandir.cpp
@@ -14,22 +14,24 @@
#include "src/dirent/scandir.h"
#include "hdr/types/struct_dirent.h"
+/*
+#include "include/llvm-libc-types/__scandir_compare_t.h"
+#include "include/llvm-libc-types/__scandir_filter_t.h"
+*/
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/libc_errno.h"
#include "src/dirent/closedir.h"
#include "src/dirent/opendir.h"
#include "src/dirent/readdir.h"
+#include "src/stdlib/qsort_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, scandir,
(const char *dir, struct dirent ***namelist,
- int (*sel)(const struct dirent *),
- int (*compar)(const struct dirent **,
- const struct dirent **))) {
+ __scandir_filter_t filter, __scandir_compare_t compare)) {
(void)namelist;
- (void)compar;
DIR *dir_fd = LIBC_NAMESPACE::opendir(dir);
if (dir_fd == nullptr) {
@@ -37,7 +39,12 @@ LLVM_LIBC_FUNCTION(int, scandir,
return -1;
}
+ struct dirent **namelist_local = {};
+ (void)namelist_local;
+
struct dirent *entry = nullptr;
+ size_t count = 0;
+
do {
libc_errno = 0;
entry = LIBC_NAMESPACE::readdir(dir_fd);
@@ -46,12 +53,14 @@ LLVM_LIBC_FUNCTION(int, scandir,
return -1;
}
- if (sel != nullptr && !sel(entry)) {
+ if (filter != nullptr && !filter(entry)) {
continue;
}
} while (entry != nullptr);
+ if (compare != nullptr) {
+ }
LIBC_NAMESPACE::closedir(dir_fd);
>From 95bd74d9bd9b59449432f248ce0d751bae5af828 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Fri, 11 Sep 2026 16:22:18 -0700
Subject: [PATCH 08/15] Implement complete scandir functionality.
---
libc/src/dirent/CMakeLists.txt | 3 ++
libc/src/dirent/scandir.cpp | 74 +++++++++++++++++++++++++++-------
2 files changed, 62 insertions(+), 15 deletions(-)
diff --git a/libc/src/dirent/CMakeLists.txt b/libc/src/dirent/CMakeLists.txt
index e81d16e83bb6f..befea755909d6 100644
--- a/libc/src/dirent/CMakeLists.txt
+++ b/libc/src/dirent/CMakeLists.txt
@@ -56,8 +56,11 @@ add_entrypoint_object(
HDRS
scandir.h
DEPENDS
+ libc.hdr.types.size_t
libc.hdr.types.struct_dirent
+ libc.src.__support.alloc_checker
libc.src.__support.common
+ libc.src.__support.CPP.vector
libc.src.__support.macros.config
libc.src.dirent.closedir
libc.src.dirent.opendir
diff --git a/libc/src/dirent/scandir.cpp b/libc/src/dirent/scandir.cpp
index 9c1d5c2ff8245..9c693bfc23ba3 100644
--- a/libc/src/dirent/scandir.cpp
+++ b/libc/src/dirent/scandir.cpp
@@ -7,61 +7,105 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// Implementation of getpriority.
+/// Implementation of scandir.
///
//===----------------------------------------------------------------------===//
#include "src/dirent/scandir.h"
+#include "hdr/types/size_t.h"
#include "hdr/types/struct_dirent.h"
-/*
-#include "include/llvm-libc-types/__scandir_compare_t.h"
-#include "include/llvm-libc-types/__scandir_filter_t.h"
-*/
+#include "src/__support/alloc-checker.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/libc_errno.h"
+#include "src/__support/CPP/vector.h"
#include "src/dirent/closedir.h"
#include "src/dirent/opendir.h"
#include "src/dirent/readdir.h"
#include "src/stdlib/qsort_util.h"
+#include "src/string/memcpy.h"
namespace LIBC_NAMESPACE_DECL {
+void free_entries(LIBC_NAMESPACE::cpp::vector<struct dirent *> &entries) {
+ for (struct dirent *entry: entries) {
+ delete entry;
+ }
+}
+
LLVM_LIBC_FUNCTION(int, scandir,
(const char *dir, struct dirent ***namelist,
__scandir_filter_t filter, __scandir_compare_t compare)) {
- (void)namelist;
-
DIR *dir_fd = LIBC_NAMESPACE::opendir(dir);
if (dir_fd == nullptr) {
// errno set by opendir
return -1;
}
- struct dirent **namelist_local = {};
- (void)namelist_local;
-
- struct dirent *entry = nullptr;
- size_t count = 0;
+ LIBC_NAMESPACE::cpp::vector<struct dirent*> entries;
- do {
+ while (true) {
libc_errno = 0;
- entry = LIBC_NAMESPACE::readdir(dir_fd);
+ struct dirent *entry = LIBC_NAMESPACE::readdir(dir_fd);
if (libc_errno != 0) {
+ free_entries(entries);
+ LIBC_NAMESPACE::closedir(dir_fd);
// errno set by readdir
return -1;
}
+ if (entry == nullptr) {
+ break;
+ }
+
if (filter != nullptr && !filter(entry)) {
continue;
}
- } while (entry != nullptr);
+ AllocChecker ac;
+ struct dirent *new_entry = new (ac) struct dirent;
+ if (!ac || new_entry == NULL) {
+ free_entries(entries);
+ LIBC_NAMESPACE::closedir(dir_fd);
+ libc_errno = ENOMEM;
+ return -1;
+ }
+
+ LIBC_NAMESPACE::memcpy(new_entry, entry, sizeof(struct dirent));
+
+ if (!entries.push_back(new_entry)) {
+ free_entries(entries);
+ LIBC_NAMESPACE::closedir(dir_fd);
+ libc_errno = ENOMEM;
+ return -1;
+ }
+ }
if (compare != nullptr) {
+ auto cmp_fn = [compare](const void *a, const void *b) {
+ auto left = static_cast<const struct dirent **>(const_cast<void *>(a));
+ auto right = static_cast<const struct dirent **>(const_cast<void *>(b));
+ return compare(left, right);
+ };
+ internal::unstable_sort(entries.data(), entries.size(), sizeof(struct dirent*), cmp_fn);
+ }
+
+ AllocChecker ac;
+ struct dirent **result = new (ac) struct dirent*[entries.size()];
+ if (!ac) {
+ free_entries(entries);
+ LIBC_NAMESPACE::closedir(dir_fd);
+ libc_errno = ENOMEM;
+ return -1;
}
+ for (size_t i = 0; i < entries.size(); ++i) {
+ result[i] = entries[i];
+ }
+
+ *namelist = result;
+
LIBC_NAMESPACE::closedir(dir_fd);
return 0;
>From 7051645f687c18f12de27110af365a5b51a18423 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Fri, 11 Sep 2026 17:14:45 -0700
Subject: [PATCH 09/15] Fix return value and refactor scandir.
---
libc/src/dirent/scandir.cpp | 52 ++++++++++++++-----------------------
1 file changed, 20 insertions(+), 32 deletions(-)
diff --git a/libc/src/dirent/scandir.cpp b/libc/src/dirent/scandir.cpp
index 9c693bfc23ba3..ab64961ab7276 100644
--- a/libc/src/dirent/scandir.cpp
+++ b/libc/src/dirent/scandir.cpp
@@ -28,12 +28,6 @@
namespace LIBC_NAMESPACE_DECL {
-void free_entries(LIBC_NAMESPACE::cpp::vector<struct dirent *> &entries) {
- for (struct dirent *entry: entries) {
- delete entry;
- }
-}
-
LLVM_LIBC_FUNCTION(int, scandir,
(const char *dir, struct dirent ***namelist,
__scandir_filter_t filter, __scandir_compare_t compare)) {
@@ -48,14 +42,8 @@ LLVM_LIBC_FUNCTION(int, scandir,
while (true) {
libc_errno = 0;
struct dirent *entry = LIBC_NAMESPACE::readdir(dir_fd);
- if (libc_errno != 0) {
- free_entries(entries);
- LIBC_NAMESPACE::closedir(dir_fd);
- // errno set by readdir
- return -1;
- }
-
if (entry == nullptr) {
+ // If the readdir call failed it set errno
break;
}
@@ -66,20 +54,32 @@ LLVM_LIBC_FUNCTION(int, scandir,
AllocChecker ac;
struct dirent *new_entry = new (ac) struct dirent;
if (!ac || new_entry == NULL) {
- free_entries(entries);
- LIBC_NAMESPACE::closedir(dir_fd);
libc_errno = ENOMEM;
- return -1;
+ break;
}
LIBC_NAMESPACE::memcpy(new_entry, entry, sizeof(struct dirent));
if (!entries.push_back(new_entry)) {
- free_entries(entries);
- LIBC_NAMESPACE::closedir(dir_fd);
libc_errno = ENOMEM;
- return -1;
+ break;
+ }
+ }
+
+ LIBC_NAMESPACE::closedir(dir_fd);
+
+
+ AllocChecker ac;
+ struct dirent **result = new (ac) struct dirent*[entries.size()];
+ if (!ac) {
+ libc_errno = ENOMEM;
+ }
+
+ if (libc_errno != 0) {
+ for (struct dirent *entry: entries) {
+ delete entry;
}
+ return -1;
}
if (compare != nullptr) {
@@ -91,24 +91,12 @@ LLVM_LIBC_FUNCTION(int, scandir,
internal::unstable_sort(entries.data(), entries.size(), sizeof(struct dirent*), cmp_fn);
}
- AllocChecker ac;
- struct dirent **result = new (ac) struct dirent*[entries.size()];
- if (!ac) {
- free_entries(entries);
- LIBC_NAMESPACE::closedir(dir_fd);
- libc_errno = ENOMEM;
- return -1;
- }
-
for (size_t i = 0; i < entries.size(); ++i) {
result[i] = entries[i];
}
*namelist = result;
-
- LIBC_NAMESPACE::closedir(dir_fd);
-
- return 0;
+ return static_cast<int>(entries.size());
}
} // namespace LIBC_NAMESPACE_DECL
>From af2b920749efbff7d0bcfb7df2aa1d66a13958bc Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Fri, 11 Sep 2026 17:45:22 -0700
Subject: [PATCH 10/15] Implement scandir unit test skeleton and helper
functions.
---
libc/test/src/dirent/CMakeLists.txt | 7 ++++
libc/test/src/dirent/scandir_test.cpp | 54 ++++++++++++++++++++++++++-
2 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/libc/test/src/dirent/CMakeLists.txt b/libc/test/src/dirent/CMakeLists.txt
index 309045f8a9536..1dc41ebd681d9 100644
--- a/libc/test/src/dirent/CMakeLists.txt
+++ b/libc/test/src/dirent/CMakeLists.txt
@@ -46,7 +46,14 @@ add_libc_test(
scandir_test.cpp
DEPENDS
libc.hdr.types.struct_dirent
+ libc.src.__support.OSUtil.path
libc.src.dirent.scandir
+ libc.src.stdio.asprintf
+ libc.src.stdio.fopen
+ libc.src.stdio.fclose
+ libc.src.stdlib.mkdtemp
+ libc.src.string.strdup
+ libc.src.unistd.rmdir
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
diff --git a/libc/test/src/dirent/scandir_test.cpp b/libc/test/src/dirent/scandir_test.cpp
index a7da06c9853de..b06903cab1ab7 100644
--- a/libc/test/src/dirent/scandir_test.cpp
+++ b/libc/test/src/dirent/scandir_test.cpp
@@ -12,7 +12,14 @@
//===----------------------------------------------------------------------===//
#include "hdr/types/struct_dirent.h"
+#include "src/__support/OSUtil/path.h"
#include "src/dirent/scandir.h"
+#include "src/stdio/asprintf.h"
+#include "src/stdio/fopen.h"
+#include "src/stdio/fclose.h"
+#include "src/stdlib/mkdtemp.h"
+#include "src/string/strdup.h"
+#include "src/unistd/rmdir.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
@@ -20,11 +27,54 @@
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
using LlvmLibcScandirTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-TEST_F(LlvmLibcScandirTest, TestDummy) {
+constexpr char TEMPLATE[] = "tmp_XXXXXX";
+
+// A dir alwasys has '.' and '..' in it.
+constexpr int MINIMUM_ENTRIES = 2;
+
+bool create_file(char *dir, const char *name) {
+ char *path = nullptr;
+
+ if (LIBC_NAMESPACE::asprintf(&path, "%s%c%s", dir, LIBC_NAMESPACE::path::SEPARATOR, name) == -1) {
+ return false;
+ }
+
+ FILE *file = LIBC_NAMESPACE::fopen(path, "w");
+ if (file == nullptr) {
+ return false;
+ }
+
+ if (LIBC_NAMESPACE::fclose(file) == -1) {
+ return false;
+ }
+
+ return true;
+}
+
+
+TEST_F(LlvmLibcScandirTest, TestBasic) {
+
+ char *tmpl = LIBC_NAMESPACE::strdup(libc_make_test_file_path(TEMPLATE));
+ ASSERT_NE(tmpl, nullptr);
+ ASSERT_THAT(LIBC_NAMESPACE::mkdtemp(tmpl), Succeeds(tmpl));
+
+ const char *filename_a = libc_make_test_file_path("a");
+ const char *filename_b = libc_make_test_file_path("file_b");
+
+ ASSERT_TRUE(create_file(tmpl, filename_a));
+ ASSERT_TRUE(create_file(tmpl, filename_b));
+
struct dirent **namelist;
- ASSERT_THAT(LIBC_NAMESPACE::scandir("/tmp", &namelist, NULL, NULL), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, NULL, NULL), Succeeds(MINIMUM_ENTRIES + 2));
+
+ // TODO: Implement file deletion!
+ /*
+ ASSERT_THAT(LIBC_NAMESPACE::rmdir(tmpl), Succeeds());
+ free(tmpl);
+ */
}
+
TEST_F(LlvmLibcScandirTest, TestBadDirname) {
struct dirent **namelist;
ASSERT_THAT(LIBC_NAMESPACE::scandir("", &namelist, NULL, NULL), Fails(ENOENT, -1));
>From 5e5bfe291a5fcdccd9f09397b90370e7cff1e772 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Sat, 12 Sep 2026 16:23:43 -0700
Subject: [PATCH 11/15] Move scandir implementation to linux/ and clean up
empty dir test.
---
libc/src/dirent/CMakeLists.txt | 32 ++++++++++---------------
libc/src/dirent/linux/CMakeLists.txt | 19 +++++++++++++++
libc/src/dirent/{ => linux}/scandir.cpp | 4 +++-
libc/test/src/dirent/CMakeLists.txt | 1 +
libc/test/src/dirent/scandir_test.cpp | 31 ++++++++++++++----------
5 files changed, 54 insertions(+), 33 deletions(-)
create mode 100644 libc/src/dirent/linux/CMakeLists.txt
rename libc/src/dirent/{ => linux}/scandir.cpp (93%)
diff --git a/libc/src/dirent/CMakeLists.txt b/libc/src/dirent/CMakeLists.txt
index befea755909d6..b5237333e2931 100644
--- a/libc/src/dirent/CMakeLists.txt
+++ b/libc/src/dirent/CMakeLists.txt
@@ -1,3 +1,8 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
+
add_entrypoint_object(
opendir
SRCS
@@ -49,26 +54,6 @@ add_entrypoint_object(
libc.src.errno.errno
)
-add_entrypoint_object(
- scandir
- SRCS
- scandir.cpp
- HDRS
- scandir.h
- DEPENDS
- libc.hdr.types.size_t
- libc.hdr.types.struct_dirent
- libc.src.__support.alloc_checker
- libc.src.__support.common
- libc.src.__support.CPP.vector
- libc.src.__support.macros.config
- libc.src.dirent.closedir
- libc.src.dirent.opendir
- libc.src.dirent.readdir
- libc.src.errno.errno
- libc.src.stdlib.qsort_util
-)
-
add_entrypoint_object(
fdopendir
SRCS
@@ -82,3 +67,10 @@ add_entrypoint_object(
libc.src.__support.File.dir
libc.src.errno.errno
)
+
+add_entrypoint_object(
+ scandir
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.scandir
+)
diff --git a/libc/src/dirent/linux/CMakeLists.txt b/libc/src/dirent/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..e68c3d0e240c6
--- /dev/null
+++ b/libc/src/dirent/linux/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_entrypoint_object(
+ scandir
+ SRCS
+ scandir.cpp
+ HDRS
+ ../scandir.h
+ DEPENDS
+ libc.hdr.types.size_t
+ libc.hdr.types.struct_dirent
+ libc.src.__support.alloc_checker
+ libc.src.__support.common
+ libc.src.__support.CPP.vector
+ libc.src.__support.macros.config
+ libc.src.dirent.closedir
+ libc.src.dirent.opendir
+ libc.src.dirent.readdir
+ libc.src.errno.errno
+ libc.src.stdlib.qsort_util
+)
diff --git a/libc/src/dirent/scandir.cpp b/libc/src/dirent/linux/scandir.cpp
similarity index 93%
rename from libc/src/dirent/scandir.cpp
rename to libc/src/dirent/linux/scandir.cpp
index ab64961ab7276..d1f1612042986 100644
--- a/libc/src/dirent/scandir.cpp
+++ b/libc/src/dirent/linux/scandir.cpp
@@ -58,7 +58,9 @@ LLVM_LIBC_FUNCTION(int, scandir,
break;
}
- LIBC_NAMESPACE::memcpy(new_entry, entry, sizeof(struct dirent));
+ // struct dirent contains an equivalent of flexible array memeber,
+ // which makes sizeof unreliable, hence we use d_reclen.
+ LIBC_NAMESPACE::memcpy(new_entry, entry, entry->d_reclen);
if (!entries.push_back(new_entry)) {
libc_errno = ENOMEM;
diff --git a/libc/test/src/dirent/CMakeLists.txt b/libc/test/src/dirent/CMakeLists.txt
index 1dc41ebd681d9..c1e7d3288bfad 100644
--- a/libc/test/src/dirent/CMakeLists.txt
+++ b/libc/test/src/dirent/CMakeLists.txt
@@ -53,6 +53,7 @@ add_libc_test(
libc.src.stdio.fclose
libc.src.stdlib.mkdtemp
libc.src.string.strdup
+ libc.src.string.strncmp
libc.src.unistd.rmdir
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
diff --git a/libc/test/src/dirent/scandir_test.cpp b/libc/test/src/dirent/scandir_test.cpp
index b06903cab1ab7..377412c5cd52a 100644
--- a/libc/test/src/dirent/scandir_test.cpp
+++ b/libc/test/src/dirent/scandir_test.cpp
@@ -19,6 +19,7 @@
#include "src/stdio/fclose.h"
#include "src/stdlib/mkdtemp.h"
#include "src/string/strdup.h"
+#include "src/string/strncmp.h"
#include "src/unistd/rmdir.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
@@ -30,7 +31,7 @@ using LlvmLibcScandirTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
constexpr char TEMPLATE[] = "tmp_XXXXXX";
// A dir alwasys has '.' and '..' in it.
-constexpr int MINIMUM_ENTRIES = 2;
+constexpr int ENTRIES_MIN = 2;
bool create_file(char *dir, const char *name) {
char *path = nullptr;
@@ -38,6 +39,7 @@ bool create_file(char *dir, const char *name) {
if (LIBC_NAMESPACE::asprintf(&path, "%s%c%s", dir, LIBC_NAMESPACE::path::SEPARATOR, name) == -1) {
return false;
}
+ free(path);
FILE *file = LIBC_NAMESPACE::fopen(path, "w");
if (file == nullptr) {
@@ -52,26 +54,31 @@ bool create_file(char *dir, const char *name) {
}
-TEST_F(LlvmLibcScandirTest, TestBasic) {
+TEST_F(LlvmLibcScandirTest, TestEmptyDir) {
char *tmpl = LIBC_NAMESPACE::strdup(libc_make_test_file_path(TEMPLATE));
ASSERT_NE(tmpl, nullptr);
ASSERT_THAT(LIBC_NAMESPACE::mkdtemp(tmpl), Succeeds(tmpl));
- const char *filename_a = libc_make_test_file_path("a");
- const char *filename_b = libc_make_test_file_path("file_b");
-
- ASSERT_TRUE(create_file(tmpl, filename_a));
- ASSERT_TRUE(create_file(tmpl, filename_b));
-
struct dirent **namelist;
- ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, NULL, NULL), Succeeds(MINIMUM_ENTRIES + 2));
+ ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, NULL, NULL), Succeeds(ENTRIES_MIN));
+ // ASSERT_STREQ(namelist[1]->d_name, ".");
+ // Order of namelist is not guaranteed so we can't easily use ASSERT_STREQ
+ ASSERT_TRUE(
+ (LIBC_NAMESPACE::strncmp(namelist[0]->d_name, ".", 1) == 0 &&
+ LIBC_NAMESPACE::strncmp(namelist[1]->d_name, "..", 2) == 0) ||
+ (LIBC_NAMESPACE::strncmp(namelist[0]->d_name, "..", 2) == 0 &&
+ LIBC_NAMESPACE::strncmp(namelist[1]->d_name, ".", 1) == 0));
+
+ // We also test that both ordering can't be true at the same time.
+ ASSERT_FALSE(
+ (LIBC_NAMESPACE::strncmp(namelist[0]->d_name, ".", 1) == 0 &&
+ LIBC_NAMESPACE::strncmp(namelist[1]->d_name, "..", 2) == 0) &&
+ (LIBC_NAMESPACE::strncmp(namelist[0]->d_name, "..", 2) == 0 &&
+ LIBC_NAMESPACE::strncmp(namelist[1]->d_name, ".", 1) == 0));
- // TODO: Implement file deletion!
- /*
ASSERT_THAT(LIBC_NAMESPACE::rmdir(tmpl), Succeeds());
free(tmpl);
- */
}
>From ae11ac69a04ce46db5523de0f9b1b2881d220a5c Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Sat, 12 Sep 2026 17:10:41 -0700
Subject: [PATCH 12/15] Use malloc instead of AllocChecker in scandir
---
libc/src/dirent/linux/CMakeLists.txt | 3 ++-
libc/src/dirent/linux/scandir.cpp | 38 ++++++++++++++++------------
2 files changed, 24 insertions(+), 17 deletions(-)
diff --git a/libc/src/dirent/linux/CMakeLists.txt b/libc/src/dirent/linux/CMakeLists.txt
index e68c3d0e240c6..71ec9be576623 100644
--- a/libc/src/dirent/linux/CMakeLists.txt
+++ b/libc/src/dirent/linux/CMakeLists.txt
@@ -5,9 +5,10 @@ add_entrypoint_object(
HDRS
../scandir.h
DEPENDS
+ libc.hdr.func.free
+ libc.hdr.func.malloc
libc.hdr.types.size_t
libc.hdr.types.struct_dirent
- libc.src.__support.alloc_checker
libc.src.__support.common
libc.src.__support.CPP.vector
libc.src.__support.macros.config
diff --git a/libc/src/dirent/linux/scandir.cpp b/libc/src/dirent/linux/scandir.cpp
index d1f1612042986..37fd06075b136 100644
--- a/libc/src/dirent/linux/scandir.cpp
+++ b/libc/src/dirent/linux/scandir.cpp
@@ -13,9 +13,10 @@
#include "src/dirent/scandir.h"
+#include "hdr/func/free.h"
+#include "hdr/func/malloc.h"
#include "hdr/types/size_t.h"
#include "hdr/types/struct_dirent.h"
-#include "src/__support/alloc-checker.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/libc_errno.h"
@@ -23,6 +24,7 @@
#include "src/dirent/closedir.h"
#include "src/dirent/opendir.h"
#include "src/dirent/readdir.h"
+#include "src/stdlib/malloc.h"
#include "src/stdlib/qsort_util.h"
#include "src/string/memcpy.h"
@@ -37,6 +39,7 @@ LLVM_LIBC_FUNCTION(int, scandir,
return -1;
}
+ int saved_errno = 0;
LIBC_NAMESPACE::cpp::vector<struct dirent*> entries;
while (true) {
@@ -44,43 +47,46 @@ LLVM_LIBC_FUNCTION(int, scandir,
struct dirent *entry = LIBC_NAMESPACE::readdir(dir_fd);
if (entry == nullptr) {
// If the readdir call failed it set errno
+ saved_errno = libc_errno;
break;
}
+ // Note, filter may modify errno
if (filter != nullptr && !filter(entry)) {
continue;
}
- AllocChecker ac;
- struct dirent *new_entry = new (ac) struct dirent;
- if (!ac || new_entry == NULL) {
- libc_errno = ENOMEM;
- break;
+ // struct dirent contains an equivalent of flexible array memeber we
+ // allocate with malloc and use d_reclen as size.
+ struct dirent *new_entry = static_cast<struct dirent*>(::malloc(entry->d_reclen));
+ if (new_entry == nullptr) {
+ saved_errno = ENOMEM;
}
-
- // struct dirent contains an equivalent of flexible array memeber,
- // which makes sizeof unreliable, hence we use d_reclen.
LIBC_NAMESPACE::memcpy(new_entry, entry, entry->d_reclen);
if (!entries.push_back(new_entry)) {
- libc_errno = ENOMEM;
+ free(new_entry);
+ saved_errno = ENOMEM;
break;
}
}
+ // Closedir may modify errno and set it to EBADF, which is not amongst
+ // POSIX-defined error codes for scandir. So we ignore closedir's errno.
LIBC_NAMESPACE::closedir(dir_fd);
+ struct dirent **result = static_cast<struct dirent**>(
+ ::malloc(entries.size() * sizeof(struct dirent *)));
- AllocChecker ac;
- struct dirent **result = new (ac) struct dirent*[entries.size()];
- if (!ac) {
- libc_errno = ENOMEM;
+ if (result == nullptr) {
+ saved_errno = ENOMEM;
}
- if (libc_errno != 0) {
+ if (saved_errno != 0) {
for (struct dirent *entry: entries) {
- delete entry;
+ ::free(entry);
}
+ libc_errno = saved_errno;
return -1;
}
>From ed3ef6633161784f2836ca22eb96cd4f874feabe Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Sat, 12 Sep 2026 17:54:21 -0700
Subject: [PATCH 13/15] Implement basic filter and compare unit tests for
scandir
---
libc/test/src/dirent/CMakeLists.txt | 2 +
libc/test/src/dirent/scandir_test.cpp | 77 ++++++++++++++++++++++-----
2 files changed, 67 insertions(+), 12 deletions(-)
diff --git a/libc/test/src/dirent/CMakeLists.txt b/libc/test/src/dirent/CMakeLists.txt
index c1e7d3288bfad..81bc4dd19bd5b 100644
--- a/libc/test/src/dirent/CMakeLists.txt
+++ b/libc/test/src/dirent/CMakeLists.txt
@@ -51,7 +51,9 @@ add_libc_test(
libc.src.stdio.asprintf
libc.src.stdio.fopen
libc.src.stdio.fclose
+ libc.src.stdio.remove
libc.src.stdlib.mkdtemp
+ libc.src.string.strcoll
libc.src.string.strdup
libc.src.string.strncmp
libc.src.unistd.rmdir
diff --git a/libc/test/src/dirent/scandir_test.cpp b/libc/test/src/dirent/scandir_test.cpp
index 377412c5cd52a..2acc0e3ed47c4 100644
--- a/libc/test/src/dirent/scandir_test.cpp
+++ b/libc/test/src/dirent/scandir_test.cpp
@@ -17,7 +17,9 @@
#include "src/stdio/asprintf.h"
#include "src/stdio/fopen.h"
#include "src/stdio/fclose.h"
+#include "src/stdio/remove.h"
#include "src/stdlib/mkdtemp.h"
+#include "src/string/strcoll.h"
#include "src/string/strdup.h"
#include "src/string/strncmp.h"
#include "src/unistd/rmdir.h"
@@ -33,15 +35,14 @@ constexpr char TEMPLATE[] = "tmp_XXXXXX";
// A dir alwasys has '.' and '..' in it.
constexpr int ENTRIES_MIN = 2;
-bool create_file(char *dir, const char *name) {
+char *join_path(char *dir, const char *filename) {
char *path = nullptr;
-
- if (LIBC_NAMESPACE::asprintf(&path, "%s%c%s", dir, LIBC_NAMESPACE::path::SEPARATOR, name) == -1) {
- return false;
+ if (LIBC_NAMESPACE::asprintf(&path, "%s%c%s", dir, LIBC_NAMESPACE::path::SEPARATOR, filename) == -1) {
+ return nullptr;
}
- free(path);
-
- FILE *file = LIBC_NAMESPACE::fopen(path, "w");
+ return path;
+}
+bool create_empty_file(char *path) { FILE *file = LIBC_NAMESPACE::fopen(path, "w");
if (file == nullptr) {
return false;
}
@@ -49,20 +50,25 @@ bool create_file(char *dir, const char *name) {
if (LIBC_NAMESPACE::fclose(file) == -1) {
return false;
}
-
return true;
}
-TEST_F(LlvmLibcScandirTest, TestEmptyDir) {
+int alphasort(const struct dirent **a, const struct dirent **b) {
+ return LIBC_NAMESPACE::strcoll((*a)->d_name, (*b)->d_name);
+}
+
+int skip_hidden(const struct dirent *entry) {
+ return entry->d_name[0] != '.';
+}
+TEST_F(LlvmLibcScandirTest, TestEmptyDir) {
char *tmpl = LIBC_NAMESPACE::strdup(libc_make_test_file_path(TEMPLATE));
ASSERT_NE(tmpl, nullptr);
ASSERT_THAT(LIBC_NAMESPACE::mkdtemp(tmpl), Succeeds(tmpl));
struct dirent **namelist;
- ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, NULL, NULL), Succeeds(ENTRIES_MIN));
- // ASSERT_STREQ(namelist[1]->d_name, ".");
+ ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, nullptr, nullptr), Succeeds(ENTRIES_MIN));
// Order of namelist is not guaranteed so we can't easily use ASSERT_STREQ
ASSERT_TRUE(
(LIBC_NAMESPACE::strncmp(namelist[0]->d_name, ".", 1) == 0 &&
@@ -70,7 +76,7 @@ TEST_F(LlvmLibcScandirTest, TestEmptyDir) {
(LIBC_NAMESPACE::strncmp(namelist[0]->d_name, "..", 2) == 0 &&
LIBC_NAMESPACE::strncmp(namelist[1]->d_name, ".", 1) == 0));
- // We also test that both ordering can't be true at the same time.
+ // We also test that both orderings can't be true at the same time.
ASSERT_FALSE(
(LIBC_NAMESPACE::strncmp(namelist[0]->d_name, ".", 1) == 0 &&
LIBC_NAMESPACE::strncmp(namelist[1]->d_name, "..", 2) == 0) &&
@@ -81,6 +87,53 @@ TEST_F(LlvmLibcScandirTest, TestEmptyDir) {
free(tmpl);
}
+TEST_F(LlvmLibcScandirTest, TestDirFilter) {
+ char *tmpl = LIBC_NAMESPACE::strdup(libc_make_test_file_path(TEMPLATE));
+ ASSERT_NE(tmpl, nullptr);
+ ASSERT_THAT(LIBC_NAMESPACE::mkdtemp(tmpl), Succeeds(tmpl));
+
+ struct dirent **namelist;
+ ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, skip_hidden, nullptr), Succeeds(0));
+
+ ASSERT_THAT(LIBC_NAMESPACE::rmdir(tmpl), Succeeds());
+ free(tmpl);
+}
+
+TEST_F(LlvmLibcScandirTest, TestDirSorted) {
+ char *tmpl = LIBC_NAMESPACE::strdup(libc_make_test_file_path(TEMPLATE));
+ ASSERT_NE(tmpl, nullptr);
+ ASSERT_THAT(LIBC_NAMESPACE::mkdtemp(tmpl), Succeeds(tmpl));
+
+ char *path_d = join_path(tmpl, "d");
+ ASSERT_TRUE(path_d != nullptr);
+ ASSERT_TRUE(create_empty_file(path_d));
+
+ char *path_a = join_path(tmpl, "a");
+ ASSERT_TRUE(path_a != nullptr);
+ ASSERT_TRUE(create_empty_file(path_a));
+
+ char *path_1 = join_path(tmpl, "1");
+ ASSERT_TRUE(path_1 != nullptr);
+ ASSERT_TRUE(create_empty_file(path_1));
+
+ struct dirent **namelist;
+ ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, skip_hidden, alphasort), Succeeds(3));
+
+ ASSERT_STREQ(namelist[0]->d_name, "1");
+ ASSERT_STREQ(namelist[1]->d_name, "a");
+ ASSERT_STREQ(namelist[2]->d_name, "d");
+
+ ASSERT_THAT(LIBC_NAMESPACE::remove(path_d), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::remove(path_a), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::remove(path_1), Succeeds());
+
+ free(path_d);
+ free(path_a);
+ free(path_1);
+
+ ASSERT_THAT(LIBC_NAMESPACE::rmdir(tmpl), Succeeds());
+ free(tmpl);
+}
TEST_F(LlvmLibcScandirTest, TestBadDirname) {
struct dirent **namelist;
>From b57c15020f9a5204df17cf0628ed37a6cef90b52 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Sat, 12 Sep 2026 18:07:20 -0700
Subject: [PATCH 14/15] Fix clang format errors
---
.../llvm-libc-types/__scandir_compare_t.h | 5 ++-
.../llvm-libc-types/__scandir_filter_t.h | 2 +-
libc/src/dirent/linux/scandir.cpp | 16 ++++---
libc/test/src/dirent/scandir_test.cpp | 44 ++++++++++---------
4 files changed, 36 insertions(+), 31 deletions(-)
diff --git a/libc/include/llvm-libc-types/__scandir_compare_t.h b/libc/include/llvm-libc-types/__scandir_compare_t.h
index 0039188ee6470..615955d0c60c0 100644
--- a/libc/include/llvm-libc-types/__scandir_compare_t.h
+++ b/libc/include/llvm-libc-types/__scandir_compare_t.h
@@ -16,6 +16,7 @@
#include "struct_dirent.h"
-typedef int (*__scandir_compare_t)(const struct dirent **, const struct dirent **);
+typedef int (*__scandir_compare_t)(const struct dirent **,
+ const struct dirent **);
-#endif // LLVM_LIBC_TYPES___SCANDIR_COMPARE_T_H
+#endif // LLVM_LIBC_TYPES___SCANDIR_COMPARE_T_H
diff --git a/libc/include/llvm-libc-types/__scandir_filter_t.h b/libc/include/llvm-libc-types/__scandir_filter_t.h
index 204c950ee1e2c..3f6aa99889f42 100644
--- a/libc/include/llvm-libc-types/__scandir_filter_t.h
+++ b/libc/include/llvm-libc-types/__scandir_filter_t.h
@@ -18,4 +18,4 @@
typedef int (*__scandir_filter_t)(const struct dirent *);
-#endif // LLVM_LIBC_TYPES___SCANDIR_FILTER_H
+#endif // LLVM_LIBC_TYPES___SCANDIR_FILTER_H
diff --git a/libc/src/dirent/linux/scandir.cpp b/libc/src/dirent/linux/scandir.cpp
index 37fd06075b136..d14b53255a1c4 100644
--- a/libc/src/dirent/linux/scandir.cpp
+++ b/libc/src/dirent/linux/scandir.cpp
@@ -17,10 +17,10 @@
#include "hdr/func/malloc.h"
#include "hdr/types/size_t.h"
#include "hdr/types/struct_dirent.h"
+#include "src/__support/CPP/vector.h"
#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
#include "src/__support/libc_errno.h"
-#include "src/__support/CPP/vector.h"
+#include "src/__support/macros/config.h"
#include "src/dirent/closedir.h"
#include "src/dirent/opendir.h"
#include "src/dirent/readdir.h"
@@ -40,7 +40,7 @@ LLVM_LIBC_FUNCTION(int, scandir,
}
int saved_errno = 0;
- LIBC_NAMESPACE::cpp::vector<struct dirent*> entries;
+ LIBC_NAMESPACE::cpp::vector<struct dirent *> entries;
while (true) {
libc_errno = 0;
@@ -58,7 +58,8 @@ LLVM_LIBC_FUNCTION(int, scandir,
// struct dirent contains an equivalent of flexible array memeber we
// allocate with malloc and use d_reclen as size.
- struct dirent *new_entry = static_cast<struct dirent*>(::malloc(entry->d_reclen));
+ struct dirent *new_entry =
+ static_cast<struct dirent *>(::malloc(entry->d_reclen));
if (new_entry == nullptr) {
saved_errno = ENOMEM;
}
@@ -75,7 +76,7 @@ LLVM_LIBC_FUNCTION(int, scandir,
// POSIX-defined error codes for scandir. So we ignore closedir's errno.
LIBC_NAMESPACE::closedir(dir_fd);
- struct dirent **result = static_cast<struct dirent**>(
+ struct dirent **result = static_cast<struct dirent **>(
::malloc(entries.size() * sizeof(struct dirent *)));
if (result == nullptr) {
@@ -83,7 +84,7 @@ LLVM_LIBC_FUNCTION(int, scandir,
}
if (saved_errno != 0) {
- for (struct dirent *entry: entries) {
+ for (struct dirent *entry : entries) {
::free(entry);
}
libc_errno = saved_errno;
@@ -96,7 +97,8 @@ LLVM_LIBC_FUNCTION(int, scandir,
auto right = static_cast<const struct dirent **>(const_cast<void *>(b));
return compare(left, right);
};
- internal::unstable_sort(entries.data(), entries.size(), sizeof(struct dirent*), cmp_fn);
+ internal::unstable_sort(entries.data(), entries.size(),
+ sizeof(struct dirent *), cmp_fn);
}
for (size_t i = 0; i < entries.size(); ++i) {
diff --git a/libc/test/src/dirent/scandir_test.cpp b/libc/test/src/dirent/scandir_test.cpp
index 2acc0e3ed47c4..fa9b701f65a0e 100644
--- a/libc/test/src/dirent/scandir_test.cpp
+++ b/libc/test/src/dirent/scandir_test.cpp
@@ -15,8 +15,8 @@
#include "src/__support/OSUtil/path.h"
#include "src/dirent/scandir.h"
#include "src/stdio/asprintf.h"
-#include "src/stdio/fopen.h"
#include "src/stdio/fclose.h"
+#include "src/stdio/fopen.h"
#include "src/stdio/remove.h"
#include "src/stdlib/mkdtemp.h"
#include "src/string/strcoll.h"
@@ -37,12 +37,15 @@ constexpr int ENTRIES_MIN = 2;
char *join_path(char *dir, const char *filename) {
char *path = nullptr;
- if (LIBC_NAMESPACE::asprintf(&path, "%s%c%s", dir, LIBC_NAMESPACE::path::SEPARATOR, filename) == -1) {
+ if (LIBC_NAMESPACE::asprintf(&path, "%s%c%s", dir,
+ LIBC_NAMESPACE::path::SEPARATOR,
+ filename) == -1) {
return nullptr;
}
return path;
}
-bool create_empty_file(char *path) { FILE *file = LIBC_NAMESPACE::fopen(path, "w");
+bool create_empty_file(char *path) {
+ FILE *file = LIBC_NAMESPACE::fopen(path, "w");
if (file == nullptr) {
return false;
}
@@ -53,14 +56,11 @@ bool create_empty_file(char *path) { FILE *file = LIBC_NAMESPACE::fopen(path, "w
return true;
}
-
int alphasort(const struct dirent **a, const struct dirent **b) {
return LIBC_NAMESPACE::strcoll((*a)->d_name, (*b)->d_name);
}
-int skip_hidden(const struct dirent *entry) {
- return entry->d_name[0] != '.';
-}
+int skip_hidden(const struct dirent *entry) { return entry->d_name[0] != '.'; }
TEST_F(LlvmLibcScandirTest, TestEmptyDir) {
char *tmpl = LIBC_NAMESPACE::strdup(libc_make_test_file_path(TEMPLATE));
@@ -68,20 +68,19 @@ TEST_F(LlvmLibcScandirTest, TestEmptyDir) {
ASSERT_THAT(LIBC_NAMESPACE::mkdtemp(tmpl), Succeeds(tmpl));
struct dirent **namelist;
- ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, nullptr, nullptr), Succeeds(ENTRIES_MIN));
+ ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, nullptr, nullptr),
+ Succeeds(ENTRIES_MIN));
// Order of namelist is not guaranteed so we can't easily use ASSERT_STREQ
- ASSERT_TRUE(
- (LIBC_NAMESPACE::strncmp(namelist[0]->d_name, ".", 1) == 0 &&
- LIBC_NAMESPACE::strncmp(namelist[1]->d_name, "..", 2) == 0) ||
- (LIBC_NAMESPACE::strncmp(namelist[0]->d_name, "..", 2) == 0 &&
- LIBC_NAMESPACE::strncmp(namelist[1]->d_name, ".", 1) == 0));
+ ASSERT_TRUE((LIBC_NAMESPACE::strncmp(namelist[0]->d_name, ".", 1) == 0 &&
+ LIBC_NAMESPACE::strncmp(namelist[1]->d_name, "..", 2) == 0) ||
+ (LIBC_NAMESPACE::strncmp(namelist[0]->d_name, "..", 2) == 0 &&
+ LIBC_NAMESPACE::strncmp(namelist[1]->d_name, ".", 1) == 0));
// We also test that both orderings can't be true at the same time.
- ASSERT_FALSE(
- (LIBC_NAMESPACE::strncmp(namelist[0]->d_name, ".", 1) == 0 &&
- LIBC_NAMESPACE::strncmp(namelist[1]->d_name, "..", 2) == 0) &&
- (LIBC_NAMESPACE::strncmp(namelist[0]->d_name, "..", 2) == 0 &&
- LIBC_NAMESPACE::strncmp(namelist[1]->d_name, ".", 1) == 0));
+ ASSERT_FALSE((LIBC_NAMESPACE::strncmp(namelist[0]->d_name, ".", 1) == 0 &&
+ LIBC_NAMESPACE::strncmp(namelist[1]->d_name, "..", 2) == 0) &&
+ (LIBC_NAMESPACE::strncmp(namelist[0]->d_name, "..", 2) == 0 &&
+ LIBC_NAMESPACE::strncmp(namelist[1]->d_name, ".", 1) == 0));
ASSERT_THAT(LIBC_NAMESPACE::rmdir(tmpl), Succeeds());
free(tmpl);
@@ -93,7 +92,8 @@ TEST_F(LlvmLibcScandirTest, TestDirFilter) {
ASSERT_THAT(LIBC_NAMESPACE::mkdtemp(tmpl), Succeeds(tmpl));
struct dirent **namelist;
- ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, skip_hidden, nullptr), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, skip_hidden, nullptr),
+ Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::rmdir(tmpl), Succeeds());
free(tmpl);
@@ -117,7 +117,8 @@ TEST_F(LlvmLibcScandirTest, TestDirSorted) {
ASSERT_TRUE(create_empty_file(path_1));
struct dirent **namelist;
- ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, skip_hidden, alphasort), Succeeds(3));
+ ASSERT_THAT(LIBC_NAMESPACE::scandir(tmpl, &namelist, skip_hidden, alphasort),
+ Succeeds(3));
ASSERT_STREQ(namelist[0]->d_name, "1");
ASSERT_STREQ(namelist[1]->d_name, "a");
@@ -137,5 +138,6 @@ TEST_F(LlvmLibcScandirTest, TestDirSorted) {
TEST_F(LlvmLibcScandirTest, TestBadDirname) {
struct dirent **namelist;
- ASSERT_THAT(LIBC_NAMESPACE::scandir("", &namelist, NULL, NULL), Fails(ENOENT, -1));
+ ASSERT_THAT(LIBC_NAMESPACE::scandir("", &namelist, NULL, NULL),
+ Fails(ENOENT, -1));
}
>From d6ea5cf2f1227745c80a59b56ba68022cf5b0a61 Mon Sep 17 00:00:00 2001
From: Vadim Kotov <kotov at google.com>
Date: Wed, 16 Sep 2026 18:54:48 +0000
Subject: [PATCH 15/15] Add aarch64 and riscv entry points.
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 1 +
2 files changed, 2 insertions(+)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index fd931e7a0a615..ba749d38e02fc 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1088,6 +1088,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.dirent.dirfd
libc.src.dirent.opendir
libc.src.dirent.readdir
+ libc.src.dirent.scandir
libc.src.dirent.fdopendir
# errno.h entrypoints
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 2525202d4ff10..fcd330084af16 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1303,6 +1303,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.dirent.dirfd
libc.src.dirent.opendir
libc.src.dirent.readdir
+ libc.src.dirent.scandir
libc.src.dirent.fdopendir
# pthread.h entrypoints
More information about the libc-commits
mailing list