1063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes/* 2063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * Copyright (C) 2008 The Android Open Source Project 3063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * All rights reserved. 4063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * 5063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * Redistribution and use in source and binary forms, with or without 6063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * modification, are permitted provided that the following conditions 7063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * are met: 8063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * * Redistributions of source code must retain the above copyright 9063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * notice, this list of conditions and the following disclaimer. 10063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * * Redistributions in binary form must reproduce the above copyright 11063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * notice, this list of conditions and the following disclaimer in 12063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * the documentation and/or other materials provided with the 13063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * distribution. 14063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * 15063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes * SUCH DAMAGE. 27063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes */ 28063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 29063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes#include <dirent.h> 30701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughes 31063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes#include <errno.h> 32063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes#include <fcntl.h> 3305fc1d7050d5451aea08dc5f504d2670287b2d43Elliott Hughes#include <malloc.h> 3405fc1d7050d5451aea08dc5f504d2670287b2d43Elliott Hughes#include <string.h> 35063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes#include <sys/stat.h> 36063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes#include <sys/types.h> 37063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes#include <unistd.h> 38063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 393e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes#include "private/ErrnoRestorer.h" 403e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes#include "private/ScopedPthreadMutexLocker.h" 41063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 42d1ead2af8bf2f6bb801da272e3778f89efefe613Elliott Hughesextern "C" int __getdents64(unsigned int, dirent*, unsigned int); 433d5cb30d23cfc6a72f01c00246e69a2c614c8228Elliott Hughes 445edb0f40f654c804d38f1bff43f91719e189c892Christopher Ferris// Apportable decided to copy the data structure from this file 455edb0f40f654c804d38f1bff43f91719e189c892Christopher Ferris// and use it in their own code, but they also call into readdir. 465edb0f40f654c804d38f1bff43f91719e189c892Christopher Ferris// In order to avoid a lockup, the structure must be maintained in 475edb0f40f654c804d38f1bff43f91719e189c892Christopher Ferris// the exact same order as in L and below. New structure members 485edb0f40f654c804d38f1bff43f91719e189c892Christopher Ferris// need to be added to the end of this structure. 495edb0f40f654c804d38f1bff43f91719e189c892Christopher Ferris// See b/21037208 for more details. 50063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughesstruct DIR { 51063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes int fd_; 52063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes size_t available_bytes_; 53063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes dirent* next_; 54063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes pthread_mutex_t mutex_; 55063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes dirent buff_[15]; 565edb0f40f654c804d38f1bff43f91719e189c892Christopher Ferris long current_pos_; 57063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes}; 58063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 59063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughesstatic DIR* __allocate_DIR(int fd) { 60063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes DIR* d = reinterpret_cast<DIR*>(malloc(sizeof(DIR))); 61063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes if (d == NULL) { 62063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return NULL; 63063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes } 64063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes d->fd_ = fd; 65063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes d->available_bytes_ = 0; 66063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes d->next_ = NULL; 675ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui d->current_pos_ = 0L; 68063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes pthread_mutex_init(&d->mutex_, NULL); 69063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return d; 70063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes} 71063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 72063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughesint dirfd(DIR* dirp) { 73063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return dirp->fd_; 74063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes} 75063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 76063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott HughesDIR* fdopendir(int fd) { 77063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes // Is 'fd' actually a directory? 78063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes struct stat sb; 79063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes if (fstat(fd, &sb) == -1) { 80063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return NULL; 81063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes } 82063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes if (!S_ISDIR(sb.st_mode)) { 83063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes errno = ENOTDIR; 84063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return NULL; 85063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes } 86063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 87063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return __allocate_DIR(fd); 88063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes} 89063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 90063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott HughesDIR* opendir(const char* path) { 91f73183f1a34df22b62a3d0bbf82e18d5797c9cdeElliott Hughes int fd = open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY); 92063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return (fd != -1) ? __allocate_DIR(fd) : NULL; 93063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes} 94063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 95063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughesstatic bool __fill_DIR(DIR* d) { 963d5cb30d23cfc6a72f01c00246e69a2c614c8228Elliott Hughes int rc = TEMP_FAILURE_RETRY(__getdents64(d->fd_, d->buff_, sizeof(d->buff_))); 97063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes if (rc <= 0) { 98063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return false; 99063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes } 100063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes d->available_bytes_ = rc; 101063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes d->next_ = d->buff_; 102063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return true; 103063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes} 104063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 105063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughesstatic dirent* __readdir_locked(DIR* d) { 106063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes if (d->available_bytes_ == 0 && !__fill_DIR(d)) { 107063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return NULL; 108063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes } 109063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 110063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes dirent* entry = d->next_; 111063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes d->next_ = reinterpret_cast<dirent*>(reinterpret_cast<char*>(entry) + entry->d_reclen); 112063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes d->available_bytes_ -= entry->d_reclen; 1135ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui // The directory entry offset uses 0, 1, 2 instead of real file offset, 1145ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui // so the value range of long type is enough. 1155ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui d->current_pos_ = static_cast<long>(entry->d_off); 116063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return entry; 117063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes} 118063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 119063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughesdirent* readdir(DIR* d) { 120063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes ScopedPthreadMutexLocker locker(&d->mutex_); 121063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return __readdir_locked(d); 122063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes} 123db1ea3474899ebbd783aba872d3005f95a816d0fElliott Hughes__strong_alias(readdir64, readdir); 124063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 125063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughesint readdir_r(DIR* d, dirent* entry, dirent** result) { 1263e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes ErrnoRestorer errno_restorer; 127063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 128063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes *result = NULL; 129063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes errno = 0; 130063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 131063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes ScopedPthreadMutexLocker locker(&d->mutex_); 132063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 133063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes dirent* next = __readdir_locked(d); 134063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes if (errno != 0 && next == NULL) { 135063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return errno; 136063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes } 137063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 138063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes if (next != NULL) { 139063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes memcpy(entry, next, next->d_reclen); 140063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes *result = entry; 141063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes } 142063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return 0; 143063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes} 144db1ea3474899ebbd783aba872d3005f95a816d0fElliott Hughes__strong_alias(readdir64_r, readdir_r); 145063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 146063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughesint closedir(DIR* d) { 147063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes if (d == NULL) { 148063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes errno = EINVAL; 149063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return -1; 150063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes } 151063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 152063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes int fd = d->fd_; 153063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes pthread_mutex_destroy(&d->mutex_); 154063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes free(d); 155063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes return close(fd); 156063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes} 157063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 158063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughesvoid rewinddir(DIR* d) { 159063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes ScopedPthreadMutexLocker locker(&d->mutex_); 160063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes lseek(d->fd_, 0, SEEK_SET); 161063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes d->available_bytes_ = 0; 1625ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui d->current_pos_ = 0L; 1635ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui} 1645ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui 1655ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cuivoid seekdir(DIR* d, long offset) { 1665ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui ScopedPthreadMutexLocker locker(&d->mutex_); 1675ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui off_t ret = lseek(d->fd_, offset, SEEK_SET); 1685ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui if (ret != -1L) { 1695ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui d->available_bytes_ = 0; 1705ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui d->current_pos_ = ret; 1715ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui } 1725ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui} 1735ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui 1745ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cuilong telldir(DIR* d) { 1755ca4a9e2da46db30ad6d8556b61679d138aaf88dYabin Cui return d->current_pos_; 176063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes} 177063cfb2084ea4b12d3c85b2d2c44e888f0857eb4Elliott Hughes 178701bec2af33feaa9dddf12ccf8e4c714441b7f2eElliott Hughesint alphasort(const dirent** a, const dirent** b) { 179c30396f5f225e0b5a83a35432e2d82a7063cfdb9David 'Digit' Turner return strcoll((*a)->d_name, (*b)->d_name); 180c30396f5f225e0b5a83a35432e2d82a7063cfdb9David 'Digit' Turner} 181db1ea3474899ebbd783aba872d3005f95a816d0fElliott Hughes__strong_alias(alphasort64, alphasort); 182