diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/common/dircache.c | 231 | ||||
-rw-r--r-- | firmware/include/dircache.h | 3 |
2 files changed, 170 insertions, 64 deletions
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index 92eba42f65..56c408e02c 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #endif | 47 | #endif |
48 | #include "rbpaths.h" | 48 | #include "rbpaths.h" |
49 | 49 | ||
50 | |||
50 | /* Queue commands. */ | 51 | /* Queue commands. */ |
51 | #define DIRCACHE_BUILD 1 | 52 | #define DIRCACHE_BUILD 1 |
52 | #define DIRCACHE_STOP 2 | 53 | #define DIRCACHE_STOP 2 |
@@ -57,9 +58,30 @@ | |||
57 | #define MAX_OPEN_DIRS 8 | 58 | #define MAX_OPEN_DIRS 8 |
58 | #endif | 59 | #endif |
59 | static DIR_CACHED opendirs[MAX_OPEN_DIRS]; | 60 | static DIR_CACHED opendirs[MAX_OPEN_DIRS]; |
60 | 61 | /* Cache Layout: | |
62 | * | ||
63 | * x - array of struct dircache_entry | ||
64 | * r - reserved buffer | ||
65 | * d - name buffer for the d_name entry of the struct dircache_entry | ||
66 | * |xxxxxx|rrrrrrrrr|dddddd| | ||
67 | * | ||
68 | * subsequent x are allocated from the front, d are allocated from the back, | ||
69 | * using the reserve buffer for entries added after initial scan | ||
70 | * | ||
71 | * after a while the cache may look like: | ||
72 | * |xxxxxxxx|rrrrr|dddddddd| | ||
73 | * | ||
74 | * after a reboot, the reserve buffer is restored in it's size, so that the | ||
75 | * total allocation size grows | ||
76 | * |xxxxxxxx|rrrrrrrrr|dddddddd| | ||
77 | */ | ||
61 | static struct dircache_entry *fd_bindings[MAX_OPEN_FILES]; | 78 | static struct dircache_entry *fd_bindings[MAX_OPEN_FILES]; |
79 | /* this points to the beginnging of the buffer and the first entry */ | ||
62 | static struct dircache_entry *dircache_root; | 80 | static struct dircache_entry *dircache_root; |
81 | /* these point to the start and end of the name buffer (d above) */ | ||
82 | static char *d_names_start, *d_names_end; | ||
83 | /* put "." and ".." into the d_names buffer to enable easy pointer logic */ | ||
84 | static char *dot, *dotdot; | ||
63 | #ifdef HAVE_MULTIVOLUME | 85 | #ifdef HAVE_MULTIVOLUME |
64 | static struct dircache_entry *append_position; | 86 | static struct dircache_entry *append_position; |
65 | #endif | 87 | #endif |
@@ -116,20 +138,12 @@ static struct dircache_entry* allocate_entry(void) | |||
116 | return NULL; | 138 | return NULL; |
117 | } | 139 | } |
118 | 140 | ||
119 | next_entry = (struct dircache_entry *)((char *)dircache_root+dircache_size); | 141 | next_entry = &dircache_root[entry_count++]; |
120 | #ifdef ROCKBOX_STRICT_ALIGN | ||
121 | /* Make sure the entry is long aligned. */ | ||
122 | if ((long)next_entry & 0x03) | ||
123 | { | ||
124 | dircache_size += 4 - ((long)next_entry & 0x03); | ||
125 | next_entry = (struct dircache_entry *)(((long)next_entry & ~0x03) + 0x04); | ||
126 | } | ||
127 | #endif | ||
128 | next_entry->d_name = NULL; | 142 | next_entry->d_name = NULL; |
129 | next_entry->up = NULL; | 143 | next_entry->up = NULL; |
130 | next_entry->down = NULL; | 144 | next_entry->down = NULL; |
131 | next_entry->next = NULL; | 145 | next_entry->next = NULL; |
132 | 146 | ||
133 | dircache_size += sizeof(struct dircache_entry); | 147 | dircache_size += sizeof(struct dircache_entry); |
134 | 148 | ||
135 | return next_entry; | 149 | return next_entry; |
@@ -230,8 +244,9 @@ static int sab_process_dir(unsigned long startcluster, struct dircache_entry *ce | |||
230 | if(!strcmp(".", sab.direntry->name) || | 244 | if(!strcmp(".", sab.direntry->name) || |
231 | !strcmp("..", sab.direntry->name)) | 245 | !strcmp("..", sab.direntry->name)) |
232 | continue; | 246 | continue; |
233 | 247 | ||
234 | ce->d_name = ((char *)dircache_root + dircache_size); | 248 | size_t size = strlen(sab.direntry->name) + 1; |
249 | ce->d_name = (d_names_start -= size); | ||
235 | ce->startcluster = sab.direntry->firstcluster; | 250 | ce->startcluster = sab.direntry->firstcluster; |
236 | ce->info.size = sab.direntry->filesize; | 251 | ce->info.size = sab.direntry->filesize; |
237 | ce->info.attribute = sab.direntry->attr; | 252 | ce->info.attribute = sab.direntry->attr; |
@@ -239,9 +254,7 @@ static int sab_process_dir(unsigned long startcluster, struct dircache_entry *ce | |||
239 | ce->info.wrttime = sab.direntry->wrttime; | 254 | ce->info.wrttime = sab.direntry->wrttime; |
240 | 255 | ||
241 | strcpy(ce->d_name, sab.direntry->name); | 256 | strcpy(ce->d_name, sab.direntry->name); |
242 | dircache_size += strlen(ce->d_name) + 1; | 257 | dircache_size += size; |
243 | |||
244 | entry_count++; | ||
245 | 258 | ||
246 | if(ce->info.attribute & FAT_ATTR_DIRECTORY) | 259 | if(ce->info.attribute & FAT_ATTR_DIRECTORY) |
247 | dircache_gen_down(ce); | 260 | dircache_gen_down(ce); |
@@ -261,7 +274,7 @@ static int sab_process_dir(unsigned long startcluster, struct dircache_entry *ce | |||
261 | } | 274 | } |
262 | 275 | ||
263 | /* add "." and ".." */ | 276 | /* add "." and ".." */ |
264 | ce->d_name = "."; | 277 | ce->d_name = dot; |
265 | ce->info.attribute = FAT_ATTR_DIRECTORY; | 278 | ce->info.attribute = FAT_ATTR_DIRECTORY; |
266 | ce->startcluster = startcluster; | 279 | ce->startcluster = startcluster; |
267 | ce->info.size = 0; | 280 | ce->info.size = 0; |
@@ -269,7 +282,7 @@ static int sab_process_dir(unsigned long startcluster, struct dircache_entry *ce | |||
269 | 282 | ||
270 | ce = dircache_gen_next(ce); | 283 | ce = dircache_gen_next(ce); |
271 | 284 | ||
272 | ce->d_name = ".."; | 285 | ce->d_name = dotdot; |
273 | ce->info.attribute = FAT_ATTR_DIRECTORY; | 286 | ce->info.attribute = FAT_ATTR_DIRECTORY; |
274 | ce->startcluster = (first_ce->up ? first_ce->up->startcluster : 0); | 287 | ce->startcluster = (first_ce->up ? first_ce->up->startcluster : 0); |
275 | ce->info.size = 0; | 288 | ce->info.size = 0; |
@@ -300,7 +313,7 @@ static int dircache_scan_and_build(IF_MV2(int volume,) struct dircache_entry *ce | |||
300 | #ifdef HAVE_MULTIVOLUME | 313 | #ifdef HAVE_MULTIVOLUME |
301 | if (volume > 0) | 314 | if (volume > 0) |
302 | { | 315 | { |
303 | ce->d_name = ((char *)dircache_root+dircache_size); | 316 | ce->d_name = (d_names_start -= sizeof(VOL_NAMES)); |
304 | size_t len = snprintf(ce->d_name, VOL_ENUM_POS + 3, VOL_NAMES, volume)+1; | 317 | size_t len = snprintf(ce->d_name, VOL_ENUM_POS + 3, VOL_NAMES, volume)+1; |
305 | dircache_size += len; | 318 | dircache_size += len; |
306 | ce->info.attribute = FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME; | 319 | ce->info.attribute = FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME; |
@@ -338,14 +351,13 @@ static int sab_process_dir(struct dircache_entry *ce) | |||
338 | if(!strcmp(".", entry->d_name) || | 351 | if(!strcmp(".", entry->d_name) || |
339 | !strcmp("..", entry->d_name)) | 352 | !strcmp("..", entry->d_name)) |
340 | continue; | 353 | continue; |
341 | 354 | ||
342 | ce->d_name = ((char *)dircache_root + dircache_size); | 355 | size_t size = strlen(entry->d_name) + 1; |
356 | ce->d_name = (d_names_start -= size); | ||
343 | ce->info = entry->info; | 357 | ce->info = entry->info; |
344 | 358 | ||
345 | strcpy(ce->d_name, entry->d_name); | 359 | strcpy(ce->d_name, entry->d_name); |
346 | dircache_size += strlen(entry->d_name) + 1; | 360 | dircache_size += size; |
347 | |||
348 | entry_count++; | ||
349 | 361 | ||
350 | if(entry->info.attribute & ATTR_DIRECTORY) | 362 | if(entry->info.attribute & ATTR_DIRECTORY) |
351 | { | 363 | { |
@@ -387,14 +399,14 @@ static int sab_process_dir(struct dircache_entry *ce) | |||
387 | } | 399 | } |
388 | 400 | ||
389 | /* add "." and ".." */ | 401 | /* add "." and ".." */ |
390 | ce->d_name = "."; | 402 | ce->d_name = dot; |
391 | ce->info.attribute = ATTR_DIRECTORY; | 403 | ce->info.attribute = ATTR_DIRECTORY; |
392 | ce->info.size = 0; | 404 | ce->info.size = 0; |
393 | ce->down = first_ce; | 405 | ce->down = first_ce; |
394 | 406 | ||
395 | ce = dircache_gen_next(ce); | 407 | ce = dircache_gen_next(ce); |
396 | 408 | ||
397 | ce->d_name = ".."; | 409 | ce->d_name = dotdot; |
398 | ce->info.attribute = ATTR_DIRECTORY; | 410 | ce->info.attribute = ATTR_DIRECTORY; |
399 | ce->info.size = 0; | 411 | ce->info.size = 0; |
400 | ce->down = first_ce->up; | 412 | ce->down = first_ce->up; |
@@ -498,7 +510,7 @@ static struct dircache_entry* dircache_get_entry(const char *path, bool go_down) | |||
498 | int dircache_load(void) | 510 | int dircache_load(void) |
499 | { | 511 | { |
500 | struct dircache_maindata maindata; | 512 | struct dircache_maindata maindata; |
501 | int bytes_read; | 513 | ssize_t bytes_read; |
502 | int fd; | 514 | int fd; |
503 | 515 | ||
504 | if (dircache_initialized) | 516 | if (dircache_initialized) |
@@ -520,29 +532,65 @@ int dircache_load(void) | |||
520 | remove_dircache_file(); | 532 | remove_dircache_file(); |
521 | return -3; | 533 | return -3; |
522 | } | 534 | } |
523 | |||
524 | dircache_root = buffer_alloc(0); | ||
525 | if ((long)maindata.root_entry != (long)dircache_root) | ||
526 | { | ||
527 | logf("Position missmatch"); | ||
528 | close(fd); | ||
529 | remove_dircache_file(); | ||
530 | return -4; | ||
531 | } | ||
532 | 535 | ||
533 | dircache_root = buffer_alloc(maindata.size + DIRCACHE_RESERVE); | 536 | dircache_root = buffer_alloc(maindata.size + DIRCACHE_RESERVE); |
534 | entry_count = maindata.entry_count; | 537 | entry_count = maindata.entry_count; |
535 | appflags = maindata.appflags; | 538 | appflags = maindata.appflags; |
536 | bytes_read = read(fd, dircache_root, MIN(DIRCACHE_LIMIT, maindata.size)); | 539 | |
537 | close(fd); | 540 | /* read the dircache file into memory, |
538 | remove_dircache_file(); | 541 | * start with the struct dircache_entries */ |
542 | ssize_t bytes_to_read = entry_count*sizeof(struct dircache_entry); | ||
543 | bytes_read = read(fd, dircache_root, bytes_to_read); | ||
539 | 544 | ||
540 | if (bytes_read != maindata.size) | 545 | if (bytes_read != bytes_to_read) |
541 | { | 546 | { |
542 | logf("Dircache read failed"); | 547 | logf("Dircache read failed #1"); |
543 | return -6; | 548 | return -6; |
544 | } | 549 | } |
545 | 550 | ||
551 | /* continue with the d_names. Fix up pointers to them if needed */ | ||
552 | d_names_start = ((char*)&dircache_root[entry_count] + DIRCACHE_RESERVE); | ||
553 | bytes_to_read = maindata.size - bytes_to_read; | ||
554 | bytes_read = read(fd, d_names_start, bytes_to_read); | ||
555 | close(fd); | ||
556 | remove_dircache_file(); | ||
557 | if (bytes_read != bytes_to_read) | ||
558 | { | ||
559 | logf("Dircache read failed #2"); | ||
560 | return -7; | ||
561 | } | ||
562 | |||
563 | d_names_end = &d_names_start[bytes_read]; | ||
564 | dot = d_names_end - sizeof("."); | ||
565 | dotdot = dot - sizeof(".."); | ||
566 | |||
567 | /* d_names are in reverse order, so the last entry points to the first string */ | ||
568 | intptr_t offset_d_names = maindata.d_names_start - d_names_start; | ||
569 | intptr_t offset_entries = maindata.root_entry - dircache_root; | ||
570 | |||
571 | /* offset_entries is less likely to differ, so check if it's 0 in the loop | ||
572 | * offset_d_names however is almost always non-zero, since dircache_save() | ||
573 | * creates a file which causes the reserve buffer to be used. since | ||
574 | * we allocate a new, empty DIRCACHE_RESERVE here, the strings are | ||
575 | * farther behind */ | ||
576 | if (offset_entries != 0 || offset_d_names != 0) | ||
577 | { | ||
578 | for(unsigned i = 0; i < entry_count; i++) | ||
579 | { | ||
580 | if (dircache_root[i].d_name) | ||
581 | dircache_root[i].d_name -= offset_d_names; | ||
582 | |||
583 | if (offset_entries == 0) | ||
584 | continue; | ||
585 | if (dircache_root[i].next) | ||
586 | dircache_root[i].next -= offset_entries; | ||
587 | if (dircache_root[i].up) | ||
588 | dircache_root[i].up -= offset_entries; | ||
589 | if (dircache_root[i].down) | ||
590 | dircache_root[i].down -= offset_entries; | ||
591 | } | ||
592 | } | ||
593 | |||
546 | /* Cache successfully loaded. */ | 594 | /* Cache successfully loaded. */ |
547 | dircache_size = maindata.size; | 595 | dircache_size = maindata.size; |
548 | allocated_size = dircache_size + DIRCACHE_RESERVE; | 596 | allocated_size = dircache_size + DIRCACHE_RESERVE; |
@@ -575,6 +623,7 @@ int dircache_save(void) | |||
575 | maindata.magic = DIRCACHE_MAGIC; | 623 | maindata.magic = DIRCACHE_MAGIC; |
576 | maindata.size = dircache_size; | 624 | maindata.size = dircache_size; |
577 | maindata.root_entry = dircache_root; | 625 | maindata.root_entry = dircache_root; |
626 | maindata.d_names_start = d_names_start; | ||
578 | maindata.entry_count = entry_count; | 627 | maindata.entry_count = entry_count; |
579 | maindata.appflags = appflags; | 628 | maindata.appflags = appflags; |
580 | 629 | ||
@@ -587,14 +636,26 @@ int dircache_save(void) | |||
587 | return -2; | 636 | return -2; |
588 | } | 637 | } |
589 | 638 | ||
590 | /* Dump whole directory cache to disk */ | 639 | /* Dump whole directory cache to disk |
591 | bytes_written = write(fd, dircache_root, dircache_size); | 640 | * start by writing the dircache_entries */ |
592 | close(fd); | 641 | size_t bytes_to_write = entry_count*sizeof(struct dircache_entry); |
593 | if (bytes_written != dircache_size) | 642 | bytes_written = write(fd, dircache_root, bytes_to_write); |
643 | if (bytes_written != bytes_to_write) | ||
594 | { | 644 | { |
595 | logf("dircache: write failed #2"); | 645 | logf("dircache: write failed #2"); |
596 | return -3; | 646 | return -3; |
597 | } | 647 | } |
648 | |||
649 | /* continue with the d_names */ | ||
650 | bytes_to_write = d_names_end - d_names_start; | ||
651 | bytes_written = write(fd, d_names_start, bytes_to_write); | ||
652 | close(fd); | ||
653 | if (bytes_written != bytes_to_write) | ||
654 | { | ||
655 | logf("dircache: write failed #3"); | ||
656 | return -4; | ||
657 | } | ||
658 | |||
598 | 659 | ||
599 | return 0; | 660 | return 0; |
600 | } | 661 | } |
@@ -605,6 +666,7 @@ int dircache_save(void) | |||
605 | */ | 666 | */ |
606 | static int dircache_do_rebuild(void) | 667 | static int dircache_do_rebuild(void) |
607 | { | 668 | { |
669 | struct dircache_entry* root_entry; | ||
608 | unsigned int start_tick; | 670 | unsigned int start_tick; |
609 | int i; | 671 | int i; |
610 | 672 | ||
@@ -612,12 +674,13 @@ static int dircache_do_rebuild(void) | |||
612 | start_tick = current_tick; | 674 | start_tick = current_tick; |
613 | dircache_initializing = true; | 675 | dircache_initializing = true; |
614 | appflags = 0; | 676 | appflags = 0; |
677 | |||
678 | /* reset dircache and alloc root entry */ | ||
615 | entry_count = 0; | 679 | entry_count = 0; |
616 | 680 | root_entry = allocate_entry(); | |
617 | dircache_size = sizeof(struct dircache_entry); | ||
618 | 681 | ||
619 | #ifdef HAVE_MULTIVOLUME | 682 | #ifdef HAVE_MULTIVOLUME |
620 | append_position = dircache_root; | 683 | append_position = root_entry; |
621 | 684 | ||
622 | for (i = NUM_VOLUMES; i >= 0; i--) | 685 | for (i = NUM_VOLUMES; i >= 0; i--) |
623 | { | 686 | { |
@@ -628,7 +691,7 @@ static int dircache_do_rebuild(void) | |||
628 | #ifdef HAVE_MULTIVOLUME | 691 | #ifdef HAVE_MULTIVOLUME |
629 | if (dircache_scan_and_build(IF_MV2(i,) append_position) < 0) | 692 | if (dircache_scan_and_build(IF_MV2(i,) append_position) < 0) |
630 | #else | 693 | #else |
631 | if (dircache_scan_and_build(IF_MV2(0,) dircache_root) < 0) | 694 | if (dircache_scan_and_build(IF_MV2(0,) root_entry) < 0) |
632 | #endif /* HAVE_MULTIVOLUME */ | 695 | #endif /* HAVE_MULTIVOLUME */ |
633 | { | 696 | { |
634 | logf("dircache_scan_and_build failed"); | 697 | logf("dircache_scan_and_build failed"); |
@@ -660,14 +723,6 @@ static int dircache_do_rebuild(void) | |||
660 | if (allocated_size - dircache_size < DIRCACHE_RESERVE) | 723 | if (allocated_size - dircache_size < DIRCACHE_RESERVE) |
661 | reserve_used = DIRCACHE_RESERVE - (allocated_size - dircache_size); | 724 | reserve_used = DIRCACHE_RESERVE - (allocated_size - dircache_size); |
662 | } | 725 | } |
663 | else | ||
664 | { | ||
665 | /* We have to long align the audiobuf to keep the buffer access fast. */ | ||
666 | audiobuf += (long)((dircache_size & ~0x03) + 0x04); | ||
667 | audiobuf += DIRCACHE_RESERVE; | ||
668 | allocated_size = dircache_size + DIRCACHE_RESERVE; | ||
669 | reserve_used = 0; | ||
670 | } | ||
671 | 726 | ||
672 | return 1; | 727 | return 1; |
673 | } | 728 | } |
@@ -712,6 +767,14 @@ static void dircache_thread(void) | |||
712 | } | 767 | } |
713 | } | 768 | } |
714 | 769 | ||
770 | static void generate_dot_d_names(void) | ||
771 | { | ||
772 | dot = (d_names_start -= sizeof(".")); | ||
773 | dotdot = (d_names_start -= sizeof("..")); | ||
774 | dircache_size += sizeof(".") + sizeof(".."); | ||
775 | strcpy(dot, "."); | ||
776 | strcpy(dotdot, ".."); | ||
777 | } | ||
715 | /** | 778 | /** |
716 | * Start scanning the disk to build the dircache. | 779 | * Start scanning the disk to build the dircache. |
717 | * Either transparent or non-transparent build method is used. | 780 | * Either transparent or non-transparent build method is used. |
@@ -734,22 +797,63 @@ int dircache_build(int last_size) | |||
734 | queue_post(&dircache_queue, DIRCACHE_BUILD, 0); | 797 | queue_post(&dircache_queue, DIRCACHE_BUILD, 0); |
735 | return 2; | 798 | return 2; |
736 | } | 799 | } |
737 | |||
738 | if (last_size > DIRCACHE_RESERVE && last_size < DIRCACHE_LIMIT ) | 800 | if (last_size > DIRCACHE_RESERVE && last_size < DIRCACHE_LIMIT ) |
739 | { | 801 | { |
740 | allocated_size = last_size + DIRCACHE_RESERVE; | 802 | allocated_size = last_size + DIRCACHE_RESERVE; |
741 | dircache_root = buffer_alloc(allocated_size); | 803 | dircache_root = buffer_alloc(allocated_size); |
804 | d_names_start = | ||
805 | d_names_end = ((char*)dircache_root)+allocated_size-1; | ||
806 | dircache_size = 0; | ||
742 | thread_enabled = true; | 807 | thread_enabled = true; |
808 | generate_dot_d_names(); | ||
743 | 809 | ||
744 | /* Start a transparent rebuild. */ | 810 | /* Start a transparent rebuild. */ |
745 | queue_post(&dircache_queue, DIRCACHE_BUILD, 0); | 811 | queue_post(&dircache_queue, DIRCACHE_BUILD, 0); |
746 | return 3; | 812 | return 3; |
747 | } | 813 | } |
748 | 814 | ||
749 | dircache_root = (struct dircache_entry *)(((long)audiobuf & ~0x03) + 0x04); | 815 | /* struct dircache_entrys are allocated from the beginning, |
816 | * their corresponding d_name from the end | ||
817 | * after generation the buffer will be compacted with DIRCACHE_RESERVE | ||
818 | * free bytes in between */ | ||
819 | audiobuf = (char*)(((intptr_t)audiobuf & ~0x03) + 0x04); | ||
820 | dircache_root = (struct dircache_entry*)audiobuf; | ||
821 | d_names_start = d_names_end = audiobufend - 1; | ||
822 | dircache_size = 0; | ||
823 | generate_dot_d_names(); | ||
750 | 824 | ||
751 | /* Start a non-transparent rebuild. */ | 825 | /* Start a non-transparent rebuild. */ |
752 | return dircache_do_rebuild(); | 826 | int res = dircache_do_rebuild(); |
827 | |||
828 | /** compact the dircache buffer **/ | ||
829 | if (res >= 0) | ||
830 | { | ||
831 | char* dst = ((char*)&dircache_root[entry_count] + DIRCACHE_RESERVE); | ||
832 | ssize_t offset = d_names_start - dst; | ||
833 | if (offset > 0) | ||
834 | { | ||
835 | ssize_t size_to_move = dircache_size - | ||
836 | entry_count*sizeof(struct dircache_entry); | ||
837 | /* move d_names down, use memmove if overlap */ | ||
838 | if (offset > size_to_move) | ||
839 | memcpy(dst, d_names_start, size_to_move); | ||
840 | else | ||
841 | memmove(dst, d_names_start, size_to_move); | ||
842 | |||
843 | /* fix up pointers to the d_names */ | ||
844 | for(unsigned i = 0; i < entry_count; i++) | ||
845 | dircache_root[i].d_name -= offset; | ||
846 | |||
847 | d_names_end -= offset; | ||
848 | /* equivalent to dircache_size + DIRCACHE_RESERVE */ | ||
849 | allocated_size = (d_names_end - (char*)dircache_root); | ||
850 | reserve_used = 0; | ||
851 | audiobuf += allocated_size; | ||
852 | } | ||
853 | else /* something went wrong */ | ||
854 | return -1; | ||
855 | } | ||
856 | return res; | ||
753 | } | 857 | } |
754 | 858 | ||
755 | /** | 859 | /** |
@@ -1008,14 +1112,15 @@ static struct dircache_entry* dircache_new_entry(const char *path, int attribute | |||
1008 | return NULL; | 1112 | return NULL; |
1009 | } | 1113 | } |
1010 | } | 1114 | } |
1011 | 1115 | ||
1012 | entry->d_name = ((char *)dircache_root+dircache_size); | 1116 | size_t size = strlen(new) + 1; |
1117 | entry->d_name = (d_names_start -= size); | ||
1013 | entry->startcluster = 0; | 1118 | entry->startcluster = 0; |
1014 | memset(&entry->info, 0, sizeof(entry->info)); | 1119 | memset(&entry->info, 0, sizeof(entry->info)); |
1015 | entry->info.attribute = attribute; | 1120 | entry->info.attribute = attribute; |
1016 | 1121 | ||
1017 | strcpy(entry->d_name, new); | 1122 | strcpy(entry->d_name, new); |
1018 | dircache_size += strlen(entry->d_name) + 1; | 1123 | dircache_size += size; |
1019 | 1124 | ||
1020 | if (attribute & ATTR_DIRECTORY) | 1125 | if (attribute & ATTR_DIRECTORY) |
1021 | { | 1126 | { |
diff --git a/firmware/include/dircache.h b/firmware/include/dircache.h index 716d1fbed2..d04c176996 100644 --- a/firmware/include/dircache.h +++ b/firmware/include/dircache.h | |||
@@ -47,13 +47,14 @@ struct travel_data { | |||
47 | int pathpos; | 47 | int pathpos; |
48 | }; | 48 | }; |
49 | 49 | ||
50 | #define DIRCACHE_MAGIC 0x00d0c0a0 | 50 | #define DIRCACHE_MAGIC 0x00d0c0a1 |
51 | struct dircache_maindata { | 51 | struct dircache_maindata { |
52 | long magic; | 52 | long magic; |
53 | long size; | 53 | long size; |
54 | long entry_count; | 54 | long entry_count; |
55 | long appflags; | 55 | long appflags; |
56 | struct dircache_entry *root_entry; | 56 | struct dircache_entry *root_entry; |
57 | char *d_names_start; | ||
57 | }; | 58 | }; |
58 | 59 | ||
59 | #define MAX_PENDING_BINDINGS 2 | 60 | #define MAX_PENDING_BINDINGS 2 |