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 <errno.h> 20#include <stdlib.h> 21 22#include "private/bionic_macros.h" 23#include "private/ScopedReaddir.h" 24 25// A smart pointer to the scandir dirent**. 26class ScandirResult { 27 public: 28 ScandirResult() : names_(NULL), size_(0), capacity_(0) { 29 } 30 31 ~ScandirResult() { 32 while (size_ > 0) { 33 free(names_[--size_]); 34 } 35 free(names_); 36 } 37 38 size_t size() { 39 return size_; 40 } 41 42 dirent** release() { 43 dirent** result = names_; 44 names_ = NULL; 45 size_ = capacity_ = 0; 46 return result; 47 } 48 49 bool Add(dirent* entry) { 50 if (size_ >= capacity_) { 51 size_t new_capacity = capacity_ + 32; 52 dirent** new_names = (dirent**) realloc(names_, new_capacity * sizeof(dirent*)); 53 if (new_names == NULL) { 54 return false; 55 } 56 names_ = new_names; 57 capacity_ = new_capacity; 58 } 59 60 dirent* copy = CopyDirent(entry); 61 if (copy == NULL) { 62 return false; 63 } 64 names_[size_++] = copy; 65 return true; 66 } 67 68 void Sort(int (*comparator)(const dirent**, const dirent**)) { 69 // If we have entries and a comparator, sort them. 70 if (size_ > 0 && comparator != NULL) { 71 qsort(names_, size_, sizeof(dirent*), (int (*)(const void*, const void*)) comparator); 72 } 73 } 74 75 private: 76 dirent** names_; 77 size_t size_; 78 size_t capacity_; 79 80 static dirent* CopyDirent(dirent* original) { 81 // Allocate the minimum number of bytes necessary, rounded up to a 4-byte boundary. 82 size_t size = ((original->d_reclen + 3) & ~3); 83 dirent* copy = (dirent*) malloc(size); 84 memcpy(copy, original, original->d_reclen); 85 return copy; 86 } 87 88 DISALLOW_COPY_AND_ASSIGN(ScandirResult); 89}; 90 91int scandir(const char* dirname, dirent*** name_list, 92 int (*filter)(const dirent*), 93 int (*comparator)(const dirent**, const dirent**)) { 94 ScopedReaddir reader(dirname); 95 if (reader.IsBad()) { 96 return -1; 97 } 98 99 ScandirResult names; 100 dirent* entry; 101 while ((entry = reader.ReadEntry()) != NULL) { 102 // If we have a filter, skip names that don't match. 103 if (filter != NULL && !(*filter)(entry)) { 104 continue; 105 } 106 names.Add(entry); 107 } 108 109 names.Sort(comparator); 110 111 size_t size = names.size(); 112 *name_list = names.release(); 113 return size; 114} 115__strong_alias(scandir64, scandir); 116