Home | History | Annotate | Download | only in bionic
      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:
     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 
     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