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
_dirScannerInit(DirScanner * s)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
_dirScanner_done(DirScanner * s)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*
dirScanner_next(DirScanner * s)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
_dirScannerInit(DirScanner * s)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
_dirScanner_done(DirScanner * s)110 _dirScanner_done( DirScanner* s )
111 {
112 if (s->dir) {
113 closedir(s->dir);
114 s->dir = NULL;
115 }
116 }
117
118 const char*
dirScanner_next(DirScanner * s)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*
dirScanner_new(const char * rootPath)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
dirScanner_free(DirScanner * s)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*
dirScanner_nextFull(DirScanner * s)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