1701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes/*
2701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes * Copyright (C) 2013 The Android Open Source Project
3701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes *
4701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
5701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes * you may not use this file except in compliance with the License.
6701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes * You may obtain a copy of the License at
7701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes *
8701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
9701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes *
10701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes * Unless required by applicable law or agreed to in writing, software
11701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
12701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes * See the License for the specific language governing permissions and
14701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes * limitations under the License.
15701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes */
16701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
17701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes#include <dirent.h>
18701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
19701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes#include <errno.h>
20701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes#include <stdlib.h>
21701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
228eac9af24ea7e570e0b297bcd6ac8a46ba3ecc39Elliott Hughes#include "private/bionic_macros.h"
23701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes#include "private/ScopedReaddir.h"
24701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
25701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes// A smart pointer to the scandir dirent**.
26701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughesclass ScandirResult {
27701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes public:
28701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  ScandirResult() : names_(NULL), size_(0), capacity_(0) {
29701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  }
30701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
31701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  ~ScandirResult() {
32701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    while (size_ > 0) {
33701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes      free(names_[--size_]);
34701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    }
35701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    free(names_);
36701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  }
37701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
38701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  size_t size() {
39701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    return size_;
40701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  }
41701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
42701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  dirent** release() {
43701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    dirent** result = names_;
44701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    names_ = NULL;
45701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    size_ = capacity_ = 0;
46701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    return result;
47701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  }
48701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
49701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  bool Add(dirent* entry) {
50701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    if (size_ >= capacity_) {
51701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes      size_t new_capacity = capacity_ + 32;
52701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes      dirent** new_names = (dirent**) realloc(names_, new_capacity * sizeof(dirent*));
53701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes      if (new_names == NULL) {
54701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes        return false;
55701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes      }
56701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes      names_ = new_names;
57701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes      capacity_ = new_capacity;
58701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    }
59701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
60701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    dirent* copy = CopyDirent(entry);
61701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    if (copy == NULL) {
62701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes      return false;
63701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    }
64701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    names_[size_++] = copy;
65701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    return true;
66701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  }
67701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
68701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  void Sort(int (*comparator)(const dirent**, const dirent**)) {
69701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    // If we have entries and a comparator, sort them.
70701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    if (size_ > 0 && comparator != NULL) {
71701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes      qsort(names_, size_, sizeof(dirent*), (int (*)(const void*, const void*)) comparator);
72701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    }
73701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  }
74701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
75701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes private:
76701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  dirent** names_;
77701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  size_t size_;
78701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  size_t capacity_;
79701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
80701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  static dirent* CopyDirent(dirent* original) {
81701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    // Allocate the minimum number of bytes necessary, rounded up to a 4-byte boundary.
82701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    size_t size = ((original->d_reclen + 3) & ~3);
83701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    dirent* copy = (dirent*) malloc(size);
84701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    memcpy(copy, original, original->d_reclen);
85701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    return copy;
86701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  }
87701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
888eac9af24ea7e570e0b297bcd6ac8a46ba3ecc39Elliott Hughes  DISALLOW_COPY_AND_ASSIGN(ScandirResult);
89701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes};
90701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
91701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughesint scandir(const char* dirname, dirent*** name_list,
92701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes            int (*filter)(const dirent*),
93701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes            int (*comparator)(const dirent**, const dirent**)) {
94701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  ScopedReaddir reader(dirname);
95701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  if (reader.IsBad()) {
96701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    return -1;
97701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  }
98701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
99701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  ScandirResult names;
100701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  dirent* entry;
101701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  while ((entry = reader.ReadEntry()) != NULL) {
102701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    // If we have a filter, skip names that don't match.
103701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    if (filter != NULL && !(*filter)(entry)) {
104701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes      continue;
105701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    }
106701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes    names.Add(entry);
107701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  }
108701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
109701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  names.Sort(comparator);
110701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes
111701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  size_t size = names.size();
112701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  *name_list = names.release();
113701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes  return size;
114701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes}
115db1ea3474899ebbd783aba872d3005f95a816d0fElliott Hughes__strong_alias(scandir64, scandir);
116