summaryrefslogtreecommitdiff
path: root/firmware/common
diff options
context:
space:
mode:
authorAmaury Pouly <pamaury@rockbox.org>2010-02-14 19:09:52 +0000
committerAmaury Pouly <pamaury@rockbox.org>2010-02-14 19:09:52 +0000
commit26c0e753d1e19747719dbcae8dc6e84a0a74671a (patch)
treee6ad178bebc9f47e2439cfd8394e686c1317bb5c /firmware/common
parente1d8c3ef7c305c94e3de486adb41696ccc18a883 (diff)
downloadrockbox-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')
-rw-r--r--firmware/common/dircache.c379
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;
71static unsigned long reserve_used = 0; 71static unsigned long reserve_used = 0;
72static unsigned int cache_build_ticks = 0; 72static unsigned int cache_build_ticks = 0;
73static unsigned long appflags = 0; 73static unsigned long appflags = 0;
74static char dircache_cur_path[MAX_PATH];
75 74
76static struct event_queue dircache_queue; 75static struct event_queue dircache_queue;
77static long dircache_stack[(DEFAULT_STACK_SIZE + 0x900)/sizeof(long)]; 76static 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
153static 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 */ 175static struct
182static 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
184static 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/** 273static 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
292static int dircache_travel(IF_MV2(int volume,) DIR_UNCACHED *dir, struct dircache_entry *ce)
293#else
294static 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 */
302static char sab_path[MAX_PATH];
342 303
343 dircache_cur_path[dir_recursion[depth].pathpos] = '\0'; 304static 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
390static 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 */
579static int dircache_do_rebuild(void) 590static 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");