diff options
author | Amaury Pouly <pamaury@rockbox.org> | 2010-02-14 19:09:52 +0000 |
---|---|---|
committer | Amaury Pouly <pamaury@rockbox.org> | 2010-02-14 19:09:52 +0000 |
commit | 26c0e753d1e19747719dbcae8dc6e84a0a74671a (patch) | |
tree | e6ad178bebc9f47e2439cfd8394e686c1317bb5c /firmware/common/dircache.c | |
parent | e1d8c3ef7c305c94e3de486adb41696ccc18a883 (diff) | |
download | rockbox-26c0e753d1e19747719dbcae8dc6e84a0a74671a.tar.gz rockbox-26c0e753d1e19747719dbcae8dc6e84a0a74671a.zip |
Rewrite dircache generation to take advantage for the FAT code. Reduce RAM usage by ~30Kb and binsize by at least several hundreds bytes. Also remove the directory depth limit of dircache.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24657 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/common/dircache.c')
-rw-r--r-- | firmware/common/dircache.c | 379 |
1 files changed, 182 insertions, 197 deletions
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index 66189c48a8..e6107801c3 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c | |||
@@ -71,7 +71,6 @@ static unsigned long entry_count = 0; | |||
71 | static unsigned long reserve_used = 0; | 71 | static unsigned long reserve_used = 0; |
72 | static unsigned int cache_build_ticks = 0; | 72 | static unsigned int cache_build_ticks = 0; |
73 | static unsigned long appflags = 0; | 73 | static unsigned long appflags = 0; |
74 | static char dircache_cur_path[MAX_PATH]; | ||
75 | 74 | ||
76 | static struct event_queue dircache_queue; | 75 | static struct event_queue dircache_queue; |
77 | static long dircache_stack[(DEFAULT_STACK_SIZE + 0x900)/sizeof(long)]; | 76 | static long dircache_stack[(DEFAULT_STACK_SIZE + 0x900)/sizeof(long)]; |
@@ -147,11 +146,6 @@ static struct dircache_entry* dircache_gen_down(struct dircache_entry *ce) | |||
147 | return next_entry; | 146 | return next_entry; |
148 | } | 147 | } |
149 | 148 | ||
150 | /* This will eat ~30 KiB of memory! | ||
151 | * We should probably use that as additional reserve buffer in future. */ | ||
152 | #define MAX_SCAN_DEPTH 16 | ||
153 | static struct travel_data dir_recursion[MAX_SCAN_DEPTH]; | ||
154 | |||
155 | /** | 149 | /** |
156 | * Returns true if there is an event waiting in the queue | 150 | * Returns true if there is an event waiting in the queue |
157 | * that requires the current operation to be aborted. | 151 | * that requires the current operation to be aborted. |
@@ -176,130 +170,111 @@ static bool check_event_queue(void) | |||
176 | return false; | 170 | return false; |
177 | } | 171 | } |
178 | 172 | ||
179 | /** | 173 | #ifndef SIMULATOR |
180 | * Internal function to iterate a path. | 174 | /* scan and build static data (avoid redundancy on stack) */ |
181 | */ | 175 | static struct |
182 | static int dircache_scan(IF_MV2(int volume,) struct travel_data *td) | ||
183 | { | 176 | { |
184 | #ifdef SIMULATOR | ||
185 | #ifdef HAVE_MULTIVOLUME | 177 | #ifdef HAVE_MULTIVOLUME |
186 | (void)volume; | 178 | int volume; |
187 | #endif | ||
188 | while ( ( td->entry = readdir_uncached(td->dir) ) ) | ||
189 | #else | ||
190 | while ( (fat_getnext(td->dir, &td->entry) >= 0) && (td->entry.name[0])) | ||
191 | #endif | 179 | #endif |
180 | struct fat_dir *dir; | ||
181 | struct fat_direntry *direntry; | ||
182 | }sab; | ||
183 | |||
184 | static int sab_process_dir(unsigned long startcluster, struct dircache_entry *ce) | ||
185 | { | ||
186 | /* normally, opendir expects a full fat_dir as parent but in our case, | ||
187 | * it's completely useless because we don't modify anything | ||
188 | * WARNING: this heavily relies on current FAT implementation ! */ | ||
189 | |||
190 | /* those field are necessary to update the FAT entry in case of modification | ||
191 | here we don't touch anything so we put dummy values */ | ||
192 | sab.dir->entry = 0; | ||
193 | sab.dir->entrycount = 0; | ||
194 | sab.dir->file.firstcluster = 0; | ||
195 | /* open directory */ | ||
196 | int rc = fat_opendir(IF_MV2(sab.volume,) sab.dir, startcluster, sab.dir); | ||
197 | if(rc < 0) | ||
192 | { | 198 | { |
193 | #ifdef SIMULATOR | 199 | logf("fat_opendir failed: %d", rc); |
194 | if (!strcmp(".", td->entry->d_name) || | 200 | return rc; |
195 | !strcmp("..", td->entry->d_name)) | 201 | } |
196 | { | 202 | |
203 | /* first pass : read dir */ | ||
204 | struct dircache_entry *first_ce = ce; | ||
205 | |||
206 | /* read through directory */ | ||
207 | while((rc = fat_getnext(sab.dir, sab.direntry)) >= 0 && sab.direntry->name[0]) | ||
208 | { | ||
209 | if(!strcmp(".", sab.direntry->name) || | ||
210 | !strcmp("..", sab.direntry->name)) | ||
197 | continue; | 211 | continue; |
198 | } | ||
199 | 212 | ||
200 | td->ce->attribute = td->entry->attribute; | 213 | ce->attribute = sab.direntry->attr; |
201 | td->ce->name_len = strlen(td->entry->d_name) + 1; | 214 | ce->name_len = strlen(sab.direntry->name) + 1; |
202 | td->ce->d_name = ((char *)dircache_root+dircache_size); | 215 | ce->d_name = ((char *)dircache_root + dircache_size); |
203 | td->ce->size = td->entry->size; | 216 | ce->startcluster = sab.direntry->firstcluster; |
204 | td->ce->wrtdate = td->entry->wrtdate; | 217 | ce->size = sab.direntry->filesize; |
205 | td->ce->wrttime = td->entry->wrttime; | 218 | ce->wrtdate = sab.direntry->wrtdate; |
206 | memcpy(td->ce->d_name, td->entry->d_name, td->ce->name_len); | 219 | ce->wrttime = sab.direntry->wrttime; |
207 | #else | 220 | memcpy(ce->d_name, sab.direntry->name, ce->name_len); |
208 | if (!strcmp(".", td->entry.name) || | ||
209 | !strcmp("..", td->entry.name)) | ||
210 | { | ||
211 | continue; | ||
212 | } | ||
213 | 221 | ||
214 | td->ce->attribute = td->entry.attr; | 222 | dircache_size += ce->name_len; |
215 | td->ce->name_len = strlen(td->entry.name) + 1; | ||
216 | td->ce->d_name = ((char *)dircache_root+dircache_size); | ||
217 | td->ce->startcluster = td->entry.firstcluster; | ||
218 | td->ce->size = td->entry.filesize; | ||
219 | td->ce->wrtdate = td->entry.wrtdate; | ||
220 | td->ce->wrttime = td->entry.wrttime; | ||
221 | memcpy(td->ce->d_name, td->entry.name, td->ce->name_len); | ||
222 | #endif | ||
223 | dircache_size += td->ce->name_len; | ||
224 | entry_count++; | 223 | entry_count++; |
225 | 224 | ||
226 | #ifdef SIMULATOR | 225 | if(ce->attribute & FAT_ATTR_DIRECTORY) |
227 | if (td->entry->attribute & ATTR_DIRECTORY) | 226 | dircache_gen_down(ce); |
228 | #else | 227 | |
229 | if (td->entry.attr & FAT_ATTR_DIRECTORY) | 228 | ce = dircache_gen_next(ce); |
230 | #endif | 229 | if(ce == NULL) |
231 | { | ||
232 | |||
233 | td->down_entry = dircache_gen_down(td->ce); | ||
234 | if (td->down_entry == NULL) | ||
235 | return -2; | ||
236 | |||
237 | td->pathpos = strlen(dircache_cur_path); | ||
238 | strlcpy(&dircache_cur_path[td->pathpos], "/", | ||
239 | sizeof(dircache_cur_path) - td->pathpos); | ||
240 | #ifdef SIMULATOR | ||
241 | strlcpy(&dircache_cur_path[td->pathpos+1], td->entry->d_name, | ||
242 | sizeof(dircache_cur_path) - td->pathpos - 1); | ||
243 | |||
244 | td->newdir = opendir_uncached(dircache_cur_path); | ||
245 | if (td->newdir == NULL) | ||
246 | { | ||
247 | logf("Failed to opendir_uncached(): %s", dircache_cur_path); | ||
248 | return -3; | ||
249 | } | ||
250 | #else | ||
251 | strlcpy(&dircache_cur_path[td->pathpos+1], td->entry.name, | ||
252 | sizeof(dircache_cur_path) - td->pathpos - 1); | ||
253 | |||
254 | td->newdir = *td->dir; | ||
255 | if (fat_opendir(IF_MV2(volume,) &td->newdir, | ||
256 | td->entry.firstcluster, td->dir) < 0 ) | ||
257 | { | ||
258 | return -3; | ||
259 | } | ||
260 | #endif | ||
261 | |||
262 | td->ce = dircache_gen_next(td->ce); | ||
263 | if (td->ce == NULL) | ||
264 | return -4; | ||
265 | |||
266 | return 1; | ||
267 | } | ||
268 | |||
269 | td->ce->down = NULL; | ||
270 | td->ce = dircache_gen_next(td->ce); | ||
271 | if (td->ce == NULL) | ||
272 | return -5; | 230 | return -5; |
273 | 231 | ||
274 | /* When simulator is used, it's only safe to yield here. */ | 232 | /* When simulator is used, it's only safe to yield here. */ |
275 | if (thread_enabled) | 233 | if(thread_enabled) |
276 | { | 234 | { |
277 | /* Stop if we got an external signal. */ | 235 | /* Stop if we got an external signal. */ |
278 | if (check_event_queue()) | 236 | if(check_event_queue()) |
279 | return -6; | 237 | return -6; |
280 | yield(); | 238 | yield(); |
281 | } | 239 | } |
240 | } | ||
241 | |||
242 | /* add "." and ".." */ | ||
243 | ce->d_name = "."; | ||
244 | ce->name_len = 2; | ||
245 | ce->attribute = FAT_ATTR_DIRECTORY; | ||
246 | ce->startcluster = startcluster; | ||
247 | ce->size = 0; | ||
248 | ce->down = first_ce; | ||
249 | |||
250 | ce = dircache_gen_next(ce); | ||
251 | |||
252 | ce->d_name = ".."; | ||
253 | ce->name_len = 3; | ||
254 | ce->attribute = FAT_ATTR_DIRECTORY; | ||
255 | ce->startcluster = first_ce->up->startcluster; | ||
256 | ce->size = 0; | ||
257 | ce->down = first_ce->up; | ||
258 | |||
259 | /* second pass: recurse ! */ | ||
260 | ce = first_ce; | ||
261 | |||
262 | while(ce) | ||
263 | { | ||
264 | if(ce->name_len != 0 && ce->down != NULL && strcmp(ce->d_name, ".") && strcmp(ce->d_name, "..")) | ||
265 | sab_process_dir(ce->startcluster, ce->down); | ||
282 | 266 | ||
267 | ce = ce->next; | ||
283 | } | 268 | } |
284 | 269 | ||
285 | return 0; | 270 | return rc; |
286 | } | 271 | } |
287 | 272 | ||
288 | /** | 273 | static int dircache_scan_and_build(IF_MV2(int volume,) struct dircache_entry *ce) |
289 | * Recursively scan the hard disk and build the cache. | ||
290 | */ | ||
291 | #ifdef SIMULATOR | ||
292 | static int dircache_travel(IF_MV2(int volume,) DIR_UNCACHED *dir, struct dircache_entry *ce) | ||
293 | #else | ||
294 | static int dircache_travel(IF_MV2(int volume,) struct fat_dir *dir, struct dircache_entry *ce) | ||
295 | #endif | ||
296 | { | 274 | { |
297 | int depth = 0; | ||
298 | int result; | ||
299 | |||
300 | memset(ce, 0, sizeof(struct dircache_entry)); | 275 | memset(ce, 0, sizeof(struct dircache_entry)); |
301 | 276 | ||
302 | #if defined(HAVE_MULTIVOLUME) && !defined(SIMULATOR) | 277 | #ifdef HAVE_MULTIVOLUME |
303 | if (volume > 0) | 278 | if (volume > 0) |
304 | { | 279 | { |
305 | ce->d_name = ((char *)dircache_root+dircache_size); | 280 | ce->d_name = ((char *)dircache_root+dircache_size); |
@@ -313,81 +288,117 @@ static int dircache_travel(IF_MV2(int volume,) struct fat_dir *dir, struct dirca | |||
313 | } | 288 | } |
314 | #endif | 289 | #endif |
315 | 290 | ||
316 | dir_recursion[0].dir = dir; | 291 | struct fat_dir dir; /* allocate on stack once for all scan */ |
317 | dir_recursion[0].ce = ce; | 292 | struct fat_direntry direntry; /* ditto */ |
318 | dir_recursion[0].first = ce; | 293 | #ifdef HAVE_MULTIVOLUME |
319 | 294 | sab.volume = volume; | |
320 | do { | ||
321 | //logf("=> %s", dircache_cur_path); | ||
322 | result = dircache_scan(IF_MV2(volume,) &dir_recursion[depth]); | ||
323 | switch (result) { | ||
324 | case 0: /* Leaving the current directory. */ | ||
325 | /* Add the standard . and .. entries. */ | ||
326 | ce = dir_recursion[depth].ce; | ||
327 | ce->d_name = "."; | ||
328 | ce->name_len = 2; | ||
329 | #ifdef SIMULATOR | ||
330 | closedir_uncached(dir_recursion[depth].dir); | ||
331 | ce->attribute = ATTR_DIRECTORY; | ||
332 | #else | ||
333 | ce->attribute = FAT_ATTR_DIRECTORY; | ||
334 | ce->startcluster = dir_recursion[depth].dir->file.firstcluster; | ||
335 | #endif | 295 | #endif |
336 | ce->size = 0; | 296 | sab.dir = &dir; |
337 | ce->down = dir_recursion[depth].first; | 297 | sab.direntry = &direntry; |
338 | 298 | ||
339 | depth--; | 299 | return sab_process_dir(0, ce); |
340 | if (depth < 0) | 300 | } |
341 | break ; | 301 | #else /* !SIMULATOR */ |
302 | static char sab_path[MAX_PATH]; | ||
342 | 303 | ||
343 | dircache_cur_path[dir_recursion[depth].pathpos] = '\0'; | 304 | static int sab_process_dir(struct dircache_entry *ce) |
344 | 305 | { | |
345 | ce = dircache_gen_next(ce); | 306 | struct dirent_uncached *entry; |
346 | if (ce == NULL) | 307 | struct dircache_entry *first_ce = ce; |
347 | { | 308 | DIR_UNCACHED *dir = opendir_uncached(sab_path); |
348 | logf("memory allocation error"); | 309 | if(dir == NULL) |
349 | return -3; | 310 | { |
350 | } | 311 | logf("Failed to opendir_uncached(%s)", sab_path); |
351 | #ifdef SIMULATOR | 312 | return -1; |
352 | ce->attribute = ATTR_DIRECTORY; | 313 | } |
353 | #else | ||
354 | ce->attribute = FAT_ATTR_DIRECTORY; | ||
355 | ce->startcluster = dir_recursion[depth].dir->file.firstcluster; | ||
356 | #endif | ||
357 | ce->d_name = ".."; | ||
358 | ce->name_len = 3; | ||
359 | ce->size = 0; | ||
360 | ce->down = dir_recursion[depth].first; | ||
361 | 314 | ||
362 | break ; | 315 | while((entry = readdir_uncached(dir))) |
363 | 316 | { | |
364 | case 1: /* Going down in the directory tree. */ | 317 | if(!strcmp(".", entry->d_name) || |
365 | depth++; | 318 | !strcmp("..", entry->d_name)) |
366 | if (depth >= MAX_SCAN_DEPTH) | 319 | continue; |
367 | { | 320 | |
368 | logf("Too deep directory structure"); | 321 | ce->attribute = entry->attribute; |
369 | return -2; | 322 | ce->name_len = strlen(entry->d_name) + 1; |
370 | } | 323 | ce->d_name = ((char *)dircache_root + dircache_size); |
324 | ce->size = entry->size; | ||
325 | ce->wrtdate = entry->wrtdate; | ||
326 | ce->wrttime = entry->wrttime; | ||
327 | memcpy(ce->d_name, entry->d_name, ce->name_len); | ||
328 | |||
329 | dircache_size += ce->name_len; | ||
330 | entry_count++; | ||
331 | |||
332 | if(entry->attribute & ATTR_DIRECTORY) | ||
333 | { | ||
334 | dircache_gen_down(ce); | ||
335 | if(ce->down == NULL) | ||
336 | { | ||
337 | closedir_uncached(dir); | ||
338 | return -1; | ||
339 | } | ||
340 | /* save current paths size */ | ||
341 | int pathpos = strlen(sab_path); | ||
342 | /* append entry */ | ||
343 | strlcpy(&sab_path[pathpos], "/", sizeof(sab_path) - pathpos); | ||
344 | strlcpy(&sab_path[pathpos+1], entry->d_name, sizeof(sab_path) - pathpos - 1); | ||
371 | 345 | ||
372 | #ifdef SIMULATOR | 346 | int rc = sab_process_dir(ce->down); |
373 | dir_recursion[depth].dir = dir_recursion[depth-1].newdir; | 347 | /* restore path */ |
374 | #else | 348 | sab_path[pathpos] = '\0'; |
375 | dir_recursion[depth].dir = &dir_recursion[depth-1].newdir; | ||
376 | #endif | ||
377 | dir_recursion[depth].first = dir_recursion[depth-1].down_entry; | ||
378 | dir_recursion[depth].ce = dir_recursion[depth-1].down_entry; | ||
379 | break ; | ||
380 | 349 | ||
381 | default: | 350 | if(rc < 0) |
382 | logf("Scan failed"); | 351 | { |
383 | logf("-> %s", dircache_cur_path); | 352 | closedir_uncached(dir); |
353 | return rc; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | ce = dircache_gen_next(ce); | ||
358 | if(ce == NULL) | ||
359 | return -5; | ||
360 | |||
361 | /* When simulator is used, it's only safe to yield here. */ | ||
362 | if(thread_enabled) | ||
363 | { | ||
364 | /* Stop if we got an external signal. */ | ||
365 | if(check_event_queue()) | ||
384 | return -1; | 366 | return -1; |
367 | yield(); | ||
385 | } | 368 | } |
386 | } while (depth >= 0) ; | 369 | } |
370 | |||
371 | /* add "." and ".." */ | ||
372 | ce->d_name = "."; | ||
373 | ce->name_len = 2; | ||
374 | ce->attribute = ATTR_DIRECTORY; | ||
375 | ce->size = 0; | ||
376 | ce->down = first_ce; | ||
377 | |||
378 | ce = dircache_gen_next(ce); | ||
379 | |||
380 | ce->d_name = ".."; | ||
381 | ce->name_len = 3; | ||
382 | ce->attribute = ATTR_DIRECTORY; | ||
383 | ce->size = 0; | ||
384 | ce->down = first_ce->up; | ||
387 | 385 | ||
386 | closedir_uncached(dir); | ||
388 | return 0; | 387 | return 0; |
389 | } | 388 | } |
390 | 389 | ||
390 | static int dircache_scan_and_build(IF_MV2(int volume,) struct dircache_entry *ce) | ||
391 | { | ||
392 | #ifdef HAVE_MULTIVOLUME | ||
393 | (void) volume; | ||
394 | #endif | ||
395 | memset(ce, 0, sizeof(struct dircache_entry)); | ||
396 | |||
397 | strlcpy(sab_path, "/", sizeof sab_path); | ||
398 | return sab_process_dir(ce); | ||
399 | } | ||
400 | #endif /* SIMULATOR */ | ||
401 | |||
391 | /** | 402 | /** |
392 | * Internal function to get a pointer to dircache_entry for a given filename. | 403 | * Internal function to get a pointer to dircache_entry for a given filename. |
393 | * path: Absolute path to a file or directory (see comment) | 404 | * path: Absolute path to a file or directory (see comment) |
@@ -578,11 +589,6 @@ int dircache_save(void) | |||
578 | */ | 589 | */ |
579 | static int dircache_do_rebuild(void) | 590 | static int dircache_do_rebuild(void) |
580 | { | 591 | { |
581 | #ifdef SIMULATOR | ||
582 | DIR_UNCACHED *pdir; | ||
583 | #else | ||
584 | struct fat_dir dir, *pdir; | ||
585 | #endif | ||
586 | unsigned int start_tick; | 592 | unsigned int start_tick; |
587 | int i; | 593 | int i; |
588 | 594 | ||
@@ -592,7 +598,6 @@ static int dircache_do_rebuild(void) | |||
592 | appflags = 0; | 598 | appflags = 0; |
593 | entry_count = 0; | 599 | entry_count = 0; |
594 | 600 | ||
595 | memset(dircache_cur_path, 0, sizeof(dircache_cur_path)); | ||
596 | dircache_size = sizeof(struct dircache_entry); | 601 | dircache_size = sizeof(struct dircache_entry); |
597 | 602 | ||
598 | #ifdef HAVE_MULTIVOLUME | 603 | #ifdef HAVE_MULTIVOLUME |
@@ -603,31 +608,11 @@ static int dircache_do_rebuild(void) | |||
603 | if (fat_ismounted(i)) | 608 | if (fat_ismounted(i)) |
604 | { | 609 | { |
605 | #endif | 610 | #endif |
606 | #ifdef SIMULATOR | ||
607 | pdir = opendir_uncached("/"); | ||
608 | if (pdir == NULL) | ||
609 | { | ||
610 | logf("Failed to open rootdir"); | ||
611 | dircache_initializing = false; | ||
612 | return -3; | ||
613 | } | ||
614 | #else | ||
615 | #ifdef HAVE_MULTIVOLUME | ||
616 | if ( fat_opendir(IF_MV2(i,) &dir, 0, NULL) < 0 ) { | ||
617 | #else | ||
618 | if ( fat_opendir(IF_MV2(0,) &dir, 0, NULL) < 0 ) { | ||
619 | #endif /* HAVE_MULTIVOLUME */ | ||
620 | logf("Failed opening root dir"); | ||
621 | dircache_initializing = false; | ||
622 | return -3; | ||
623 | } | ||
624 | pdir = &dir; | ||
625 | #endif | ||
626 | cpu_boost(true); | 611 | cpu_boost(true); |
627 | #ifdef HAVE_MULTIVOLUME | 612 | #ifdef HAVE_MULTIVOLUME |
628 | if (dircache_travel(IF_MV2(i,) pdir, append_position) < 0) | 613 | if (dircache_scan_and_build(IF_MV2(i,) append_position) < 0) |
629 | #else | 614 | #else |
630 | if (dircache_travel(IF_MV2(0,) pdir, dircache_root) < 0) | 615 | if (dircache_scan_and_build(IF_MV2(0,) dircache_root) < 0) |
631 | #endif /* HAVE_MULTIVOLUME */ | 616 | #endif /* HAVE_MULTIVOLUME */ |
632 | { | 617 | { |
633 | logf("dircache_travel failed"); | 618 | logf("dircache_travel failed"); |