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