Merge "Implement scandirat and scandirat64."

This commit is contained in:
Elliott Hughes 2015-10-27 21:40:31 +00:00 committed by Gerrit Code Review
commit 1721be2229
5 changed files with 109 additions and 14 deletions

View File

@ -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);

View File

@ -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

View File

@ -1346,6 +1346,8 @@ LIBC_N {
preadv64;
pwritev;
pwritev64;
scandirat;
scandirat64;
strchrnul;
} LIBC;

View File

@ -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() {

View File

@ -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);