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