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