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 "qemu-common.h" 15 #include <stddef.h> 16 17 #define DIRSCANNER_BASE \ 18 char root[PATH_MAX]; \ 19 int rootLen; \ 20 char full[PATH_MAX]; \ 21 22 23 #if _WIN32 24 25 #include <io.h> 26 27 struct DirScanner { 28 DIRSCANNER_BASE 29 intptr_t findIndex1; 30 struct _finddata_t findData; 31 }; 32 33 /* note: findIndex1 contains the find index + 1 34 * so a value of 0 means 'invalid' 35 */ 36 37 static int 38 _dirScannerInit( DirScanner* s ) 39 { 40 char* p = s->root + s->rootLen; 41 char* end = s->root + sizeof s->root; 42 int ret; 43 44 /* create file spec by appending \* to root */ 45 p = bufprint(p, end, "\\*"); 46 if (p >= end) 47 return -1; 48 49 ret = _findfirst(s->root, &s->findData); 50 51 s->findIndex1 = ret+1; 52 return ret; 53 } 54 55 static void 56 _dirScanner_done( DirScanner* s ) 57 { 58 if (s->findIndex1 > 0) { 59 _findclose(s->findIndex1-1); 60 s->findIndex1 = 0; 61 } 62 } 63 64 const char* 65 dirScanner_next( DirScanner* s ) 66 { 67 char* ret = NULL; 68 69 if (!s || s->findIndex1 <= 0) 70 return NULL; 71 72 while (ret == NULL) { 73 ret = s->findData.name; 74 75 /* ignore special directories */ 76 if (!strcmp(ret, ".") || !strcmp(ret, "..")) { 77 ret = NULL; 78 } 79 /* find next one */ 80 if (_findnext(s->findIndex1-1, &s->findData) < 0) { 81 _dirScanner_done(s); 82 break; 83 } 84 } 85 return ret; 86 } 87 88 #else /* !_WIN32 */ 89 90 #include <dirent.h> 91 struct DirScanner { 92 DIRSCANNER_BASE 93 DIR* dir; 94 struct dirent* entry; 95 }; 96 97 static int 98 _dirScannerInit( DirScanner* s ) 99 { 100 s->dir = opendir(s->root); 101 102 if (s->dir == NULL) 103 return -1; 104 105 s->entry = NULL; 106 return 0; 107 } 108 109 static void 110 _dirScanner_done( DirScanner* s ) 111 { 112 if (s->dir) { 113 closedir(s->dir); 114 s->dir = NULL; 115 } 116 } 117 118 const char* 119 dirScanner_next( DirScanner* s ) 120 { 121 char* ret = NULL; 122 123 if (!s || s->dir == NULL) 124 return NULL; 125 126 for (;;) 127 { 128 /* read new entry if needed */ 129 s->entry = readdir(s->dir); 130 if (s->entry == NULL) { 131 _dirScanner_done(s); 132 break; 133 } 134 135 /* ignore special directories */ 136 ret = s->entry->d_name; 137 138 if (!strcmp(ret,".") || !strcmp(ret,"..")) { 139 ret = NULL; 140 continue; 141 } 142 break; 143 } 144 return ret; 145 } 146 147 #endif /* !_WIN32 */ 148 149 DirScanner* 150 dirScanner_new ( const char* rootPath ) 151 { 152 DirScanner* s = qemu_mallocz(sizeof *s); 153 char* p = s->root; 154 char* end = p + sizeof s->root; 155 156 p = bufprint(p, end, "%s", rootPath); 157 if (p >= end) 158 goto FAIL; 159 160 s->rootLen = (p - s->root); 161 162 if (_dirScannerInit(s) < 0) 163 goto FAIL; 164 165 return s; 166 167 FAIL: 168 dirScanner_free(s); 169 return NULL; 170 } 171 172 173 void 174 dirScanner_free( DirScanner* s ) 175 { 176 if (!s) 177 return; 178 179 _dirScanner_done(s); 180 qemu_free(s); 181 } 182 183 184 const char* 185 dirScanner_nextFull( DirScanner* s ) 186 { 187 const char* name = dirScanner_next(s); 188 char* p; 189 char* end; 190 191 if (name == NULL) 192 return NULL; 193 194 p = s->full; 195 end = p + sizeof s->full; 196 197 p = bufprint(p, end, "%.*s/%s", s->rootLen, s->root, name); 198 if (p >= end) { 199 /* ignore if the full name is too long */ 200 return dirScanner_nextFull(s); 201 } 202 return s->full; 203 } 204