OSDN Git Service

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