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 #include <unistd.h> 29 #include <dirent.h> 30 #include <memory.h> 31 #include <string.h> 32 #include <fcntl.h> 33 #include <stdlib.h> 34 #include <pthread.h> 35 #include <errno.h> 36 37 struct DIR 38 { 39 int _DIR_fd; 40 size_t _DIR_avail; 41 struct dirent* _DIR_next; 42 pthread_mutex_t _DIR_lock; 43 struct dirent _DIR_buff[15]; 44 }; 45 46 int dirfd(DIR* dirp) 47 { 48 return dirp->_DIR_fd; 49 } 50 51 DIR* opendir( const char* dirpath ) 52 { 53 DIR* dir = malloc(sizeof(DIR)); 54 55 if (!dir) 56 goto Exit; 57 58 dir->_DIR_fd = open(dirpath, O_RDONLY|O_DIRECTORY); 59 if (dir->_DIR_fd < 0) 60 { 61 free(dir); 62 dir = NULL; 63 } 64 else 65 { 66 dir->_DIR_avail = 0; 67 dir->_DIR_next = NULL; 68 pthread_mutex_init( &dir->_DIR_lock, NULL ); 69 } 70 Exit: 71 return dir; 72 } 73 74 75 DIR* fdopendir(int fd) 76 { 77 DIR* dir = malloc(sizeof(DIR)); 78 79 if (!dir) 80 return 0; 81 82 dir->_DIR_fd = fd; 83 dir->_DIR_avail = 0; 84 dir->_DIR_next = NULL; 85 pthread_mutex_init( &dir->_DIR_lock, NULL ); 86 87 return dir; 88 } 89 90 91 static struct dirent* 92 _readdir_unlocked(DIR* dir) 93 { 94 struct dirent* entry; 95 96 if ( !dir->_DIR_avail ) 97 { 98 int rc; 99 100 for (;;) { 101 rc = getdents( dir->_DIR_fd, dir->_DIR_buff, sizeof(dir->_DIR_buff)); 102 if (rc >= 0 || errno != EINTR) 103 break; 104 } 105 if (rc <= 0) 106 return NULL; 107 108 dir->_DIR_avail = rc; 109 dir->_DIR_next = dir->_DIR_buff; 110 } 111 112 entry = dir->_DIR_next; 113 114 /* perform some sanity checks here */ 115 if (((long)(void*)entry & 3) != 0) 116 return NULL; 117 118 if ( (unsigned)entry->d_reclen > sizeof(*entry) || 119 entry->d_reclen <= offsetof(struct dirent, d_name) ) 120 goto Bad; 121 122 if ( (char*)entry + entry->d_reclen > (char*)dir->_DIR_buff + sizeof(dir->_DIR_buff) ) 123 goto Bad; 124 125 if ( !memchr( entry->d_name, 0, entry->d_reclen - offsetof(struct dirent, d_name)) ) 126 goto Bad; 127 128 dir->_DIR_next = (struct dirent*)((char*)entry + entry->d_reclen); 129 dir->_DIR_avail -= entry->d_reclen; 130 131 return entry; 132 133 Bad: 134 errno = EINVAL; 135 return NULL; 136 } 137 138 139 struct dirent* 140 readdir(DIR * dir) 141 { 142 struct dirent *entry = NULL; 143 144 pthread_mutex_lock( &dir->_DIR_lock ); 145 entry = _readdir_unlocked(dir); 146 pthread_mutex_unlock( &dir->_DIR_lock ); 147 148 return entry; 149 } 150 151 152 int readdir_r(DIR* dir, struct dirent *entry, struct dirent **result) 153 { 154 struct dirent* ent; 155 int save_errno = errno; 156 int retval; 157 158 *result = NULL; 159 errno = 0; 160 161 pthread_mutex_lock( &dir->_DIR_lock ); 162 163 ent = _readdir_unlocked(dir); 164 retval = errno; 165 if (ent == NULL) { 166 if (!retval) { 167 errno = save_errno; 168 } 169 } else { 170 if (!retval) { 171 errno = save_errno; 172 *result = entry; 173 memcpy( entry, ent, ent->d_reclen ); 174 } 175 } 176 177 pthread_mutex_unlock( &dir->_DIR_lock ); 178 179 return retval; 180 } 181 182 183 184 int closedir(DIR *dir) 185 { 186 int rc; 187 188 rc = close(dir->_DIR_fd); 189 dir->_DIR_fd = -1; 190 191 pthread_mutex_destroy( &dir->_DIR_lock ); 192 193 free(dir); 194 return rc; 195 } 196 197 198 void rewinddir(DIR *dir) 199 { 200 pthread_mutex_lock( &dir->_DIR_lock ); 201 lseek( dir->_DIR_fd, 0, SEEK_SET ); 202 dir->_DIR_avail = 0; 203 pthread_mutex_unlock( &dir->_DIR_lock ); 204 } 205 206 207 int alphasort(const void *a, const void *b) 208 { 209 struct dirent **d1, **d2; 210 211 d1 = (struct dirent **) a; 212 d2 = (struct dirent **) b; 213 return strcmp((*d1)->d_name, (*d2)->d_name); 214 } 215 216 217 int scandir(const char *dir, struct dirent ***namelist, 218 int(*filter)(const struct dirent *), 219 int(*compar)(const struct dirent **, const struct dirent **)) 220 { 221 DIR *d; 222 int n_elem = 0; 223 struct dirent *this_de, *de; 224 struct dirent **de_list = NULL; 225 int de_list_size = 0; 226 227 d = opendir(dir); 228 if (d == NULL) { 229 return -1; 230 } 231 232 while ((this_de = readdir(d)) != NULL) { 233 if (filter && (*filter)(this_de) == 0) { 234 continue; 235 } 236 if (n_elem == 0) { 237 de_list_size = 4; 238 de_list = (struct dirent **) 239 malloc(sizeof(struct dirent *)*de_list_size); 240 if (de_list == NULL) { 241 return -1; 242 } 243 } 244 else if (n_elem == de_list_size) { 245 struct dirent **de_list_new; 246 247 de_list_size += 10; 248 de_list_new = (struct dirent **) 249 realloc(de_list, sizeof(struct dirent *)*de_list_size); 250 if (de_list_new == NULL) { 251 free(de_list); 252 return -1; 253 } 254 de_list = de_list_new; 255 } 256 de = (struct dirent *) malloc(sizeof(struct dirent)); 257 *de = *this_de; 258 de_list[n_elem++] = de; 259 } 260 closedir(d); 261 if (n_elem && compar) { 262 qsort(de_list, n_elem, sizeof(struct dirent *), 263 (int (*)(const void *, const void *)) compar); 264 } 265 *namelist = de_list; 266 return n_elem; 267 } 268