• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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