Merge "Implement scandirat and scandirat64."
This commit is contained in:
commit
1721be2229
@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "private/bionic_macros.h"
|
#include "private/bionic_macros.h"
|
||||||
#include "private/ScopedReaddir.h"
|
#include "private/ScopedReaddir.h"
|
||||||
@ -26,7 +28,7 @@
|
|||||||
// A smart pointer to the scandir dirent**.
|
// A smart pointer to the scandir dirent**.
|
||||||
class ScandirResult {
|
class ScandirResult {
|
||||||
public:
|
public:
|
||||||
ScandirResult() : names_(NULL), size_(0), capacity_(0) {
|
ScandirResult() : names_(nullptr), size_(0), capacity_(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScandirResult() {
|
~ScandirResult() {
|
||||||
@ -42,7 +44,7 @@ class ScandirResult {
|
|||||||
|
|
||||||
dirent** release() {
|
dirent** release() {
|
||||||
dirent** result = names_;
|
dirent** result = names_;
|
||||||
names_ = NULL;
|
names_ = nullptr;
|
||||||
size_ = capacity_ = 0;
|
size_ = capacity_ = 0;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -52,7 +54,7 @@ class ScandirResult {
|
|||||||
size_t new_capacity = capacity_ + 32;
|
size_t new_capacity = capacity_ + 32;
|
||||||
dirent** new_names =
|
dirent** new_names =
|
||||||
reinterpret_cast<dirent**>(realloc(names_, new_capacity * sizeof(dirent*)));
|
reinterpret_cast<dirent**>(realloc(names_, new_capacity * sizeof(dirent*)));
|
||||||
if (new_names == NULL) {
|
if (new_names == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
names_ = new_names;
|
names_ = new_names;
|
||||||
@ -60,7 +62,7 @@ class ScandirResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dirent* copy = CopyDirent(entry);
|
dirent* copy = CopyDirent(entry);
|
||||||
if (copy == NULL) {
|
if (copy == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
names_[size_++] = copy;
|
names_[size_++] = copy;
|
||||||
@ -69,7 +71,7 @@ class ScandirResult {
|
|||||||
|
|
||||||
void Sort(int (*comparator)(const dirent**, const dirent**)) {
|
void Sort(int (*comparator)(const dirent**, const dirent**)) {
|
||||||
// If we have entries and a comparator, sort them.
|
// If we have entries and a comparator, sort them.
|
||||||
if (size_ > 0 && comparator != NULL) {
|
if (size_ > 0 && comparator != nullptr) {
|
||||||
qsort(names_, size_, sizeof(dirent*),
|
qsort(names_, size_, sizeof(dirent*),
|
||||||
reinterpret_cast<int (*)(const void*, const void*)>(comparator));
|
reinterpret_cast<int (*)(const void*, const void*)>(comparator));
|
||||||
}
|
}
|
||||||
@ -91,19 +93,29 @@ class ScandirResult {
|
|||||||
DISALLOW_COPY_AND_ASSIGN(ScandirResult);
|
DISALLOW_COPY_AND_ASSIGN(ScandirResult);
|
||||||
};
|
};
|
||||||
|
|
||||||
int scandir(const char* dirname, dirent*** name_list,
|
int scandirat(int parent_fd, const char* dir_name, dirent*** name_list,
|
||||||
int (*filter)(const dirent*),
|
int (*filter)(const dirent*),
|
||||||
int (*comparator)(const dirent**, const dirent**)) {
|
int (*comparator)(const dirent**, const dirent**)) {
|
||||||
ScopedReaddir reader(dirname);
|
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()) {
|
if (reader.IsBad()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScandirResult names;
|
ScandirResult names;
|
||||||
dirent* entry;
|
dirent* entry;
|
||||||
while ((entry = reader.ReadEntry()) != NULL) {
|
while ((entry = reader.ReadEntry()) != nullptr) {
|
||||||
// If we have a filter, skip names that don't match.
|
// If we have a filter, skip names that don't match.
|
||||||
if (filter != NULL && !(*filter)(entry)) {
|
if (filter != nullptr && !(*filter)(entry)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
names.Add(entry);
|
names.Add(entry);
|
||||||
@ -115,4 +127,11 @@ int scandir(const char* dirname, dirent*** name_list,
|
|||||||
*name_list = names.release();
|
*name_list = names.release();
|
||||||
return size;
|
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);
|
__strong_alias(scandir64, scandir);
|
||||||
|
@ -81,8 +81,13 @@ extern long telldir(DIR*);
|
|||||||
extern int dirfd(DIR*);
|
extern int dirfd(DIR*);
|
||||||
extern int alphasort(const struct dirent**, const struct dirent**);
|
extern int alphasort(const struct dirent**, const struct dirent**);
|
||||||
extern int alphasort64(const struct dirent64**, const struct dirent64**);
|
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 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
|
__END_DECLS
|
||||||
|
|
||||||
|
@ -1346,6 +1346,8 @@ LIBC_N {
|
|||||||
preadv64;
|
preadv64;
|
||||||
pwritev;
|
pwritev;
|
||||||
pwritev64;
|
pwritev64;
|
||||||
|
scandirat;
|
||||||
|
scandirat64;
|
||||||
strchrnul;
|
strchrnul;
|
||||||
} LIBC;
|
} LIBC;
|
||||||
|
|
||||||
|
@ -23,8 +23,11 @@
|
|||||||
|
|
||||||
class ScopedReaddir {
|
class ScopedReaddir {
|
||||||
public:
|
public:
|
||||||
ScopedReaddir(const char* path) {
|
ScopedReaddir(const char* path) : ScopedReaddir(opendir(path)) {
|
||||||
dir_ = opendir(path);
|
}
|
||||||
|
|
||||||
|
ScopedReaddir(DIR* dir) {
|
||||||
|
dir_ = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScopedReaddir() {
|
~ScopedReaddir() {
|
||||||
|
@ -81,6 +81,72 @@ TEST(dirent, scandir_scandir64) {
|
|||||||
CheckProcSelf(name_set);
|
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) {
|
TEST(dirent, fdopendir_invalid) {
|
||||||
ASSERT_TRUE(fdopendir(-1) == NULL);
|
ASSERT_TRUE(fdopendir(-1) == NULL);
|
||||||
ASSERT_EQ(EBADF, errno);
|
ASSERT_EQ(EBADF, errno);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user