Merge "Implement scandirat and scandirat64."
This commit is contained in:
commit
1721be2229
@ -16,9 +16,11 @@
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "private/bionic_macros.h"
|
||||
#include "private/ScopedReaddir.h"
|
||||
@ -26,7 +28,7 @@
|
||||
// A smart pointer to the scandir dirent**.
|
||||
class ScandirResult {
|
||||
public:
|
||||
ScandirResult() : names_(NULL), size_(0), capacity_(0) {
|
||||
ScandirResult() : names_(nullptr), size_(0), capacity_(0) {
|
||||
}
|
||||
|
||||
~ScandirResult() {
|
||||
@ -42,7 +44,7 @@ class ScandirResult {
|
||||
|
||||
dirent** release() {
|
||||
dirent** result = names_;
|
||||
names_ = NULL;
|
||||
names_ = nullptr;
|
||||
size_ = capacity_ = 0;
|
||||
return result;
|
||||
}
|
||||
@ -52,7 +54,7 @@ class ScandirResult {
|
||||
size_t new_capacity = capacity_ + 32;
|
||||
dirent** new_names =
|
||||
reinterpret_cast<dirent**>(realloc(names_, new_capacity * sizeof(dirent*)));
|
||||
if (new_names == NULL) {
|
||||
if (new_names == nullptr) {
|
||||
return false;
|
||||
}
|
||||
names_ = new_names;
|
||||
@ -60,7 +62,7 @@ class ScandirResult {
|
||||
}
|
||||
|
||||
dirent* copy = CopyDirent(entry);
|
||||
if (copy == NULL) {
|
||||
if (copy == nullptr) {
|
||||
return false;
|
||||
}
|
||||
names_[size_++] = copy;
|
||||
@ -69,7 +71,7 @@ class ScandirResult {
|
||||
|
||||
void Sort(int (*comparator)(const dirent**, const dirent**)) {
|
||||
// If we have entries and a comparator, sort them.
|
||||
if (size_ > 0 && comparator != NULL) {
|
||||
if (size_ > 0 && comparator != nullptr) {
|
||||
qsort(names_, size_, sizeof(dirent*),
|
||||
reinterpret_cast<int (*)(const void*, const void*)>(comparator));
|
||||
}
|
||||
@ -91,19 +93,29 @@ class ScandirResult {
|
||||
DISALLOW_COPY_AND_ASSIGN(ScandirResult);
|
||||
};
|
||||
|
||||
int scandir(const char* dirname, dirent*** name_list,
|
||||
int (*filter)(const dirent*),
|
||||
int (*comparator)(const dirent**, const dirent**)) {
|
||||
ScopedReaddir reader(dirname);
|
||||
int scandirat(int parent_fd, const char* dir_name, dirent*** name_list,
|
||||
int (*filter)(const dirent*),
|
||||
int (*comparator)(const dirent**, const dirent**)) {
|
||||
DIR* dir = nullptr;
|
||||
if (parent_fd == AT_FDCWD) {
|
||||
dir = opendir(dir_name);
|
||||
} else {
|
||||
int dir_fd = openat(parent_fd, dir_name, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
|
||||
if (dir_fd != -1) {
|
||||
dir = fdopendir(dir_fd);
|
||||
}
|
||||
}
|
||||
|
||||
ScopedReaddir reader(dir);
|
||||
if (reader.IsBad()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ScandirResult names;
|
||||
dirent* entry;
|
||||
while ((entry = reader.ReadEntry()) != NULL) {
|
||||
while ((entry = reader.ReadEntry()) != nullptr) {
|
||||
// If we have a filter, skip names that don't match.
|
||||
if (filter != NULL && !(*filter)(entry)) {
|
||||
if (filter != nullptr && !(*filter)(entry)) {
|
||||
continue;
|
||||
}
|
||||
names.Add(entry);
|
||||
@ -115,4 +127,11 @@ int scandir(const char* dirname, dirent*** name_list,
|
||||
*name_list = names.release();
|
||||
return size;
|
||||
}
|
||||
__strong_alias(scandirat64, scandirat);
|
||||
|
||||
int scandir(const char* dir_path, dirent*** name_list,
|
||||
int (*filter)(const dirent*),
|
||||
int (*comparator)(const dirent**, const dirent**)) {
|
||||
return scandirat(AT_FDCWD, dir_path, name_list, filter, comparator);
|
||||
}
|
||||
__strong_alias(scandir64, scandir);
|
||||
|
@ -81,8 +81,13 @@ extern long telldir(DIR*);
|
||||
extern int dirfd(DIR*);
|
||||
extern int alphasort(const struct dirent**, const struct dirent**);
|
||||
extern int alphasort64(const struct dirent64**, const struct dirent64**);
|
||||
extern int scandir(const char*, struct dirent***, int (*)(const struct dirent*), int (*)(const struct dirent**, const struct dirent**));
|
||||
extern int scandir64(const char*, struct dirent64***, int (*)(const struct dirent64*), int (*)(const struct dirent64**, const struct dirent64**));
|
||||
extern int scandir(const char*, struct dirent***, int (*)(const struct dirent*), int (*)(const struct dirent**, const struct dirent**));
|
||||
|
||||
#if defined(__USE_GNU)
|
||||
int scandirat64(int, const char*, struct dirent64***, int (*)(const struct dirent64*), int (*)(const struct dirent64**, const struct dirent64**));
|
||||
int scandirat(int, const char*, struct dirent***, int (*)(const struct dirent*), int (*)(const struct dirent**, const struct dirent**));
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
@ -1346,6 +1346,8 @@ LIBC_N {
|
||||
preadv64;
|
||||
pwritev;
|
||||
pwritev64;
|
||||
scandirat;
|
||||
scandirat64;
|
||||
strchrnul;
|
||||
} LIBC;
|
||||
|
||||
|
@ -23,8 +23,11 @@
|
||||
|
||||
class ScopedReaddir {
|
||||
public:
|
||||
ScopedReaddir(const char* path) {
|
||||
dir_ = opendir(path);
|
||||
ScopedReaddir(const char* path) : ScopedReaddir(opendir(path)) {
|
||||
}
|
||||
|
||||
ScopedReaddir(DIR* dir) {
|
||||
dir_ = dir;
|
||||
}
|
||||
|
||||
~ScopedReaddir() {
|
||||
|
@ -81,6 +81,72 @@ TEST(dirent, scandir_scandir64) {
|
||||
CheckProcSelf(name_set);
|
||||
}
|
||||
|
||||
TEST(dirent, scandirat_scandirat64) {
|
||||
// Get everything from /proc/self...
|
||||
dirent** entries;
|
||||
int entry_count = scandir("/proc/self", &entries, NULL, alphasort);
|
||||
ASSERT_GE(entry_count, 0);
|
||||
|
||||
int proc_fd = open("/proc", O_DIRECTORY);
|
||||
ASSERT_NE(-1, proc_fd);
|
||||
|
||||
dirent** entries_at;
|
||||
int entry_count_at = scandirat(proc_fd, "self", &entries_at, NULL, alphasort);
|
||||
ASSERT_EQ(entry_count, entry_count_at);
|
||||
|
||||
dirent64** entries_at64;
|
||||
int entry_count_at64 = scandirat64(proc_fd, "self", &entries_at64, NULL, alphasort64);
|
||||
ASSERT_EQ(entry_count, entry_count_at64);
|
||||
|
||||
close(proc_fd);
|
||||
|
||||
// scandirat and scandirat64 should return the same results as scandir.
|
||||
std::set<std::string> name_set, name_set_at, name_set_at64;
|
||||
std::vector<std::string> unsorted_name_list, unsorted_name_list_at, unsorted_name_list_at64;
|
||||
ScanEntries(entries, entry_count, name_set, unsorted_name_list);
|
||||
ScanEntries(entries_at, entry_count_at, name_set_at, unsorted_name_list_at);
|
||||
ScanEntries(entries_at64, entry_count_at64, name_set_at64, unsorted_name_list_at64);
|
||||
|
||||
ASSERT_EQ(name_set, name_set_at);
|
||||
ASSERT_EQ(name_set, name_set_at64);
|
||||
ASSERT_EQ(unsorted_name_list, unsorted_name_list_at);
|
||||
ASSERT_EQ(unsorted_name_list, unsorted_name_list_at64);
|
||||
}
|
||||
|
||||
TEST(dirent, scandir_ENOENT) {
|
||||
dirent** entries;
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, scandir("/does-not-exist", &entries, nullptr, nullptr));
|
||||
ASSERT_EQ(ENOENT, errno);
|
||||
}
|
||||
|
||||
TEST(dirent, scandir64_ENOENT) {
|
||||
dirent64** entries;
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, scandir64("/does-not-exist", &entries, nullptr, nullptr));
|
||||
ASSERT_EQ(ENOENT, errno);
|
||||
}
|
||||
|
||||
TEST(dirent, scandirat_ENOENT) {
|
||||
int root_fd = open("/", O_DIRECTORY | O_RDONLY);
|
||||
ASSERT_NE(-1, root_fd);
|
||||
dirent** entries;
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, scandirat(root_fd, "does-not-exist", &entries, nullptr, nullptr));
|
||||
ASSERT_EQ(ENOENT, errno);
|
||||
close(root_fd);
|
||||
}
|
||||
|
||||
TEST(dirent, scandirat64_ENOENT) {
|
||||
int root_fd = open("/", O_DIRECTORY | O_RDONLY);
|
||||
ASSERT_NE(-1, root_fd);
|
||||
dirent64** entries;
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, scandirat64(root_fd, "does-not-exist", &entries, nullptr, nullptr));
|
||||
ASSERT_EQ(ENOENT, errno);
|
||||
close(root_fd);
|
||||
}
|
||||
|
||||
TEST(dirent, fdopendir_invalid) {
|
||||
ASSERT_TRUE(fdopendir(-1) == NULL);
|
||||
ASSERT_EQ(EBADF, errno);
|
||||
|
Loading…
Reference in New Issue
Block a user