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