* commit 'd9cb69881a062c615a8009be0a70270c70eb35da': Reimplement scandir(3).
This commit is contained in:
		@@ -293,6 +293,7 @@ libc_bionic_src_files := \
 | 
			
		||||
    bionic/pthread_sigmask.cpp \
 | 
			
		||||
    bionic/raise.cpp \
 | 
			
		||||
    bionic/sbrk.cpp \
 | 
			
		||||
    bionic/scandir.cpp \
 | 
			
		||||
    bionic/__set_errno.cpp \
 | 
			
		||||
    bionic/setlocale.cpp \
 | 
			
		||||
    bionic/signalfd.cpp \
 | 
			
		||||
 
 | 
			
		||||
@@ -27,11 +27,9 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
@@ -146,51 +144,6 @@ void rewinddir(DIR* d) {
 | 
			
		||||
  d->available_bytes_ = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int scandir(const char* path, dirent*** namelist,
 | 
			
		||||
            int(*filter)(const dirent*),
 | 
			
		||||
            int(*compar)(const dirent**, const dirent**))
 | 
			
		||||
{
 | 
			
		||||
  int n_elem = 0;
 | 
			
		||||
  dirent* this_de, *de;
 | 
			
		||||
  dirent** de_list = NULL;
 | 
			
		||||
  int de_list_size = 0;
 | 
			
		||||
 | 
			
		||||
  DIR* d = opendir(path);
 | 
			
		||||
  if (d == NULL) {
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while ((this_de = readdir(d)) != NULL) {
 | 
			
		||||
    if (filter != NULL && (*filter)(this_de) == 0) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    if (n_elem == 0) {
 | 
			
		||||
      de_list_size = 4;
 | 
			
		||||
      de_list = (dirent**) malloc(sizeof(dirent*) * de_list_size);
 | 
			
		||||
      if (de_list == NULL) {
 | 
			
		||||
        return -1;
 | 
			
		||||
      }
 | 
			
		||||
    } else if (n_elem == de_list_size) {
 | 
			
		||||
      de_list_size += 10;
 | 
			
		||||
      dirent** de_list_new = (dirent**) realloc(de_list, sizeof(dirent*) * de_list_size);
 | 
			
		||||
      if (de_list_new == NULL) {
 | 
			
		||||
        free(de_list);
 | 
			
		||||
        return -1;
 | 
			
		||||
      }
 | 
			
		||||
      de_list = de_list_new;
 | 
			
		||||
    }
 | 
			
		||||
    de = (dirent*) malloc(sizeof(dirent));
 | 
			
		||||
    *de = *this_de;
 | 
			
		||||
    de_list[n_elem++] = de;
 | 
			
		||||
  }
 | 
			
		||||
  closedir(d);
 | 
			
		||||
  if (n_elem && compar) {
 | 
			
		||||
    qsort(de_list, n_elem, sizeof(dirent*), (int (*)(const void*, const void*)) compar);
 | 
			
		||||
  }
 | 
			
		||||
  *namelist = de_list;
 | 
			
		||||
  return n_elem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int alphasort(const struct dirent** a, const struct dirent** b) {
 | 
			
		||||
int alphasort(const dirent** a, const dirent** b) {
 | 
			
		||||
  return strcoll((*a)->d_name, (*b)->d_name);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										115
									
								
								libc/bionic/scandir.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								libc/bionic/scandir.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2013 The Android Open Source Project
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include "private/ScopedReaddir.h"
 | 
			
		||||
 | 
			
		||||
// A smart pointer to the scandir dirent**.
 | 
			
		||||
class ScandirResult {
 | 
			
		||||
 public:
 | 
			
		||||
  ScandirResult() : names_(NULL), size_(0), capacity_(0) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ~ScandirResult() {
 | 
			
		||||
    while (size_ > 0) {
 | 
			
		||||
      free(names_[--size_]);
 | 
			
		||||
    }
 | 
			
		||||
    free(names_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t size() {
 | 
			
		||||
    return size_;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  dirent** release() {
 | 
			
		||||
    dirent** result = names_;
 | 
			
		||||
    names_ = NULL;
 | 
			
		||||
    size_ = capacity_ = 0;
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool Add(dirent* entry) {
 | 
			
		||||
    if (size_ >= capacity_) {
 | 
			
		||||
      size_t new_capacity = capacity_ + 32;
 | 
			
		||||
      dirent** new_names = (dirent**) realloc(names_, new_capacity * sizeof(dirent*));
 | 
			
		||||
      if (new_names == NULL) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
      names_ = new_names;
 | 
			
		||||
      capacity_ = new_capacity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dirent* copy = CopyDirent(entry);
 | 
			
		||||
    if (copy == NULL) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    names_[size_++] = copy;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Sort(int (*comparator)(const dirent**, const dirent**)) {
 | 
			
		||||
    // If we have entries and a comparator, sort them.
 | 
			
		||||
    if (size_ > 0 && comparator != NULL) {
 | 
			
		||||
      qsort(names_, size_, sizeof(dirent*), (int (*)(const void*, const void*)) comparator);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  dirent** names_;
 | 
			
		||||
  size_t size_;
 | 
			
		||||
  size_t capacity_;
 | 
			
		||||
 | 
			
		||||
  static dirent* CopyDirent(dirent* original) {
 | 
			
		||||
    // Allocate the minimum number of bytes necessary, rounded up to a 4-byte boundary.
 | 
			
		||||
    size_t size = ((original->d_reclen + 3) & ~3);
 | 
			
		||||
    dirent* copy = (dirent*) malloc(size);
 | 
			
		||||
    memcpy(copy, original, original->d_reclen);
 | 
			
		||||
    return copy;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Disallow copy and assignment.
 | 
			
		||||
  ScandirResult(const ScandirResult&);
 | 
			
		||||
  void operator=(const ScandirResult&);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int scandir(const char* dirname, dirent*** name_list,
 | 
			
		||||
            int (*filter)(const dirent*),
 | 
			
		||||
            int (*comparator)(const dirent**, const dirent**)) {
 | 
			
		||||
  ScopedReaddir reader(dirname);
 | 
			
		||||
  if (reader.IsBad()) {
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ScandirResult names;
 | 
			
		||||
  dirent* entry;
 | 
			
		||||
  while ((entry = reader.ReadEntry()) != NULL) {
 | 
			
		||||
    // If we have a filter, skip names that don't match.
 | 
			
		||||
    if (filter != NULL && !(*filter)(entry)) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    names.Add(entry);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  names.Sort(comparator);
 | 
			
		||||
 | 
			
		||||
  size_t size = names.size();
 | 
			
		||||
  *name_list = names.release();
 | 
			
		||||
  return size;
 | 
			
		||||
}
 | 
			
		||||
@@ -39,6 +39,8 @@
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include "private/ScopedReaddir.h"
 | 
			
		||||
 | 
			
		||||
/* seems to be the default on Linux, per the GLibc sources and my own digging */
 | 
			
		||||
 | 
			
		||||
#define  SYSTEM_CLK_TCK         100
 | 
			
		||||
@@ -78,19 +80,18 @@ static bool __matches_cpuN(const char* s) {
 | 
			
		||||
static int __sysconf_nprocessors_conf() {
 | 
			
		||||
  // On x86 kernels you can use /proc/cpuinfo for this, but on ARM kernels offline CPUs disappear
 | 
			
		||||
  // from there. This method works on both.
 | 
			
		||||
  DIR* d = opendir("/sys/devices/system/cpu");
 | 
			
		||||
  if (!d) {
 | 
			
		||||
  ScopedReaddir reader("/sys/devices/system/cpu");
 | 
			
		||||
  if (reader.IsBad()) {
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int result = 0;
 | 
			
		||||
  struct dirent* e;
 | 
			
		||||
  while ((e = readdir(d)) != NULL) {
 | 
			
		||||
    if (e->d_type == DT_DIR && __matches_cpuN(e->d_name)) {
 | 
			
		||||
  dirent* entry;
 | 
			
		||||
  while ((entry = reader.ReadEntry()) != NULL) {
 | 
			
		||||
    if (entry->d_type == DT_DIR && __matches_cpuN(entry->d_name)) {
 | 
			
		||||
      ++result;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  closedir(d);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										50
									
								
								libc/private/ScopedReaddir.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								libc/private/ScopedReaddir.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2013 The Android Open Source Project
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SCOPED_READDIR_H
 | 
			
		||||
#define SCOPED_READDIR_H
 | 
			
		||||
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
 | 
			
		||||
class ScopedReaddir {
 | 
			
		||||
 public:
 | 
			
		||||
  ScopedReaddir(const char* path) {
 | 
			
		||||
    dir_ = opendir(path);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ~ScopedReaddir() {
 | 
			
		||||
    if (dir_ != NULL) {
 | 
			
		||||
      closedir(dir_);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool IsBad() {
 | 
			
		||||
    return dir_ == NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  dirent* ReadEntry() {
 | 
			
		||||
    return readdir(dir_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  DIR* dir_;
 | 
			
		||||
 | 
			
		||||
  // Disallow copy and assignment.
 | 
			
		||||
  ScopedReaddir(const ScopedReaddir&);
 | 
			
		||||
  void operator=(const ScopedReaddir&);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // SCOPED_READDIR_H
 | 
			
		||||
		Reference in New Issue
	
	Block a user