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