1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <dirent.h> 18 19#include <fcntl.h> 20#include <errno.h> 21#include <stdlib.h> 22#include <string.h> 23#include <unistd.h> 24 25#include "private/bionic_macros.h" 26#include "private/ScopedReaddir.h" 27 28// A smart pointer to the scandir dirent**. 29class ScandirResult { 30 public: 31 ScandirResult() : names_(nullptr), size_(0), capacity_(0) { 32 } 33 34 ~ScandirResult() { 35 while (size_ > 0) { 36 free(names_[--size_]); 37 } 38 free(names_); 39 } 40 41 size_t size() { 42 return size_; 43 } 44 45 dirent** release() { 46 dirent** result = names_; 47 names_ = nullptr; 48 size_ = capacity_ = 0; 49 return result; 50 } 51 52 bool Add(dirent* entry) { 53 if (size_ >= capacity_) { 54 size_t new_capacity = capacity_ + 32; 55 dirent** new_names = 56 reinterpret_cast<dirent**>(realloc(names_, new_capacity * sizeof(dirent*))); 57 if (new_names == nullptr) { 58 return false; 59 } 60 names_ = new_names; 61 capacity_ = new_capacity; 62 } 63 64 dirent* copy = CopyDirent(entry); 65 if (copy == nullptr) { 66 return false; 67 } 68 names_[size_++] = copy; 69 return true; 70 } 71 72 void Sort(int (*comparator)(const dirent**, const dirent**)) { 73 // If we have entries and a comparator, sort them. 74 if (size_ > 0 && comparator != nullptr) { 75 qsort(names_, size_, sizeof(dirent*), 76 reinterpret_cast<int (*)(const void*, const void*)>(comparator)); 77 } 78 } 79 80 private: 81 dirent** names_; 82 size_t size_; 83 size_t capacity_; 84 85 static dirent* CopyDirent(dirent* original) { 86 // Allocate the minimum number of bytes necessary, rounded up to a 4-byte boundary. 87 size_t size = ((original->d_reclen + 3) & ~3); 88 dirent* copy = reinterpret_cast<dirent*>(malloc(size)); 89 memcpy(copy, original, original->d_reclen); 90 return copy; 91 } 92 93 DISALLOW_COPY_AND_ASSIGN(ScandirResult); 94}; 95 96int scandirat(int parent_fd, const char* dir_name, dirent*** name_list, 97 int (*filter)(const dirent*), 98 int (*comparator)(const dirent**, const dirent**)) { 99 DIR* dir = nullptr; 100 if (parent_fd == AT_FDCWD) { 101 dir = opendir(dir_name); 102 } else { 103 int dir_fd = openat(parent_fd, dir_name, O_CLOEXEC | O_DIRECTORY | O_RDONLY); 104 if (dir_fd != -1) { 105 dir = fdopendir(dir_fd); 106 } 107 } 108 109 ScopedReaddir reader(dir); 110 if (reader.IsBad()) { 111 return -1; 112 } 113 114 ScandirResult names; 115 dirent* entry; 116 while ((entry = reader.ReadEntry()) != nullptr) { 117 // If we have a filter, skip names that don't match. 118 if (filter != nullptr && !(*filter)(entry)) { 119 continue; 120 } 121 names.Add(entry); 122 } 123 124 names.Sort(comparator); 125 126 size_t size = names.size(); 127 *name_list = names.release(); 128 return size; 129} 130__strong_alias(scandirat64, scandirat); 131 132int scandir(const char* dir_path, dirent*** name_list, 133 int (*filter)(const dirent*), 134 int (*comparator)(const dirent**, const dirent**)) { 135 return scandirat(AT_FDCWD, dir_path, name_list, filter, comparator); 136} 137__strong_alias(scandir64, scandir); 138