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 <malloc.h>
     34 #include <string.h>
     35 #include <sys/stat.h>
     36 #include <sys/types.h>
     37 #include <unistd.h>
     38 
     39 #include "private/ErrnoRestorer.h"
     40 #include "private/ScopedPthreadMutexLocker.h"
     41 
     42 extern "C" int __getdents64(unsigned int, dirent*, unsigned int);
     43 
     44 // Apportable decided to copy the data structure from this file
     45 // and use it in their own code, but they also call into readdir.
     46 // In order to avoid a lockup, the structure must be maintained in
     47 // the exact same order as in L and below. New structure members
     48 // need to be added to the end of this structure.
     49 // See b/21037208 for more details.
     50 struct DIR {
     51   int fd_;
     52   size_t available_bytes_;
     53   dirent* next_;
     54   pthread_mutex_t mutex_;
     55   dirent buff_[15];
     56   long current_pos_;
     57 };
     58 
     59 static DIR* __allocate_DIR(int fd) {
     60   DIR* d = reinterpret_cast<DIR*>(malloc(sizeof(DIR)));
     61   if (d == NULL) {
     62     return NULL;
     63   }
     64   d->fd_ = fd;
     65   d->available_bytes_ = 0;
     66   d->next_ = NULL;
     67   d->current_pos_ = 0L;
     68   pthread_mutex_init(&d->mutex_, NULL);
     69   return d;
     70 }
     71 
     72 int dirfd(DIR* dirp) {
     73   return dirp->fd_;
     74 }
     75 
     76 DIR* fdopendir(int fd) {
     77   // Is 'fd' actually a directory?
     78   struct stat sb;
     79   if (fstat(fd, &sb) == -1) {
     80     return NULL;
     81   }
     82   if (!S_ISDIR(sb.st_mode)) {
     83     errno = ENOTDIR;
     84     return NULL;
     85   }
     86 
     87   return __allocate_DIR(fd);
     88 }
     89 
     90 DIR* opendir(const char* path) {
     91   int fd = open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
     92   return (fd != -1) ? __allocate_DIR(fd) : NULL;
     93 }
     94 
     95 static bool __fill_DIR(DIR* d) {
     96   int rc = TEMP_FAILURE_RETRY(__getdents64(d->fd_, d->buff_, sizeof(d->buff_)));
     97   if (rc <= 0) {
     98     return false;
     99   }
    100   d->available_bytes_ = rc;
    101   d->next_ = d->buff_;
    102   return true;
    103 }
    104 
    105 static dirent* __readdir_locked(DIR* d) {
    106   if (d->available_bytes_ == 0 && !__fill_DIR(d)) {
    107     return NULL;
    108   }
    109 
    110   dirent* entry = d->next_;
    111   d->next_ = reinterpret_cast<dirent*>(reinterpret_cast<char*>(entry) + entry->d_reclen);
    112   d->available_bytes_ -= entry->d_reclen;
    113   // The directory entry offset uses 0, 1, 2 instead of real file offset,
    114   // so the value range of long type is enough.
    115   d->current_pos_ = static_cast<long>(entry->d_off);
    116   return entry;
    117 }
    118 
    119 dirent* readdir(DIR* d) {
    120   ScopedPthreadMutexLocker locker(&d->mutex_);
    121   return __readdir_locked(d);
    122 }
    123 __strong_alias(readdir64, readdir);
    124 
    125 int readdir_r(DIR* d, dirent* entry, dirent** result) {
    126   ErrnoRestorer errno_restorer;
    127 
    128   *result = NULL;
    129   errno = 0;
    130 
    131   ScopedPthreadMutexLocker locker(&d->mutex_);
    132 
    133   dirent* next = __readdir_locked(d);
    134   if (errno != 0 && next == NULL) {
    135     return errno;
    136   }
    137 
    138   if (next != NULL) {
    139     memcpy(entry, next, next->d_reclen);
    140     *result = entry;
    141   }
    142   return 0;
    143 }
    144 __strong_alias(readdir64_r, readdir_r);
    145 
    146 int closedir(DIR* d) {
    147   if (d == NULL) {
    148     errno = EINVAL;
    149     return -1;
    150   }
    151 
    152   int fd = d->fd_;
    153   pthread_mutex_destroy(&d->mutex_);
    154   free(d);
    155   return close(fd);
    156 }
    157 
    158 void rewinddir(DIR* d) {
    159   ScopedPthreadMutexLocker locker(&d->mutex_);
    160   lseek(d->fd_, 0, SEEK_SET);
    161   d->available_bytes_ = 0;
    162   d->current_pos_ = 0L;
    163 }
    164 
    165 void seekdir(DIR* d, long offset) {
    166   ScopedPthreadMutexLocker locker(&d->mutex_);
    167   off_t ret = lseek(d->fd_, offset, SEEK_SET);
    168   if (ret != -1L) {
    169     d->available_bytes_ = 0;
    170     d->current_pos_ = ret;
    171   }
    172 }
    173 
    174 long telldir(DIR* d) {
    175   return d->current_pos_;
    176 }
    177 
    178 int alphasort(const dirent** a, const dirent** b) {
    179   return strcoll((*a)->d_name, (*b)->d_name);
    180 }
    181 __strong_alias(alphasort64, alphasort);
    182