Home | History | Annotate | Download | only in bionic
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <dirent.h>
     30 
     31 #include <errno.h>
     32 #include <fcntl.h>
     33 #include <sys/stat.h>
     34 #include <sys/types.h>
     35 #include <unistd.h>
     36 
     37 #include "private/ErrnoRestorer.h"
     38 #include "private/ScopedPthreadMutexLocker.h"
     39 
     40 struct DIR {
     41   int fd_;
     42   size_t available_bytes_;
     43   dirent* next_;
     44   pthread_mutex_t mutex_;
     45   dirent buff_[15];
     46 };
     47 
     48 static DIR* __allocate_DIR(int fd) {
     49   DIR* d = reinterpret_cast<DIR*>(malloc(sizeof(DIR)));
     50   if (d == NULL) {
     51     return NULL;
     52   }
     53   d->fd_ = fd;
     54   d->available_bytes_ = 0;
     55   d->next_ = NULL;
     56   pthread_mutex_init(&d->mutex_, NULL);
     57   return d;
     58 }
     59 
     60 int dirfd(DIR* dirp) {
     61   return dirp->fd_;
     62 }
     63 
     64 DIR* fdopendir(int fd) {
     65   // Is 'fd' actually a directory?
     66   struct stat sb;
     67   if (fstat(fd, &sb) == -1) {
     68     return NULL;
     69   }
     70   if (!S_ISDIR(sb.st_mode)) {
     71     errno = ENOTDIR;
     72     return NULL;
     73   }
     74 
     75   return __allocate_DIR(fd);
     76 }
     77 
     78 DIR* opendir(const char* path) {
     79   int fd = open(path, O_RDONLY | O_DIRECTORY);
     80   return (fd != -1) ? __allocate_DIR(fd) : NULL;
     81 }
     82 
     83 static bool __fill_DIR(DIR* d) {
     84   int rc = TEMP_FAILURE_RETRY(getdents(d->fd_, d->buff_, sizeof(d->buff_)));
     85   if (rc <= 0) {
     86     return false;
     87   }
     88   d->available_bytes_ = rc;
     89   d->next_ = d->buff_;
     90   return true;
     91 }
     92 
     93 static dirent* __readdir_locked(DIR* d) {
     94   if (d->available_bytes_ == 0 && !__fill_DIR(d)) {
     95     return NULL;
     96   }
     97 
     98   dirent* entry = d->next_;
     99   d->next_ = reinterpret_cast<dirent*>(reinterpret_cast<char*>(entry) + entry->d_reclen);
    100   d->available_bytes_ -= entry->d_reclen;
    101   return entry;
    102 }
    103 
    104 dirent* readdir(DIR* d) {
    105   ScopedPthreadMutexLocker locker(&d->mutex_);
    106   return __readdir_locked(d);
    107 }
    108 
    109 int readdir_r(DIR* d, dirent* entry, dirent** result) {
    110   ErrnoRestorer errno_restorer;
    111 
    112   *result = NULL;
    113   errno = 0;
    114 
    115   ScopedPthreadMutexLocker locker(&d->mutex_);
    116 
    117   dirent* next = __readdir_locked(d);
    118   if (errno != 0 && next == NULL) {
    119     return errno;
    120   }
    121 
    122   if (next != NULL) {
    123     memcpy(entry, next, next->d_reclen);
    124     *result = entry;
    125   }
    126   return 0;
    127 }
    128 
    129 int closedir(DIR* d) {
    130   if (d == NULL) {
    131     errno = EINVAL;
    132     return -1;
    133   }
    134 
    135   int fd = d->fd_;
    136   pthread_mutex_destroy(&d->mutex_);
    137   free(d);
    138   return close(fd);
    139 }
    140 
    141 void rewinddir(DIR* d) {
    142   ScopedPthreadMutexLocker locker(&d->mutex_);
    143   lseek(d->fd_, 0, SEEK_SET);
    144   d->available_bytes_ = 0;
    145 }
    146 
    147 int alphasort(const dirent** a, const dirent** b) {
    148   return strcoll((*a)->d_name, (*b)->d_name);
    149 }
    150