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**.
26 class ScandirResult {
27 public:
ScandirResult()28 ScandirResult() : names_(NULL), size_(0), capacity_(0) {
29 }
30
~ScandirResult()31 ~ScandirResult() {
32 while (size_ > 0) {
33 free(names_[--size_]);
34 }
35 free(names_);
36 }
37
size()38 size_t size() {
39 return size_;
40 }
41
release()42 dirent** release() {
43 dirent** result = names_;
44 names_ = NULL;
45 size_ = capacity_ = 0;
46 return result;
47 }
48
Add(dirent * entry)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
Sort(int (* comparator)(const dirent **,const dirent **))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
CopyDirent(dirent * original)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
scandir(const char * dirname,dirent *** name_list,int (* filter)(const dirent *),int (* comparator)(const dirent **,const dirent **))91 int 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