2013-02-25 22:14:31 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2013 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <dirent.h>
|
|
|
|
|
2015-10-27 19:10:36 +01:00
|
|
|
#include <fcntl.h>
|
2013-02-25 22:14:31 +01:00
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
2015-01-26 22:34:58 +01:00
|
|
|
#include <string.h>
|
2015-10-27 19:10:36 +01:00
|
|
|
#include <unistd.h>
|
2013-02-25 22:14:31 +01:00
|
|
|
|
2014-05-10 04:12:08 +02:00
|
|
|
#include "private/bionic_macros.h"
|
2013-02-25 22:14:31 +01:00
|
|
|
#include "private/ScopedReaddir.h"
|
|
|
|
|
|
|
|
// A smart pointer to the scandir dirent**.
|
|
|
|
class ScandirResult {
|
|
|
|
public:
|
2015-10-27 19:10:36 +01:00
|
|
|
ScandirResult() : names_(nullptr), size_(0), capacity_(0) {
|
2013-02-25 22:14:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
~ScandirResult() {
|
|
|
|
while (size_ > 0) {
|
|
|
|
free(names_[--size_]);
|
|
|
|
}
|
|
|
|
free(names_);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t size() {
|
|
|
|
return size_;
|
|
|
|
}
|
|
|
|
|
|
|
|
dirent** release() {
|
|
|
|
dirent** result = names_;
|
2015-10-27 19:10:36 +01:00
|
|
|
names_ = nullptr;
|
2013-02-25 22:14:31 +01:00
|
|
|
size_ = capacity_ = 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Add(dirent* entry) {
|
|
|
|
if (size_ >= capacity_) {
|
|
|
|
size_t new_capacity = capacity_ + 32;
|
2015-01-22 01:19:07 +01:00
|
|
|
dirent** new_names =
|
|
|
|
reinterpret_cast<dirent**>(realloc(names_, new_capacity * sizeof(dirent*)));
|
2015-10-27 19:10:36 +01:00
|
|
|
if (new_names == nullptr) {
|
2013-02-25 22:14:31 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
names_ = new_names;
|
|
|
|
capacity_ = new_capacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
dirent* copy = CopyDirent(entry);
|
2015-10-27 19:10:36 +01:00
|
|
|
if (copy == nullptr) {
|
2013-02-25 22:14:31 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
names_[size_++] = copy;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sort(int (*comparator)(const dirent**, const dirent**)) {
|
|
|
|
// If we have entries and a comparator, sort them.
|
2015-10-27 19:10:36 +01:00
|
|
|
if (size_ > 0 && comparator != nullptr) {
|
2015-01-22 01:19:07 +01:00
|
|
|
qsort(names_, size_, sizeof(dirent*),
|
|
|
|
reinterpret_cast<int (*)(const void*, const void*)>(comparator));
|
2013-02-25 22:14:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
dirent** names_;
|
|
|
|
size_t size_;
|
|
|
|
size_t capacity_;
|
|
|
|
|
|
|
|
static dirent* CopyDirent(dirent* original) {
|
|
|
|
// Allocate the minimum number of bytes necessary, rounded up to a 4-byte boundary.
|
|
|
|
size_t size = ((original->d_reclen + 3) & ~3);
|
2015-01-22 01:19:07 +01:00
|
|
|
dirent* copy = reinterpret_cast<dirent*>(malloc(size));
|
2013-02-25 22:14:31 +01:00
|
|
|
memcpy(copy, original, original->d_reclen);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2014-05-10 04:12:08 +02:00
|
|
|
DISALLOW_COPY_AND_ASSIGN(ScandirResult);
|
2013-02-25 22:14:31 +01:00
|
|
|
};
|
|
|
|
|
2015-10-27 19:10:36 +01:00
|
|
|
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);
|
2013-02-25 22:14:31 +01:00
|
|
|
if (reader.IsBad()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScandirResult names;
|
|
|
|
dirent* entry;
|
2015-10-27 19:10:36 +01:00
|
|
|
while ((entry = reader.ReadEntry()) != nullptr) {
|
2013-02-25 22:14:31 +01:00
|
|
|
// If we have a filter, skip names that don't match.
|
2015-10-27 19:10:36 +01:00
|
|
|
if (filter != nullptr && !(*filter)(entry)) {
|
2013-02-25 22:14:31 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
names.Add(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
names.Sort(comparator);
|
|
|
|
|
|
|
|
size_t size = names.size();
|
|
|
|
*name_list = names.release();
|
|
|
|
return size;
|
|
|
|
}
|
2015-10-27 19:10:36 +01:00
|
|
|
__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);
|
|
|
|
}
|
Implement some of the missing LFS64 support.
This gives us:
* <dirent.h>
struct dirent64
readdir64, readdir64_r, alphasort64, scandir64
* <fcntl.h>
creat64, openat64, open64.
* <sys/stat.h>
struct stat64
fstat64, fstatat64, lstat64, stat64.
* <sys/statvfs.h>
struct statvfs64
statvfs64, fstatvfs64.
* <sys/vfs.h>
struct statfs64
statfs64, fstatfs64.
This also removes some of the incorrect #define hacks we've had in the
past (for stat64, for example, which we promised to clean up way back
in bug 8472078).
Bug: 11865851
Bug: 8472078
Change-Id: Ia46443521918519f2dfa64d4621027dfd13ac566
2014-01-18 03:42:49 +01:00
|
|
|
__strong_alias(scandir64, scandir);
|