1 /* Copyright (C) 2007-2008 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 #include "android/utils/dirscanner.h" 13 #include "android/utils/bufprint.h" 14 #include "android/utils/system.h" 15 #include "android/utils/path.h" 16 #include <stddef.h> 17 18 #define DIRSCANNER_BASE \ 19 char root[PATH_MAX]; \ 20 int rootLen; \ 21 char full[PATH_MAX]; \ 22 23 24 #if _WIN32 25 26 #include <io.h> 27 28 struct DirScanner { 29 DIRSCANNER_BASE 30 intptr_t findIndex1; 31 struct _finddata_t findData; 32 }; 33 34 /* note: findIndex1 contains the find index + 1 35 * so a value of 0 means 'invalid' 36 */ 37 38 static int 39 _dirScannerInit( DirScanner* s ) 40 { 41 char* p = s->root + s->rootLen; 42 char* end = s->root + sizeof s->root; 43 int ret; 44 45 /* create file spec by appending \* to root */ 46 p = bufprint(p, end, "\\*"); 47 if (p >= end) 48 return -1; 49 50 ret = _findfirst(s->root, &s->findData); 51 52 s->findIndex1 = ret+1; 53 return ret; 54 } 55 56 static void 57 _dirScanner_done( DirScanner* s ) 58 { 59 if (s->findIndex1 > 0) { 60 _findclose(s->findIndex1-1); 61 s->findIndex1 = 0; 62 } 63 } 64 65 const char* 66 dirScanner_next( DirScanner* s ) 67 { 68 char* ret = NULL; 69 70 if (!s || s->findIndex1 <= 0) 71 return NULL; 72 73 while (ret == NULL) { 74 ret = s->findData.name; 75 76 /* ignore special directories */ 77 if (!strcmp(ret, ".") || !strcmp(ret, "..")) { 78 ret = NULL; 79 } 80 /* find next one */ 81 if (_findnext(s->findIndex1-1, &s->findData) < 0) { 82 _dirScanner_done(s); 83 break; 84 } 85 } 86 return ret; 87 } 88 89 #else /* !_WIN32 */ 90 91 #include <dirent.h> 92 struct DirScanner { 93 DIRSCANNER_BASE 94 DIR* dir; 95 struct dirent* entry; 96 }; 97 98 static int 99 _dirScannerInit( DirScanner* s ) 100 { 101 s->dir = opendir(s->root); 102 103 if (s->dir == NULL) 104 return -1; 105 106 s->entry = NULL; 107 return 0; 108 } 109 110 static void 111 _dirScanner_done( DirScanner* s ) 112 { 113 if (s->dir) { 114 closedir(s->dir); 115 s->dir = NULL; 116 } 117 } 118 119 const char* 120 dirScanner_next( DirScanner* s ) 121 { 122 char* ret = NULL; 123 124 if (!s || s->dir == NULL) 125 return NULL; 126 127 for (;;) 128 { 129 /* read new entry if needed */ 130 s->entry = readdir(s->dir); 131 if (s->entry == NULL) { 132 _dirScanner_done(s); 133 break; 134 } 135 136 /* ignore special directories */ 137 ret = s->entry->d_name; 138 139 if (!strcmp(ret,".") || !strcmp(ret,"..")) { 140 ret = NULL; 141 continue; 142 } 143 break; 144 } 145 return ret; 146 } 147 148 #endif /* !_WIN32 */ 149 150 DirScanner* 151 dirScanner_new ( const char* rootPath ) 152 { 153 DirScanner* s = android_alloc0(sizeof *s); 154 char* p = s->root; 155 char* end = p + sizeof s->root; 156 157 p = bufprint(p, end, "%s", rootPath); 158 if (p >= end) 159 goto FAIL; 160 161 s->rootLen = (p - s->root); 162 163 if (_dirScannerInit(s) < 0) 164 goto FAIL; 165 166 return s; 167 168 FAIL: 169 dirScanner_free(s); 170 return NULL; 171 } 172 173 174 void 175 dirScanner_free( DirScanner* s ) 176 { 177 if (!s) 178 return; 179 180 _dirScanner_done(s); 181 AFREE(s); 182 } 183 184 185 const char* 186 dirScanner_nextFull( DirScanner* s ) 187 { 188 const char* name = dirScanner_next(s); 189 char* p; 190 char* end; 191 192 if (name == NULL) 193 return NULL; 194 195 p = s->full; 196 end = p + sizeof s->full; 197 198 p = bufprint(p, end, "%.*s/%s", s->rootLen, s->root, name); 199 if (p >= end) { 200 /* ignore if the full name is too long */ 201 return dirScanner_nextFull(s); 202 } 203 return s->full; 204 } 205