summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2017-01-18 04:39:35 -0500
committerMichael Sevakis <jethead71@rockbox.org>2017-02-10 05:05:23 -0500
commit7373cf518f4d4c47f49693690c2ab8ec29bb8510 (patch)
tree0a3c025749be24561e952078e83c5f2e8b838900
parentabd75a17d18c0779b59f64a612f9226b62af5823 (diff)
downloadrockbox-7373cf518f4d4c47f49693690c2ab8ec29bb8510.tar.gz
rockbox-7373cf518f4d4c47f49693690c2ab8ec29bb8510.zip
Restore dircache hookup in the database ramcache.
Do a few other changes to dircache and file code flags to accomodate its demands. Change-Id: I4742a54e8cfbe4d8b9cffb75faaf920dd907cf8a
-rw-r--r--apps/playlist.c2
-rw-r--r--apps/tagcache.c837
-rw-r--r--firmware/common/dir.c3
-rw-r--r--firmware/common/dircache.c209
-rw-r--r--firmware/common/file.c10
-rw-r--r--firmware/common/file_internal.c10
-rw-r--r--firmware/include/dircache.h11
-rw-r--r--firmware/include/file_internal.h27
8 files changed, 619 insertions, 490 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index 176cfc3af7..e8d9896a01 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -1324,7 +1324,7 @@ static void playlist_thread(void)
1324 && queue_empty(&playlist_queue); index++) 1324 && queue_empty(&playlist_queue); index++)
1325 { 1325 {
1326 /* Process only pointers that are superficially stale. */ 1326 /* Process only pointers that are superficially stale. */
1327 if (dircache_search(DCS_FILEREF, &playlist->dcfrefs[index], NULL) == 0) 1327 if (dircache_search(DCS_FILEREF, &playlist->dcfrefs[index], NULL) > 0)
1328 continue ; 1328 continue ;
1329 1329
1330 control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; 1330 control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK;
diff --git a/apps/tagcache.c b/apps/tagcache.c
index 2b3c7212a2..be4686679b 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -82,18 +82,15 @@
82#include "pathfuncs.h" 82#include "pathfuncs.h"
83#include "structec.h" 83#include "structec.h"
84#include "debug.h" 84#include "debug.h"
85#ifdef HAVE_DIRCACHE
86#include "dircache.h"
87#endif
85 88
86#ifndef __PCTOOL__ 89#ifndef __PCTOOL__
87#include "lang.h" 90#include "lang.h"
88#include "eeprom_settings.h" 91#include "eeprom_settings.h"
89#endif 92#endif
90 93
91#undef HAVE_DIRCACHE
92
93#ifdef HAVE_DIRCACHE
94#include "dircache.h"
95#endif
96
97#ifdef __PCTOOL__ 94#ifdef __PCTOOL__
98#define yield() do { } while(0) 95#define yield() do { } while(0)
99#define sim_sleep(timeout) do { } while(0) 96#define sim_sleep(timeout) do { } while(0)
@@ -213,27 +210,60 @@ static const char * const master_header_ec = "llllll";
213static struct master_header current_tcmh; 210static struct master_header current_tcmh;
214 211
215#ifdef HAVE_TC_RAMCACHE 212#ifdef HAVE_TC_RAMCACHE
213
214#define TC_ALIGN_PTR(p, gap_out_p) \
215 ({ typeof (p) __p = (p); \
216 typeof (p) __palgn = ALIGN_UP(__p, sizeof (intptr_t)); \
217 *(gap_out_p) = __palgn - __p; \
218 __palgn; })
219
220#define IF_TCRCDC(...) IF_DIRCACHE(__VA_ARGS__)
221
222#ifdef HAVE_DIRCACHE
223#define tcrc_dcfrefs \
224 ((struct dircache_fileref *)(tcramcache.hdr->tags[tag_filename] + \
225 sizeof (struct tagcache_header)))
226#endif /* HAVE_DIRCACHE */
227
216/* Header is created when loading database to ram. */ 228/* Header is created when loading database to ram. */
217struct ramcache_header { 229struct ramcache_header {
218 char *tags[TAG_COUNT]; /* Tag file content (not including filename tag) */ 230 char *tags[TAG_COUNT]; /* Tag file content (dcfrefs if tag_filename) */
219 int entry_count[TAG_COUNT]; /* Number of entries in the indices. */ 231 int entry_count[TAG_COUNT]; /* Number of entries in the indices. */
220 struct index_entry indices[0]; /* Master index file content */ 232 struct index_entry indices[0]; /* Master index file content */
221}; 233};
222 234
223# ifdef HAVE_EEPROM_SETTINGS 235#ifdef HAVE_EEPROM_SETTINGS
224struct statefile_header { 236struct statefile_header {
225 int32_t magic; /* Statefile version number */ 237 int32_t magic; /* Statefile version number */
226 struct master_header mh; /* Header from the master index */ 238 struct master_header mh; /* Header from the master index */
227 struct ramcache_header *hdr; /* Old load address of hdr for relocation */ 239 struct ramcache_header *hdr; /* Old load address of hdr for relocation */
228 struct tagcache_stat tc_stat; 240 struct tagcache_stat tc_stat;
229}; 241};
230# endif 242#endif /* HAVE_EEPROM_SETTINGS */
231 243
232/* Pointer to allocated ramcache_header */ 244/* In-RAM ramcache structure (not persisted) */
233static struct ramcache_header *ramcache_hdr; 245static struct tcramcache
234/* lock entity to temporarily prevent ramcache_hdr from moving */ 246{
235static int move_lock; 247 struct ramcache_header *hdr; /* allocated ramcache_header */
236#endif 248 int handle; /* buffer handle */
249 int move_lock;
250} tcramcache;
251
252static inline void tcrc_buffer_lock(void)
253{
254 tcramcache.move_lock++;
255}
256
257static inline void tcrc_buffer_unlock(void)
258{
259 tcramcache.move_lock--;
260}
261
262#else /* ndef HAVE_TC_RAMCACHE */
263
264#define IF_TCRCDC(...)
265
266#endif /* HAVE_TC_RAMCACHE */
237 267
238/** 268/**
239 * Full tag entries stored in a temporary file waiting 269 * Full tag entries stored in a temporary file waiting
@@ -275,6 +305,41 @@ static volatile int read_lock;
275 305
276static bool delete_entry(long idx_id); 306static bool delete_entry(long idx_id);
277 307
308static void allocate_tempbuf(void)
309{
310 /* Yeah, malloc would be really nice now :) */
311 size_t size;
312 tempbuf_size = 0;
313
314#ifdef __PCTOOL__
315 size = 32*1024*1024;
316 tempbuf = malloc(size);
317 if (tempbuf)
318 tempbuf_size = size;
319#else /* !__PCTOOL__ */
320 tempbuf_handle = core_alloc_maximum("tc tempbuf", &size, NULL);
321 if (tempbuf_handle > 0)
322 {
323 tempbuf = core_get_data(tempbuf_handle);
324 tempbuf_size = size;
325 }
326#endif /* __PCTOOL__ */
327}
328
329static void free_tempbuf(void)
330{
331 if (tempbuf_size == 0)
332 return ;
333
334#ifdef __PCTOOL__
335 free(tempbuf);
336#else
337 tempbuf_handle = core_free(tempbuf_handle);
338#endif
339 tempbuf = NULL;
340 tempbuf_size = 0;
341}
342
278const char* tagcache_tag_to_str(int tag) 343const char* tagcache_tag_to_str(int tag)
279{ 344{
280 return tags_str[tag]; 345 return tags_str[tag];
@@ -381,51 +446,64 @@ static bool do_timed_yield(void)
381 } 446 }
382 return false; 447 return false;
383} 448}
384#endif 449#endif /* __PCTOOL__ */
385 450
386#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 451#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
387/* find the ramcache entry corresponding to the file indicated by 452/* find the ramcache entry corresponding to the file indicated by
388 * filename and dc (it's corresponding dircache id). */ 453 * filename and dc (it's corresponding dircache id). */
389static long find_entry_ram(const char *filename, int dc) 454static long find_entry_ram(const char *filename)
390{ 455{
391 static long last_pos = 0; 456 static long last_pos = 0;
392 int i; 457 struct dircache_fileref dcfref;
393 458
394 /* Check if tagcache is loaded into ram. */ 459 /* Check if tagcache is loaded into ram. */
395 if (!tc_stat.ramcache || !is_dircache_intact()) 460 if (!tc_stat.ramcache)
396 return -1; 461 return -1;
397 462
398 if (dc < 0) 463 if (dircache_search(DCS_CACHED_PATH | DCS_UPDATE_FILEREF, &dcfref,
399 dc = dircache_get_entry_id(filename); 464 filename) <= 0)
400
401 if (dc < 0)
402 { 465 {
403 logf("tagcache: file not found."); 466 logf("tagcache: file not found.");
404 return -1; 467 return -1;
405 } 468 }
406 469
407 try_again: 470 /* Search references */
408 471 int end_pos = current_tcmh.tch.entry_count;
409 if (last_pos > 0) 472 while (1)
410 i = last_pos;
411 else
412 i = 0;
413
414 for (; i < current_tcmh.tch.entry_count; i++)
415 { 473 {
416 if (ramcache_hdr->indices[i].tag_seek[tag_filename] == dc) 474 for (int i = last_pos; i < end_pos; i++)
417 { 475 {
418 last_pos = MAX(0, i - 3); 476 if (tcramcache.hdr->indices[i].flag & FLAG_DIRCACHE)
419 return i; 477 {
478 int cmp = dircache_fileref_cmp(&tcrc_dcfrefs[i], &dcfref);
479 if (cmp > 0)
480 {
481 if (cmp < 3)
482 {
483 if (dircache_search(DCS_CACHED_PATH | DCS_UPDATE_FILEREF,
484 &dcfref, filename) <= 0)
485 return -1;
486
487 if (dircache_fileref_cmp(&tcrc_dcfrefs[i], &dcfref) < 3)
488 return -1;
489 }
490
491 last_pos = MAX(0, i - 3);
492 return i;
493 }
494 }
495
496 do_timed_yield();
420 } 497 }
421
422 do_timed_yield();
423 }
424 498
425 if (last_pos > 0) 499 if (last_pos == 0)
426 { 500 {
501 last_pos = MAX(0, end_pos - 3);
502 break;
503 }
504
505 end_pos = last_pos;
427 last_pos = 0; 506 last_pos = 0;
428 goto try_again;
429 } 507 }
430 508
431 return -1; 509 return -1;
@@ -450,7 +528,7 @@ static long find_entry_disk(const char *filename_raw, bool localfd)
450 char pathbuf[PATH_MAX]; /* Note: Don't use MAX_PATH here, it's too small */ 528 char pathbuf[PATH_MAX]; /* Note: Don't use MAX_PATH here, it's too small */
451 if (realpath(filename, pathbuf) == pathbuf) 529 if (realpath(filename, pathbuf) == pathbuf)
452 filename = pathbuf; 530 filename = pathbuf;
453#endif 531#endif /* APPLICATION */
454 532
455 if (!tc_stat.ready) 533 if (!tc_stat.ready)
456 return -2; 534 return -2;
@@ -540,7 +618,7 @@ static int find_index(const char *filename)
540 long idx_id = -1; 618 long idx_id = -1;
541 619
542#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 620#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
543 idx_id = find_entry_ram(filename, -1); 621 idx_id = find_entry_ram(filename);
544#endif 622#endif
545 623
546 if (idx_id < 0) 624 if (idx_id < 0)
@@ -583,19 +661,13 @@ static bool get_index(int masterfd, int idxid,
583#ifdef HAVE_TC_RAMCACHE 661#ifdef HAVE_TC_RAMCACHE
584 if (tc_stat.ramcache && use_ram) 662 if (tc_stat.ramcache && use_ram)
585 { 663 {
586 if (ramcache_hdr->indices[idxid].flag & FLAG_DELETED) 664 if (tcramcache.hdr->indices[idxid].flag & FLAG_DELETED)
587 return false; 665 return false;
588 666
589#ifdef HAVE_DIRCACHE 667 *idx = tcramcache.hdr->indices[idxid];
590 if (!(ramcache_hdr->indices[idxid].flag & FLAG_DIRCACHE) 668 return true;
591 || is_dircache_intact())
592#endif
593 {
594 memcpy(idx, &ramcache_hdr->indices[idxid], sizeof(struct index_entry));
595 return true;
596 }
597 } 669 }
598#endif 670#endif /* HAVE_TC_RAMCACHE */
599 671
600 if (masterfd < 0) 672 if (masterfd < 0)
601 { 673 {
@@ -647,10 +719,9 @@ static bool write_index(int masterfd, int idxid, struct index_entry *idx)
647 */ 719 */
648 if (tc_stat.ramcache) 720 if (tc_stat.ramcache)
649 { 721 {
650 int tag; 722 struct index_entry *idx_ram = &tcramcache.hdr->indices[idxid];
651 struct index_entry *idx_ram = &ramcache_hdr->indices[idxid];
652 723
653 for (tag = 0; tag < TAG_COUNT; tag++) 724 for (int tag = 0; tag < TAG_COUNT; tag++)
654 { 725 {
655 if (TAGCACHE_IS_NUMERIC(tag)) 726 if (TAGCACHE_IS_NUMERIC(tag))
656 { 727 {
@@ -662,7 +733,7 @@ static bool write_index(int masterfd, int idxid, struct index_entry *idx)
662 idx_ram->flag = (idx->flag & 0x0000ffff) 733 idx_ram->flag = (idx->flag & 0x0000ffff)
663 | (idx_ram->flag & (0xffff0000 | FLAG_DIRCACHE)); 734 | (idx_ram->flag & (0xffff0000 | FLAG_DIRCACHE));
664 } 735 }
665#endif 736#endif /* HAVE_TC_RAMCACHE */
666 737
667 lseek(masterfd, idxid * sizeof(struct index_entry) 738 lseek(masterfd, idxid * sizeof(struct index_entry)
668 + sizeof(struct master_header), SEEK_SET); 739 + sizeof(struct master_header), SEEK_SET);
@@ -697,8 +768,8 @@ static bool open_files(struct tagcache_search *tcs, int tag)
697 return true; 768 return true;
698} 769}
699 770
700static bool retrieve(struct tagcache_search *tcs, struct index_entry *idx, 771static bool retrieve(struct tagcache_search *tcs, int idx_id,
701 int tag, char *buf, long size) 772 struct index_entry *idx, int tag, char *buf, long size)
702{ 773{
703 struct tagfile_entry tfe; 774 struct tagfile_entry tfe;
704 long seek; 775 long seek;
@@ -718,39 +789,24 @@ static bool retrieve(struct tagcache_search *tcs, struct index_entry *idx,
718#ifdef HAVE_TC_RAMCACHE 789#ifdef HAVE_TC_RAMCACHE
719 if (tcs->ramsearch) 790 if (tcs->ramsearch)
720 { 791 {
721 struct tagfile_entry *ep;
722
723#ifdef HAVE_DIRCACHE 792#ifdef HAVE_DIRCACHE
724 if (tag == tag_filename && (idx->flag & FLAG_DIRCACHE)) 793 if (tag == tag_filename && (idx->flag & FLAG_DIRCACHE))
725 { 794 {
726 /* for tag_filename, seek is a dircache index */ 795 if (dircache_get_fileref_path(&tcrc_dcfrefs[idx_id], buf, size) >= 0)
727 if (is_dircache_intact())
728 {
729 dircache_copy_path(seek, buf, size);
730 return true; 796 return true;
731 }
732 else
733 {
734 /* The seek is useless now, there's nothing we can return. */
735 logf("retrieve: dircache gone, cannot read file name");
736 tagcache_unload_ramcache();
737 // XXX do this when there's a way to not trigger an
738 // update before reloading:
739 // tagcache_start_scan();
740 return false;
741 }
742 } 797 }
743 else 798 else
744#endif /* HAVE_DIRCACHE */ 799#endif /* HAVE_DIRCACHE */
745 if (tag != tag_filename) 800 if (tag != tag_filename)
746 { 801 {
747 ep = (struct tagfile_entry *)&ramcache_hdr->tags[tag][seek]; 802 struct tagfile_entry *ep =
803 (struct tagfile_entry *)&tcramcache.hdr->tags[tag][seek];
748 strlcpy(buf, ep->tag_data, size); 804 strlcpy(buf, ep->tag_data, size);
749 805
750 return true; 806 return true;
751 } 807 }
752 } 808 }
753#endif 809#endif /* HAVE_TC_RAMCACHE */
754 810
755 if (!open_files(tcs, tag)) 811 if (!open_files(tcs, tag))
756 return false; 812 return false;
@@ -777,7 +833,7 @@ static bool retrieve(struct tagcache_search *tcs, struct index_entry *idx,
777 } 833 }
778 834
779 buf[tfe.tag_length] = '\0'; 835 buf[tfe.tag_length] = '\0';
780 836
781 return true; 837 return true;
782} 838}
783 839
@@ -1031,12 +1087,13 @@ static bool check_clauses(struct tagcache_search *tcs,
1031 if (clause->tag == tag_filename 1087 if (clause->tag == tag_filename
1032 || clause->tag == tag_virt_basename) 1088 || clause->tag == tag_virt_basename)
1033 { 1089 {
1034 retrieve(tcs, idx, tag_filename, buf, sizeof buf); 1090 retrieve(tcs, tcs->idx_id, idx, tag_filename, buf,
1091 sizeof buf);
1035 } 1092 }
1036 else 1093 else
1037 { 1094 {
1038 tfe = (struct tagfile_entry *) 1095 tfe = (struct tagfile_entry *)
1039 &ramcache_hdr->tags[clause->tag][seek]; 1096 &tcramcache.hdr->tags[clause->tag][seek];
1040 /* str points to movable data, but no locking required here, 1097 /* str points to movable data, but no locking required here,
1041 * as no yield() is following */ 1098 * as no yield() is following */
1042 str = tfe->tag_data; 1099 str = tfe->tag_data;
@@ -1044,7 +1101,7 @@ static bool check_clauses(struct tagcache_search *tcs,
1044 } 1101 }
1045 } 1102 }
1046 else 1103 else
1047#endif 1104#endif /* HAVE_TC_RAMCACHE */
1048 { 1105 {
1049 struct tagfile_entry tfe; 1106 struct tagfile_entry tfe;
1050 1107
@@ -1147,18 +1204,15 @@ static bool build_lookup_list(struct tagcache_search *tcs)
1147 tcs->seek_list_count = 0; 1204 tcs->seek_list_count = 0;
1148 1205
1149#ifdef HAVE_TC_RAMCACHE 1206#ifdef HAVE_TC_RAMCACHE
1150 if (tcs->ramsearch 1207 if (tcs->ramsearch)
1151# ifdef HAVE_DIRCACHE
1152 && (tcs->type != tag_filename || is_dircache_intact())
1153# endif
1154 )
1155 { 1208 {
1156 move_lock++; /* lock because below makes a pointer to movable data */ 1209 tcrc_buffer_lock(); /* lock because below makes a pointer to movable data */
1210
1157 for (i = tcs->seek_pos; i < current_tcmh.tch.entry_count; i++) 1211 for (i = tcs->seek_pos; i < current_tcmh.tch.entry_count; i++)
1158 { 1212 {
1159 struct tagcache_seeklist_entry *seeklist; 1213 struct tagcache_seeklist_entry *seeklist;
1160 /* idx points to movable data, don't yield or reload */ 1214 /* idx points to movable data, don't yield or reload */
1161 struct index_entry *idx = &ramcache_hdr->indices[i]; 1215 struct index_entry *idx = &tcramcache.hdr->indices[i];
1162 if (tcs->seek_list_count == SEEK_LIST_SIZE) 1216 if (tcs->seek_list_count == SEEK_LIST_SIZE)
1163 break ; 1217 break ;
1164 1218
@@ -1192,13 +1246,14 @@ static bool build_lookup_list(struct tagcache_search *tcs)
1192 seeklist->idx_id = i; 1246 seeklist->idx_id = i;
1193 tcs->seek_list_count++; 1247 tcs->seek_list_count++;
1194 } 1248 }
1195 move_lock--; 1249
1196 1250 tcrc_buffer_unlock();
1251
1197 tcs->seek_pos = i; 1252 tcs->seek_pos = i;
1198 1253
1199 return tcs->seek_list_count > 0; 1254 return tcs->seek_list_count > 0;
1200 } 1255 }
1201#endif 1256#endif /* HAVE_TC_RAMCACHE */
1202 1257
1203 if (tcs->masterfd < 0) 1258 if (tcs->masterfd < 0)
1204 { 1259 {
@@ -1339,7 +1394,7 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
1339 tcs->ramsearch = tc_stat.ramcache; 1394 tcs->ramsearch = tc_stat.ramcache;
1340 if (tcs->ramsearch) 1395 if (tcs->ramsearch)
1341 { 1396 {
1342 tcs->entry_count = ramcache_hdr->entry_count[tcs->type]; 1397 tcs->entry_count = tcramcache.hdr->entry_count[tcs->type];
1343 } 1398 }
1344 else 1399 else
1345#endif 1400#endif
@@ -1510,34 +1565,24 @@ static bool get_next(struct tagcache_search *tcs)
1510#ifdef HAVE_DIRCACHE 1565#ifdef HAVE_DIRCACHE
1511 if (tcs->type == tag_filename && (flag & FLAG_DIRCACHE)) 1566 if (tcs->type == tag_filename && (flag & FLAG_DIRCACHE))
1512 { 1567 {
1513 if (is_dircache_intact()) 1568 ssize_t len = dircache_get_fileref_path(&tcrc_dcfrefs[tcs->idx_id],
1569 buf, sizeof (buf));
1570 if (len >= 0)
1514 { 1571 {
1515 size_t len = dircache_copy_path(tcs->position, buf, sizeof buf);
1516 tcs->result_len = len + 1; 1572 tcs->result_len = len + 1;
1517 tcs->result = buf; 1573 tcs->result = buf;
1518 tcs->ramresult = false; 1574 tcs->ramresult = false;
1519
1520 return true; 1575 return true;
1521 } 1576 }
1522 else 1577 /* else do it the hard way */
1523 {
1524 /* The seek is useless now, there's nothing we can return. */
1525 logf("get_next: dircache gone, cannot read file name");
1526 tagcache_unload_ramcache();
1527 // XXX do this when there's a way to not trigger an
1528 // update before reloading:
1529 // tagcache_start_scan();
1530 tcs->valid = false;
1531 return false;
1532 }
1533 } 1578 }
1534 else
1535#endif /* HAVE_DIRCACHE */ 1579#endif /* HAVE_DIRCACHE */
1580
1536 if (tcs->type != tag_filename) 1581 if (tcs->type != tag_filename)
1537 { 1582 {
1538 struct tagfile_entry *ep; 1583 struct tagfile_entry *ep;
1539 1584
1540 ep = (struct tagfile_entry *)&ramcache_hdr->tags[tcs->type][tcs->position]; 1585 ep = (struct tagfile_entry *)&tcramcache.hdr->tags[tcs->type][tcs->position];
1541 /* don't return ep->tag_data directly as it may move */ 1586 /* don't return ep->tag_data directly as it may move */
1542 tcs->result_len = strlcpy(buf, ep->tag_data, sizeof(buf)) + 1; 1587 tcs->result_len = strlcpy(buf, ep->tag_data, sizeof(buf)) + 1;
1543 tcs->result = buf; 1588 tcs->result = buf;
@@ -1550,7 +1595,7 @@ static bool get_next(struct tagcache_search *tcs)
1550 return true; 1595 return true;
1551 } 1596 }
1552 } 1597 }
1553#endif 1598#endif /* HAVE_TC_RAMCACHE */
1554 1599
1555 if (!open_files(tcs, tcs->type)) 1600 if (!open_files(tcs, tcs->type))
1556 { 1601 {
@@ -1616,7 +1661,7 @@ bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
1616 if (!get_index(tcs->masterfd, idxid, &idx, true)) 1661 if (!get_index(tcs->masterfd, idxid, &idx, true))
1617 return false; 1662 return false;
1618 1663
1619 return retrieve(tcs, &idx, tag, buf, size); 1664 return retrieve(tcs, idxid, &idx, tag, buf, size);
1620} 1665}
1621 1666
1622static bool update_master_header(void) 1667static bool update_master_header(void)
@@ -1674,7 +1719,7 @@ void tagcache_search_finish(struct tagcache_search *tcs)
1674#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 1719#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1675static struct tagfile_entry *get_tag(const struct index_entry *entry, int tag) 1720static struct tagfile_entry *get_tag(const struct index_entry *entry, int tag)
1676{ 1721{
1677 return (struct tagfile_entry *)&ramcache_hdr->tags[tag][entry->tag_seek[tag]]; 1722 return (struct tagfile_entry *)&tcramcache.hdr->tags[tag][entry->tag_seek[tag]];
1678} 1723}
1679 1724
1680static long get_tag_numeric(const struct index_entry *entry, int tag, int idx_id) 1725static long get_tag_numeric(const struct index_entry *entry, int tag, int idx_id)
@@ -1697,11 +1742,11 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
1697 return false; 1742 return false;
1698 1743
1699 /* Find the corresponding entry in tagcache. */ 1744 /* Find the corresponding entry in tagcache. */
1700 idx_id = find_entry_ram(filename, -1); 1745 idx_id = find_entry_ram(filename);
1701 if (idx_id < 0) 1746 if (idx_id < 0)
1702 return false; 1747 return false;
1703 1748
1704 entry = &ramcache_hdr->indices[idx_id]; 1749 entry = &tcramcache.hdr->indices[idx_id];
1705 1750
1706 memset(id3, 0, sizeof(struct mp3entry)); 1751 memset(id3, 0, sizeof(struct mp3entry));
1707 char* buf = id3->id3v2buf; 1752 char* buf = id3->id3v2buf;
@@ -1761,14 +1806,7 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
1761 1806
1762 return true; 1807 return true;
1763} 1808}
1764#elif defined (HAVE_TC_RAMCACHE) 1809#endif /* defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) */
1765/* temporary dummy function until integration is sorted out --jethead71 */
1766bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
1767{
1768 return false;
1769 (void)id3; (void)filename;
1770}
1771#endif
1772 1810
1773static inline void write_item(const char *item) 1811static inline void write_item(const char *item)
1774{ 1812{
@@ -1799,22 +1837,18 @@ static int check_if_empty(char **tag)
1799 return length + 1; 1837 return length + 1;
1800} 1838}
1801 1839
1802#define ADD_TAG(entry,tag,data) \
1803 /* Adding tag */ \
1804 entry.tag_offset[tag] = offset; \
1805 entry.tag_length[tag] = check_if_empty(data); \
1806 offset += entry.tag_length[tag]
1807/* GCC 3.4.6 for Coldfire can choose to inline this function. Not a good 1840/* GCC 3.4.6 for Coldfire can choose to inline this function. Not a good
1808 * idea, as it uses lots of stack and is called from a recursive function 1841 * idea, as it uses lots of stack and is called from a recursive function
1809 * (check_dir). 1842 * (check_dir).
1810 */ 1843 */
1811static void __attribute__ ((noinline)) add_tagcache(char *path, 1844static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
1812 unsigned long mtime
1813#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1814 ,int dc
1815#endif
1816 )
1817{ 1845{
1846 #define ADD_TAG(entry, tag, data) \
1847 /* Adding tag */ \
1848 entry.tag_offset[tag] = offset; \
1849 entry.tag_length[tag] = check_if_empty(data); \
1850 offset += entry.tag_length[tag]
1851
1818 struct mp3entry id3; 1852 struct mp3entry id3;
1819 struct temp_file_entry entry; 1853 struct temp_file_entry entry;
1820 bool ret; 1854 bool ret;
@@ -1830,12 +1864,13 @@ static void __attribute__ ((noinline)) add_tagcache(char *path,
1830 /* Crude logging for the sim - to aid in debugging */ 1864 /* Crude logging for the sim - to aid in debugging */
1831 int logfd = open(ROCKBOX_DIR "/database.log", 1865 int logfd = open(ROCKBOX_DIR "/database.log",
1832 O_WRONLY | O_APPEND | O_CREAT, 0666); 1866 O_WRONLY | O_APPEND | O_CREAT, 0666);
1833 if (logfd >= 0) { 1867 if (logfd >= 0)
1868 {
1834 write(logfd, path, strlen(path)); 1869 write(logfd, path, strlen(path));
1835 write(logfd, "\n", 1); 1870 write(logfd, "\n", 1);
1836 close(logfd); 1871 close(logfd);
1837 } 1872 }
1838#endif 1873#endif /* SIMULATOR */
1839 1874
1840 if (cachefd < 0) 1875 if (cachefd < 0)
1841 return ; 1876 return ;
@@ -1854,7 +1889,7 @@ static void __attribute__ ((noinline)) add_tagcache(char *path,
1854 1889
1855 /* Check if the file is already cached. */ 1890 /* Check if the file is already cached. */
1856#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 1891#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1857 idx_id = find_entry_ram(path, dc); 1892 idx_id = find_entry_ram(path);
1858#endif 1893#endif
1859 1894
1860 /* Be sure the entry doesn't exist. */ 1895 /* Be sure the entry doesn't exist. */
@@ -1979,7 +2014,10 @@ static void __attribute__ ((noinline)) add_tagcache(char *path,
1979 { 2014 {
1980 write_item(id3.title); 2015 write_item(id3.title);
1981 } 2016 }
1982 total_entry_count++; 2017
2018 total_entry_count++;
2019
2020 #undef ADD_TAG
1983} 2021}
1984 2022
1985static bool tempbuf_insert(char *str, int id, int idx_id, bool unique) 2023static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
@@ -2302,7 +2340,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
2302 * Skip unless the entry is marked as being deleted 2340 * Skip unless the entry is marked as being deleted
2303 * or the data has already been resurrected. 2341 * or the data has already been resurrected.
2304 */ 2342 */
2305 if (!(idx.flag & FLAG_DELETED) || idx.flag & FLAG_RESURRECTED) 2343 if (!(idx.flag & FLAG_DELETED) || (idx.flag & FLAG_RESURRECTED))
2306 continue; 2344 continue;
2307 2345
2308 /* Now try to match the entry. */ 2346 /* Now try to match the entry. */
@@ -2938,8 +2976,6 @@ static bool commit(void)
2938#ifdef HAVE_TC_RAMCACHE 2976#ifdef HAVE_TC_RAMCACHE
2939 bool ramcache_buffer_stolen = false; 2977 bool ramcache_buffer_stolen = false;
2940#endif 2978#endif
2941 bool local_allocation = false;
2942
2943 logf("committing tagcache"); 2979 logf("committing tagcache");
2944 2980
2945 while (write_lock) 2981 while (write_lock)
@@ -2990,9 +3026,6 @@ static bool commit(void)
2990 read_lock++; 3026 read_lock++;
2991 3027
2992 /* Try to steal every buffer we can :) */ 3028 /* Try to steal every buffer we can :) */
2993 if (tempbuf_size == 0)
2994 local_allocation = true;
2995
2996#ifdef HAVE_DIRCACHE 3029#ifdef HAVE_DIRCACHE
2997 if (tempbuf_size == 0) 3030 if (tempbuf_size == 0)
2998 { 3031 {
@@ -3007,13 +3040,13 @@ static bool commit(void)
3007#ifdef HAVE_TC_RAMCACHE 3040#ifdef HAVE_TC_RAMCACHE
3008 if (tempbuf_size == 0 && tc_stat.ramcache_allocated > 0) 3041 if (tempbuf_size == 0 && tc_stat.ramcache_allocated > 0)
3009 { 3042 {
3010 tempbuf = (char *)(ramcache_hdr + 1); 3043 tcrc_buffer_lock();
3044 tempbuf = (char *)(tcramcache.hdr + 1);
3011 tempbuf_size = tc_stat.ramcache_allocated - sizeof(struct ramcache_header) - 128; 3045 tempbuf_size = tc_stat.ramcache_allocated - sizeof(struct ramcache_header) - 128;
3012 tempbuf_size &= ~0x03; 3046 tempbuf_size &= ~0x03;
3013 move_lock++;
3014 ramcache_buffer_stolen = true; 3047 ramcache_buffer_stolen = true;
3015 } 3048 }
3016#endif 3049#endif /* HAVE_TC_RAMCACHE */
3017 3050
3018 /* And finally fail if there are no buffers available. */ 3051 /* And finally fail if there are no buffers available. */
3019 if (tempbuf_size == 0) 3052 if (tempbuf_size == 0)
@@ -3089,75 +3122,46 @@ static bool commit(void)
3089 tc_stat.ready = check_all_headers(); 3122 tc_stat.ready = check_all_headers();
3090 tc_stat.readyvalid = true; 3123 tc_stat.readyvalid = true;
3091 3124
3092 if (local_allocation)
3093 {
3094 tempbuf = NULL;
3095 tempbuf_size = 0;
3096 }
3097
3098#ifdef HAVE_TC_RAMCACHE 3125#ifdef HAVE_TC_RAMCACHE
3099 if (ramcache_buffer_stolen) 3126 if (ramcache_buffer_stolen)
3100 { 3127 {
3128 tempbuf = NULL;
3129 tempbuf_size = 0;
3101 ramcache_buffer_stolen = false; 3130 ramcache_buffer_stolen = false;
3102 move_lock--; 3131 tcrc_buffer_unlock();
3103 } 3132 }
3104 3133
3105 /* Reload tagcache. */ 3134 /* Reload tagcache. */
3106 if (tc_stat.ramcache_allocated > 0) 3135 if (tc_stat.ramcache_allocated > 0)
3107 tagcache_start_scan(); 3136 tagcache_start_scan();
3108#endif 3137#endif /* HAVE_TC_RAMCACHE */
3109 3138
3110 rc = true; 3139 rc = true;
3111 3140
3112commit_error: 3141commit_error:
3113#ifdef HAVE_TC_RAMCACHE 3142#ifdef HAVE_TC_RAMCACHE
3114 if (ramcache_buffer_stolen) 3143 if (ramcache_buffer_stolen)
3115 move_lock--; 3144 {
3116#endif 3145 tempbuf = NULL;
3146 tempbuf_size = 0;
3147 tcrc_buffer_unlock();
3148 }
3149#endif /* HAVE_TC_RAMCACHE */
3117 3150
3118 read_lock--; 3151 read_lock--;
3119 3152
3120#ifdef HAVE_DIRCACHE 3153#ifdef HAVE_DIRCACHE
3121 /* Resume the dircache, if we stole the buffer. */ 3154 /* Resume the dircache, if we stole the buffer. */
3122 if (dircache_buffer_stolen) 3155 if (dircache_buffer_stolen)
3156 {
3157 free_tempbuf();
3123 dircache_resume(); 3158 dircache_resume();
3124#endif 3159 }
3160#endif /* HAVE_DIRCACHE */
3125 3161
3126 return rc; 3162 return rc;
3127} 3163}
3128 3164
3129static void allocate_tempbuf(void)
3130{
3131 /* Yeah, malloc would be really nice now :) */
3132 size_t size;
3133 tempbuf_size = 0;
3134
3135#ifdef __PCTOOL__
3136 size = 32*1024*1024;
3137 tempbuf = malloc(size);
3138#else
3139 tempbuf_handle = core_alloc_maximum("tc tempbuf", &size, NULL);
3140 tempbuf = core_get_data(tempbuf_handle);
3141#endif
3142
3143 if (tempbuf)
3144 tempbuf_size = size;
3145}
3146
3147static void free_tempbuf(void)
3148{
3149 if (tempbuf_size == 0)
3150 return ;
3151
3152#ifdef __PCTOOL__
3153 free(tempbuf);
3154#else
3155 tempbuf_handle = core_free(tempbuf_handle);
3156#endif
3157 tempbuf = NULL;
3158 tempbuf_size = 0;
3159}
3160
3161#ifndef __PCTOOL__ 3165#ifndef __PCTOOL__
3162 3166
3163static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data) 3167static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data)
@@ -3645,7 +3649,7 @@ static bool delete_entry(long idx_id)
3645#ifdef HAVE_TC_RAMCACHE 3649#ifdef HAVE_TC_RAMCACHE
3646 /* At first mark the entry removed from ram cache. */ 3650 /* At first mark the entry removed from ram cache. */
3647 if (tc_stat.ramcache) 3651 if (tc_stat.ramcache)
3648 ramcache_hdr->indices[idx_id].flag |= FLAG_DELETED; 3652 tcramcache.hdr->indices[idx_id].flag |= FLAG_DELETED;
3649#endif 3653#endif
3650 3654
3651 if ( (masterfd = open_master_fd(&myhdr, true) ) < 0) 3655 if ( (masterfd = open_master_fd(&myhdr, true) ) < 0)
@@ -3684,7 +3688,7 @@ static bool delete_entry(long idx_id)
3684#ifdef HAVE_TC_RAMCACHE 3688#ifdef HAVE_TC_RAMCACHE
3685 /* Use RAM DB if available for greater speed */ 3689 /* Use RAM DB if available for greater speed */
3686 if (tc_stat.ramcache) 3690 if (tc_stat.ramcache)
3687 idxp = &ramcache_hdr->indices[i]; 3691 idxp = &tcramcache.hdr->indices[i];
3688 else 3692 else
3689#endif 3693#endif
3690 { 3694 {
@@ -3727,16 +3731,16 @@ static bool delete_entry(long idx_id)
3727 if (tc_stat.ramcache && tag != tag_filename) 3731 if (tc_stat.ramcache && tag != tag_filename)
3728 { 3732 {
3729 struct tagfile_entry *tfe; 3733 struct tagfile_entry *tfe;
3730 int32_t *seek = &ramcache_hdr->indices[idx_id].tag_seek[tag]; 3734 int32_t *seek = &tcramcache.hdr->indices[idx_id].tag_seek[tag];
3731 3735
3732 tfe = (struct tagfile_entry *)&ramcache_hdr->tags[tag][*seek]; 3736 tfe = (struct tagfile_entry *)&tcramcache.hdr->tags[tag][*seek];
3733 move_lock++; /* protect tfe and seek if crc_32() yield()s */ 3737 tcrc_buffer_lock(); /* protect tfe and seek if crc_32() yield()s */
3734 *seek = crc_32(tfe->tag_data, strlen(tfe->tag_data), 0xffffffff); 3738 *seek = crc_32(tfe->tag_data, strlen(tfe->tag_data), 0xffffffff);
3735 move_lock--; 3739 tcrc_buffer_unlock();
3736 myidx.tag_seek[tag] = *seek; 3740 myidx.tag_seek[tag] = *seek;
3737 } 3741 }
3738 else 3742 else
3739#endif 3743#endif /* HAVE_TC_RAMCACHE */
3740 { 3744 {
3741 struct tagfile_entry tfe; 3745 struct tagfile_entry tfe;
3742 3746
@@ -3777,10 +3781,10 @@ static bool delete_entry(long idx_id)
3777 if (tc_stat.ramcache && tag != tag_filename) 3781 if (tc_stat.ramcache && tag != tag_filename)
3778 { 3782 {
3779 struct tagfile_entry *tagentry = 3783 struct tagfile_entry *tagentry =
3780 (struct tagfile_entry *)&ramcache_hdr->tags[tag][oldseek]; 3784 (struct tagfile_entry *)&tcramcache.hdr->tags[tag][oldseek];
3781 tagentry->tag_data[0] = '\0'; 3785 tagentry->tag_data[0] = '\0';
3782 } 3786 }
3783#endif 3787#endif /* HAVE_TC_RAMCACHE */
3784 3788
3785 /* Open the index file, which contains the tag names. */ 3789 /* Open the index file, which contains the tag names. */
3786 if (fd < 0) 3790 if (fd < 0)
@@ -3829,13 +3833,13 @@ static bool delete_entry(long idx_id)
3829 return false; 3833 return false;
3830} 3834}
3831 3835
3832#ifndef __PCTOOL__
3833/** 3836/**
3834 * Returns true if there is an event waiting in the queue 3837 * Returns true if there is an event waiting in the queue
3835 * that requires the current operation to be aborted. 3838 * that requires the current operation to be aborted.
3836 */ 3839 */
3837static bool check_event_queue(void) 3840static bool check_event_queue(void)
3838{ 3841{
3842#ifndef __PCTOOL__
3839 struct queue_event ev; 3843 struct queue_event ev;
3840 3844
3841 if(!queue_peek(&tagcache_queue, &ev)) 3845 if(!queue_peek(&tagcache_queue, &ev))
@@ -3848,10 +3852,10 @@ static bool check_event_queue(void)
3848 case SYS_USB_CONNECTED: 3852 case SYS_USB_CONNECTED:
3849 return true; 3853 return true;
3850 } 3854 }
3855#endif /* __PCTOOL__ */
3851 3856
3852 return false; 3857 return false;
3853} 3858}
3854#endif
3855 3859
3856#ifdef HAVE_TC_RAMCACHE 3860#ifdef HAVE_TC_RAMCACHE
3857 3861
@@ -3859,18 +3863,18 @@ static void fix_ramcache(void* old_addr, void* new_addr)
3859{ 3863{
3860 ptrdiff_t offpos = new_addr - old_addr; 3864 ptrdiff_t offpos = new_addr - old_addr;
3861 for (int i = 0; i < TAG_COUNT; i++) 3865 for (int i = 0; i < TAG_COUNT; i++)
3862 ramcache_hdr->tags[i] += offpos; 3866 tcramcache.hdr->tags[i] += offpos;
3863} 3867}
3864 3868
3865static int move_cb(int handle, void* current, void* new) 3869static int move_cb(int handle, void* current, void* new)
3866{ 3870{
3867 (void)handle; 3871 if (tcramcache.move_lock > 0)
3868 if (move_lock > 0)
3869 return BUFLIB_CB_CANNOT_MOVE; 3872 return BUFLIB_CB_CANNOT_MOVE;
3870 3873
3871 fix_ramcache(current, new); 3874 fix_ramcache(current, new);
3872 ramcache_hdr = new; 3875 tcramcache.hdr = new;
3873 return BUFLIB_CB_OK; 3876 return BUFLIB_CB_OK;
3877 (void)handle;
3874} 3878}
3875 3879
3876static struct buflib_callbacks ops = { 3880static struct buflib_callbacks ops = {
@@ -3880,13 +3884,12 @@ static struct buflib_callbacks ops = {
3880 3884
3881static bool allocate_tagcache(void) 3885static bool allocate_tagcache(void)
3882{ 3886{
3883 struct master_header tcmh;
3884 int fd;
3885
3886 /* Load the header. */ 3887 /* Load the header. */
3887 if ( (fd = open_master_fd(&tcmh, false)) < 0) 3888 struct master_header tcmh;
3889 int fd = open_master_fd(&tcmh, false);
3890 if (fd < 0)
3888 { 3891 {
3889 ramcache_hdr = NULL; 3892 tcramcache.hdr = NULL;
3890 return false; 3893 return false;
3891 } 3894 }
3892 3895
@@ -3896,22 +3899,37 @@ static bool allocate_tagcache(void)
3896 * Now calculate the required cache size plus 3899 * Now calculate the required cache size plus
3897 * some extra space for alignment fixes. 3900 * some extra space for alignment fixes.
3898 */ 3901 */
3899 tc_stat.ramcache_allocated = tcmh.tch.datasize + 256 + TAGCACHE_RESERVE + 3902 tc_stat.ramcache_allocated = 0;
3903
3904 size_t alloc_size = tcmh.tch.datasize + 256 + TAGCACHE_RESERVE +
3900 sizeof(struct ramcache_header) + TAG_COUNT*sizeof(void *); 3905 sizeof(struct ramcache_header) + TAG_COUNT*sizeof(void *);
3901 int handle = core_alloc_ex("tc ramcache", tc_stat.ramcache_allocated, &ops); 3906#ifdef HAVE_DIRCACHE
3902 ramcache_hdr = core_get_data(handle); 3907 alloc_size += tcmh.tch.entry_count*sizeof(struct dircache_fileref);
3903 memset(ramcache_hdr, 0, sizeof(struct ramcache_header)); 3908#endif
3909
3910 int handle = core_alloc_ex("tc ramcache", alloc_size, &ops);
3911 if (handle <= 0)
3912 return false;
3913
3914 void *data = core_get_data(handle);
3915
3916 tcramcache.hdr = data;
3917 tc_stat.ramcache_allocated = alloc_size;
3918
3919 memset(tcramcache.hdr, 0, sizeof(struct ramcache_header));
3904 memcpy(&current_tcmh, &tcmh, sizeof current_tcmh); 3920 memcpy(&current_tcmh, &tcmh, sizeof current_tcmh);
3905 logf("tagcache: %d bytes allocated.", tc_stat.ramcache_allocated); 3921 logf("tagcache: %lu bytes allocated.", tc_stat.ramcache_allocated);
3906 3922
3907 return true; 3923 return true;
3908} 3924}
3909 3925
3910# ifdef HAVE_EEPROM_SETTINGS 3926#ifdef HAVE_EEPROM_SETTINGS
3911static bool tagcache_dumpload(void) 3927static bool tagcache_dumpload(void)
3912{ 3928{
3913 struct statefile_header shdr; 3929 struct statefile_header shdr;
3914 int fd, rc, handle; 3930 int fd, rc, handle;
3931
3932 tcramcache.hdr = NULL;
3915 3933
3916 fd = open(TAGCACHE_STATEFILE, O_RDONLY); 3934 fd = open(TAGCACHE_STATEFILE, O_RDONLY);
3917 if (fd < 0) 3935 if (fd < 0)
@@ -3927,31 +3945,36 @@ static bool tagcache_dumpload(void)
3927 || shdr.mh.tch.magic != TAGCACHE_MAGIC) 3945 || shdr.mh.tch.magic != TAGCACHE_MAGIC)
3928 { 3946 {
3929 logf("incorrect statefile"); 3947 logf("incorrect statefile");
3930 ramcache_hdr = NULL;
3931 close(fd); 3948 close(fd);
3932 return false; 3949 return false;
3933 } 3950 }
3934 3951
3935
3936 /* Lets allocate real memory and load it */ 3952 /* Lets allocate real memory and load it */
3937 handle = core_alloc_ex("tc ramcache", shdr.tc_stat.ramcache_allocated, &ops); 3953 handle = core_alloc_ex("tc ramcache", shdr.tc_stat.ramcache_allocated, &ops);
3938 ramcache_hdr = core_get_data(handle); 3954 if (handle <= 0)
3939 move_lock++; 3955 {
3940 rc = read(fd, ramcache_hdr, shdr.tc_stat.ramcache_allocated); 3956 logf("alloc failure");
3941 move_lock--; 3957 return false;
3958 }
3959
3960 tcrc_buffer_lock();
3961 tcramcache.hdr = core_get_data(handle);
3962 rc = read(fd, tcramcache.hdr, shdr.tc_stat.ramcache_allocated);
3963 tcrc_buffer_unlock();
3964
3942 close(fd); 3965 close(fd);
3943 3966
3944 if (rc != shdr.tc_stat.ramcache_allocated) 3967 if (rc != shdr.tc_stat.ramcache_allocated)
3945 { 3968 {
3946 logf("read failure!"); 3969 logf("read failure!");
3947 ramcache_hdr = NULL; 3970 core_free(handle);
3948 return false; 3971 return false;
3949 } 3972 }
3950 3973
3951 memcpy(&tc_stat, &shdr.tc_stat, sizeof(struct tagcache_stat)); 3974 tc_stat = shdr.tc_stat;
3952 3975
3953 /* Now fix the pointers */ 3976 /* Now fix the pointers */
3954 fix_ramcache(shdr.hdr, ramcache_hdr); 3977 fix_ramcache(shdr.hdr, tcramcache.hdr);
3955 3978
3956 /* Load the tagcache master header (should match the actual DB file header). */ 3979 /* Load the tagcache master header (should match the actual DB file header). */
3957 memcpy(&current_tcmh, &shdr.mh, sizeof current_tcmh); 3980 memcpy(&current_tcmh, &shdr.mh, sizeof current_tcmh);
@@ -3976,63 +3999,62 @@ static bool tagcache_dumpsave(void)
3976 3999
3977 /* Create the header */ 4000 /* Create the header */
3978 shdr.magic = TAGCACHE_STATEFILE_MAGIC; 4001 shdr.magic = TAGCACHE_STATEFILE_MAGIC;
3979 shdr.hdr = ramcache_hdr; 4002 shdr.hdr = tcramcache.hdr;
3980 memcpy(&shdr.mh, &current_tcmh, sizeof current_tcmh); 4003 memcpy(&shdr.mh, &current_tcmh, sizeof current_tcmh);
3981 memcpy(&shdr.tc_stat, &tc_stat, sizeof tc_stat); 4004 memcpy(&shdr.tc_stat, &tc_stat, sizeof tc_stat);
3982 write(fd, &shdr, sizeof shdr); 4005 write(fd, &shdr, sizeof shdr);
3983 4006
3984 /* And dump the data too */ 4007 /* And dump the data too */
3985 move_lock++; 4008 tcrc_buffer_lock();
3986 write(fd, ramcache_hdr, tc_stat.ramcache_allocated); 4009 write(fd, tcramcache.hdr, tc_stat.ramcache_allocated);
3987 move_lock--; 4010 tcrc_buffer_unlock();
3988 close(fd); 4011 close(fd);
3989 4012
3990 return true; 4013 return true;
3991} 4014}
3992# endif 4015#endif /* HAVE_EEPROM_SETTINGS */
3993 4016
3994static bool load_tagcache(void) 4017static bool load_tagcache(void)
3995{ 4018{
3996 struct tagcache_header *tch; 4019 /* DEBUG: After tagcache commit and dircache rebuild, hdr-sturcture
3997 struct master_header tcmh; 4020 * may become corrupt. */
3998 long bytesleft = tc_stat.ramcache_allocated - sizeof(struct ramcache_header); 4021
3999 struct index_entry *idx; 4022 bool const auto_update = global_settings.tagcache_autoupdate;
4000 int rc, fd; 4023
4001 char *p; 4024 bool ok = false;
4002 int i, tag; 4025 ssize_t bytesleft = tc_stat.ramcache_allocated - sizeof(struct ramcache_header);
4003 4026 int fd;
4004# ifdef HAVE_DIRCACHE 4027
4005 while (dircache_is_initializing()) 4028#ifdef HAVE_DIRCACHE
4006 sleep(1); 4029 /* Wait for any in-progress dircache build to complete */
4030 dircache_wait();
4031#endif /* HAVE_DIRCACHE */
4007 4032
4008 dircache_set_appflag(DIRCACHE_APPFLAG_TAGCACHE);
4009# endif
4010
4011 logf("loading tagcache to ram..."); 4033 logf("loading tagcache to ram...");
4012 4034
4013 fd = open(TAGCACHE_FILE_MASTER, O_RDONLY); 4035 fd = open(TAGCACHE_FILE_MASTER, O_RDONLY);
4014 if (fd < 0) 4036 if (fd < 0)
4015 { 4037 {
4016 logf("tagcache open failed"); 4038 logf("tagcache open failed");
4017 return false; 4039 goto failure;
4018 } 4040 }
4019 4041
4042 tcrc_buffer_lock(); /* lock for the rest of the scan, simpler to handle */
4043
4044 struct master_header tcmh;
4020 if (ecread(fd, &tcmh, 1, master_header_ec, tc_stat.econ) 4045 if (ecread(fd, &tcmh, 1, master_header_ec, tc_stat.econ)
4021 != sizeof(struct master_header) 4046 != sizeof(struct master_header)
4022 || tcmh.tch.magic != TAGCACHE_MAGIC) 4047 || tcmh.tch.magic != TAGCACHE_MAGIC)
4023 { 4048 {
4024 logf("incorrect header"); 4049 logf("incorrect header");
4025 return false; 4050 goto failure;
4026 } 4051 }
4027 4052
4028 /* Master header copy should already match, this can be redundant to do. */ 4053 /* Master header copy should already match, this can be redundant to do. */
4029 memcpy(&current_tcmh, &tcmh, sizeof current_tcmh); 4054 current_tcmh = tcmh;
4030
4031 move_lock++; /* lock for the reset of the scan, simpler to handle */
4032 idx = ramcache_hdr->indices;
4033 4055
4034 /* Load the master index table. */ 4056 /* Load the master index table. */
4035 for (i = 0; i < tcmh.tch.entry_count; i++) 4057 for (int i = 0; i < tcmh.tch.entry_count; i++)
4036 { 4058 {
4037 bytesleft -= sizeof(struct index_entry); 4059 bytesleft -= sizeof(struct index_entry);
4038 if (bytesleft < 0) 4060 if (bytesleft < 0)
@@ -4041,142 +4063,157 @@ static bool load_tagcache(void)
4041 goto failure; 4063 goto failure;
4042 } 4064 }
4043 4065
4044 /* DEBUG: After tagcache commit and dircache rebuild, hdr-sturcture 4066 int rc = ecread_index_entry(fd, &tcramcache.hdr->indices[i]);
4045 * may become corrupt. */ 4067 if (rc != sizeof (struct index_entry))
4046 rc = ecread_index_entry(fd, idx);
4047 if (rc != sizeof(struct index_entry))
4048 { 4068 {
4049 logf("read error #10"); 4069 logf("read error #10");
4050 goto failure; 4070 goto failure;
4051 } 4071 }
4052
4053 idx++;
4054 } 4072 }
4055 4073
4056 close(fd); 4074 close(fd);
4075 fd = -1;
4057 4076
4058 /* Load the tags. */ 4077 /* Load the tags right after the index entries */
4059 p = (char *)idx; 4078 char *p = (char *)&tcramcache.hdr->indices[tcmh.tch.entry_count];
4060 for (tag = 0; tag < TAG_COUNT; tag++) 4079
4080 for (int tag = 0; tag < TAG_COUNT; tag++)
4061 { 4081 {
4062 struct tagfile_entry *fe; 4082 ssize_t rc;
4063 char buf[TAG_MAXLEN+32];
4064 4083
4065 if (TAGCACHE_IS_NUMERIC(tag)) 4084 if (TAGCACHE_IS_NUMERIC(tag))
4066 continue ; 4085 continue;
4067 4086
4068 //p = ((void *)p+1); 4087 p = TC_ALIGN_PTR(p, &rc);
4069 p = (char *)((long)p & ~0x03) + 0x04; 4088 bytesleft -= rc;
4070 ramcache_hdr->tags[tag] = p; 4089 if (bytesleft <= 0)
4090 {
4091 logf("Too big tagcache #10.5");
4092 goto failure;
4093 }
4094
4095 tcramcache.hdr->tags[tag] = p;
4071 4096
4072 /* Check the header. */ 4097 /* Load the header */
4073 tch = (struct tagcache_header *)p; 4098 struct tagcache_header *tch = (struct tagcache_header *)p;
4074 p += sizeof(struct tagcache_header); 4099 p += sizeof(struct tagcache_header);
4075 4100 bytesleft -= sizeof (struct tagcache_header);
4076 if ( (fd = open_tag_fd(tch, tag, false)) < 0) 4101
4077 goto failure_nofd; 4102 fd = open_tag_fd(tch, tag, false);
4078 4103 if (rc < 0)
4079 for (ramcache_hdr->entry_count[tag] = 0; 4104 goto failure;
4080 ramcache_hdr->entry_count[tag] < tch->entry_count; 4105
4081 ramcache_hdr->entry_count[tag]++) 4106 /* Load the entries for this tag */
4107 for (tcramcache.hdr->entry_count[tag] = 0;
4108 tcramcache.hdr->entry_count[tag] < tch->entry_count;
4109 tcramcache.hdr->entry_count[tag]++)
4082 { 4110 {
4083 long pos; 4111 /* Abort if we got a critical event in queue */
4084 4112 if (do_timed_yield() && check_event_queue())
4085 if (do_timed_yield()) 4113 goto failure;
4114
4115 p = TC_ALIGN_PTR(p, &rc);
4116 bytesleft -= rc;
4117 if (bytesleft <= 0)
4086 { 4118 {
4087 /* Abort if we got a critical event in queue */ 4119 logf("Too big tagcache #10.75");
4088 if (check_event_queue()) 4120 goto failure;
4089 goto failure; 4121 }
4122
4123 if (bytesleft < (ssize_t)sizeof (struct tagfile_entry))
4124 {
4125 logf("Too big tagcache #10.875");
4126 goto failure;
4090 } 4127 }
4091 4128
4092 fe = (struct tagfile_entry *)p; 4129 struct tagfile_entry *fe = (struct tagfile_entry *)p;
4093 pos = lseek(fd, 0, SEEK_CUR); 4130 off_t pos = lseek(fd, 0, SEEK_CUR);
4094 rc = ecread_tagfile_entry(fd, fe); 4131
4095 if (rc != sizeof(struct tagfile_entry)) 4132 /* Load the header for the tag itself */
4133 if (ecread_tagfile_entry(fd, fe) != sizeof(struct tagfile_entry))
4096 { 4134 {
4097 /* End of lookup table. */ 4135 /* End of lookup table. */
4098 logf("read error #11"); 4136 logf("read error #11");
4099 goto failure; 4137 goto failure;
4100 } 4138 }
4101 4139
4102 /* We have a special handling for the filename tags. */ 4140 /* We have a special handling for the filename tags; neither the
4141 paths nor the entry headers are stored; only the tagcache header
4142 and dircache references are. */
4103 if (tag == tag_filename) 4143 if (tag == tag_filename)
4104 { 4144 {
4105# ifdef HAVE_DIRCACHE 4145 int idx_id = fe->idx_id; /* gonna clobber tagfile entry */
4106 int dc; 4146 struct index_entry *idx = &tcramcache.hdr->indices[idx_id];
4107# endif 4147
4108 4148 #ifdef HAVE_DIRCACHE
4109 idx = &ramcache_hdr->indices[fe->idx_id];
4110
4111 if (fe->tag_length >= (long)sizeof(buf)-1)
4112 {
4113 read(fd, buf, 10);
4114 buf[10] = '\0';
4115 logf("TAG:%s", buf);
4116 logf("too long filename");
4117 goto failure;
4118 }
4119
4120 rc = read(fd, buf, fe->tag_length);
4121 if (rc != fe->tag_length)
4122 {
4123 logf("read error #12");
4124 goto failure;
4125 }
4126
4127 /* Check if the entry has already been removed */
4128 if (idx->flag & FLAG_DELETED)
4129 continue;
4130
4131 /* This flag must not be used yet. */
4132 if (idx->flag & FLAG_DIRCACHE) 4149 if (idx->flag & FLAG_DIRCACHE)
4133 { 4150 {
4151 /* This flag must not be used yet. */
4134 logf("internal error!"); 4152 logf("internal error!");
4135 goto failure; 4153 goto failure;
4136 } 4154 }
4137 4155
4156 p += sizeof (struct dircache_fileref);
4157 bytesleft -= sizeof (struct dircache_fileref);
4158 #endif /* HAVE_DIRCACHE */
4159
4138 if (idx->tag_seek[tag] != pos) 4160 if (idx->tag_seek[tag] != pos)
4139 { 4161 {
4140 logf("corrupt data structures!"); 4162 logf("corrupt data structures!");
4141 goto failure; 4163 goto failure;
4142 } 4164 }
4143 4165
4144 if (global_settings.tagcache_autoupdate) 4166 char filename[TAG_MAXLEN+32];
4167 if (fe->tag_length >= (long)sizeof(filename)-1)
4145 { 4168 {
4146 /* Check if entry has been removed. */ 4169 read(fd, filename, 10);
4147 #ifdef HAVE_DIRCACHE 4170 filename[10] = '\0';
4148 /* This will be very slow unless dircache is enabled 4171 logf("TAG:%s", filename);
4149 or target is flash based. */ 4172 logf("too long filename");
4150################## 4173 goto failure;
4151 if (dircache_search( /* will get this! -- jethead71 */ 4174 }
4152 dc = dircache_get_entry_id(buf); 4175
4153 if (dc < 0) 4176 if ((idx->flag & FLAG_DELETED) IFN_DIRCACHE( || !auto_update ))
4177 {
4178 if (lseek(fd, fe->tag_length, SEEK_CUR) < 0)
4154 { 4179 {
4155 logf("Entry no longer valid."); 4180 logf("read error #11.5");
4156 logf("-> %s", buf); 4181 goto failure;
4157 if (global_settings.tagcache_autoupdate)
4158 delete_entry(fe->idx_id);
4159 continue ;
4160 } 4182 }
4183 }
4184
4185 if (read(fd, filename, fe->tag_length) != fe->tag_length)
4186 {
4187 logf("read error #12");
4188 goto failure;
4189 }
4190
4191 #ifdef HAVE_DIRCACHE
4192 /* If auto updating, check storage too, otherwise simply
4193 attempt to load cache references */
4194 unsigned int searchflag = auto_update ? DCS_STORAGE_PATH :
4195 DCS_CACHED_PATH;
4161 4196
4197 int rc = dircache_search(searchflag | DCS_UPDATE_FILEREF,
4198 &tcrc_dcfrefs[idx_id], filename);
4199 if (rc > 0) /* in cache and we have fileref */
4162 idx->flag |= FLAG_DIRCACHE; 4200 idx->flag |= FLAG_DIRCACHE;
4163 idx->tag_seek[tag_filename] = dc; 4201 else if (rc == 0) /* not in cache but okay */
4164 #else /* ndef HAVE_DIRCACHE */ 4202 ;
4165 /* This will be very slow unless target is flash based; 4203 else if (auto_update)
4166 do it anyway for consistency. */ 4204 #else /* ndef HAVE_DIRCACHE */
4167 if (!file_exists(buf)) 4205 /* Check if path is no longer valid */
4168 { 4206 if (auto_update && !file_exists(filename))
4169 logf("Entry no longer valid."); 4207 #endif /* HAVE_DIRCACHE */
4170 logf("-> %s", buf); 4208 {
4171 delete_entry(fe->idx_id); 4209 logf("Entry no longer valid.");
4172 continue; 4210 logf("-> %s", filename);
4173 } 4211 delete_entry(idx_id);
4174 #endif /* HAVE_DIRCACHE */
4175 } 4212 }
4176 4213
4177 continue ; 4214 continue;
4178 } 4215 }
4179 4216
4180 bytesleft -= sizeof(struct tagfile_entry) + fe->tag_length; 4217 bytesleft -= sizeof(struct tagfile_entry) + fe->tag_length;
4181 if (bytesleft < 0) 4218 if (bytesleft < 0)
4182 { 4219 {
@@ -4187,7 +4224,7 @@ static bool load_tagcache(void)
4187 } 4224 }
4188 4225
4189 p = fe->tag_data; 4226 p = fe->tag_data;
4190 rc = read(fd, fe->tag_data, fe->tag_length); 4227 rc = read(fd, p, fe->tag_length);
4191 p += rc; 4228 p += rc;
4192 4229
4193 if (rc != fe->tag_length) 4230 if (rc != fe->tag_length)
@@ -4200,20 +4237,27 @@ static bool load_tagcache(void)
4200 goto failure; 4237 goto failure;
4201 } 4238 }
4202 } 4239 }
4240
4241 #ifdef HAVE_DIRCACHE
4242 if (tag == tag_filename)
4243 p = (char *)&tcrc_dcfrefs[tcmh.tch.entry_count];
4244 #endif /* HAVE_DIRCACHE */
4245
4203 close(fd); 4246 close(fd);
4204 } 4247 }
4205 4248
4206 tc_stat.ramcache_used = tc_stat.ramcache_allocated - bytesleft; 4249 tc_stat.ramcache_used = tc_stat.ramcache_allocated - bytesleft;
4207 logf("tagcache loaded into ram!"); 4250 logf("tagcache loaded into ram!");
4251 logf("utilization: %d%%", 100*tc_stat.ramcache_used / tc_stat.ramcache_allocated);
4208 4252
4209 move_lock--; 4253 ok = true;
4210 return true;
4211 4254
4212failure: 4255failure:
4213 close(fd); 4256 if (fd >= 0)
4214failure_nofd: 4257 close(fd);
4215 move_lock--; 4258
4216 return false; 4259 tcrc_buffer_unlock();
4260 return ok;
4217} 4261}
4218#endif /* HAVE_TC_RAMCACHE */ 4262#endif /* HAVE_TC_RAMCACHE */
4219 4263
@@ -4235,10 +4279,7 @@ static bool check_deleted_files(void)
4235 4279
4236 lseek(fd, sizeof(struct tagcache_header), SEEK_SET); 4280 lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
4237 while (ecread_tagfile_entry(fd, &tfe) == sizeof(struct tagfile_entry) 4281 while (ecread_tagfile_entry(fd, &tfe) == sizeof(struct tagfile_entry)
4238#ifndef __PCTOOL__ 4282 && !check_event_queue())
4239 && !check_event_queue()
4240#endif
4241 )
4242 { 4283 {
4243 if (tfe.tag_length >= (long)sizeof(buf)-1) 4284 if (tfe.tag_length >= (long)sizeof(buf)-1)
4244 { 4285 {
@@ -4278,7 +4319,7 @@ static bool check_deleted_files(void)
4278/* Note that this function must not be inlined, otherwise the whole point 4319/* Note that this function must not be inlined, otherwise the whole point
4279 * of having the code in a separate function is lost. 4320 * of having the code in a separate function is lost.
4280 */ 4321 */
4281static void __attribute__ ((noinline)) check_ignore(const char *dirname, 4322static void NO_INLINE check_ignore(const char *dirname,
4282 int *ignore, int *unignore) 4323 int *ignore, int *unignore)
4283{ 4324{
4284 char newpath[MAX_PATH]; 4325 char newpath[MAX_PATH];
@@ -4408,18 +4449,17 @@ static int free_search_roots(struct search_roots_ll * start)
4408 4449
4409static bool check_dir(const char *dirname, int add_files) 4450static bool check_dir(const char *dirname, int add_files)
4410{ 4451{
4411 DIR *dir;
4412 int len;
4413 int success = false; 4452 int success = false;
4414 int ignore, unignore;
4415 4453
4416 dir = opendir(dirname); 4454 DIR *dir = opendir(dirname);
4417 if (!dir) 4455 if (!dir)
4418 { 4456 {
4419 logf("tagcache: opendir(%s) failed", dirname); 4457 logf("tagcache: opendir(%s) failed", dirname);
4420 return false; 4458 return false;
4421 } 4459 }
4460
4422 /* check for a database.ignore and database.unignore */ 4461 /* check for a database.ignore and database.unignore */
4462 int ignore, unignore;
4423 check_ignore(dirname, &ignore, &unignore); 4463 check_ignore(dirname, &ignore, &unignore);
4424 4464
4425 /* don't do anything if both ignore and unignore are there */ 4465 /* don't do anything if both ignore and unignore are there */
@@ -4427,11 +4467,7 @@ static bool check_dir(const char *dirname, int add_files)
4427 add_files = unignore; 4467 add_files = unignore;
4428 4468
4429 /* Recursively scan the dir. */ 4469 /* Recursively scan the dir. */
4430#ifdef __PCTOOL__
4431 while (1)
4432#else
4433 while (!check_event_queue()) 4470 while (!check_event_queue())
4434#endif
4435 { 4471 {
4436 struct dirent *entry = readdir(dir); 4472 struct dirent *entry = readdir(dir);
4437 if (entry == NULL) 4473 if (entry == NULL)
@@ -4440,42 +4476,32 @@ static bool check_dir(const char *dirname, int add_files)
4440 break; 4476 break;
4441 } 4477 }
4442 4478
4443 if (!strcmp((char *)entry->d_name, ".") || 4479 if (is_dotdir_name(entry->d_name))
4444 !strcmp((char *)entry->d_name, ".."))
4445 continue; 4480 continue;
4446 4481
4447 struct dirinfo info = dir_get_info(dir, entry); 4482 struct dirinfo info = dir_get_info(dir, entry);
4448 4483 size_t len = strlen(curpath);
4449 yield(); 4484 path_append(&curpath[len], PA_SEP_HARD, entry->d_name,
4450 4485 sizeof (curpath) - len);
4451 len = strlen(curpath);
4452 /* don't add an extra / for curpath == / */
4453 if (len <= 1) len = 0;
4454 snprintf(&curpath[len], sizeof(curpath) - len, "/%s", entry->d_name);
4455 4486
4456 processed_dir_count++; 4487 processed_dir_count++;
4457 if (info.attribute & ATTR_DIRECTORY) 4488 if (info.attribute & ATTR_DIRECTORY)
4489 {
4458#ifndef SIMULATOR 4490#ifndef SIMULATOR
4459 { /* don't follow symlinks to dirs, but try to add it as a search root 4491 /* don't follow symlinks to dirs, but try to add it as a search root
4460 * this makes able to avoid looping in recursive symlinks */ 4492 * this makes able to avoid looping in recursive symlinks */
4461 if (info.attribute & ATTR_LINK) 4493 if (info.attribute & ATTR_LINK)
4462 add_search_root(curpath); 4494 add_search_root(curpath);
4463 else 4495 else
4496#endif /* SIMULATOR */
4464 check_dir(curpath, add_files); 4497 check_dir(curpath, add_files);
4465 } 4498 }
4466#else
4467 check_dir(curpath, add_files);
4468#endif
4469 else if (add_files) 4499 else if (add_files)
4470 { 4500 {
4471 tc_stat.curentry = curpath; 4501 tc_stat.curentry = curpath;
4472 4502
4473 /* Add a new entry to the temporary db file. */ 4503 /* Add a new entry to the temporary db file. */
4474 add_tagcache(curpath, info.mtime 4504 add_tagcache(curpath, info.mtime);
4475#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
4476 , dir->internal_entry
4477#endif
4478 );
4479 4505
4480 /* Wait until current path for debug screen is read and unset. */ 4506 /* Wait until current path for debug screen is read and unset. */
4481 while (tc_stat.syncscreen && tc_stat.curentry != NULL) 4507 while (tc_stat.syncscreen && tc_stat.curentry != NULL)
@@ -4517,8 +4543,7 @@ void do_tagcache_build(const char *path[])
4517 processed_dir_count = 0; 4543 processed_dir_count = 0;
4518 4544
4519#ifdef HAVE_DIRCACHE 4545#ifdef HAVE_DIRCACHE
4520 while (dircache_is_initializing()) 4546 dircache_wait();
4521 sleep(1);
4522#endif 4547#endif
4523 4548
4524 logf("updating tagcache"); 4549 logf("updating tagcache");
@@ -4606,7 +4631,7 @@ void do_tagcache_build(const char *path[])
4606#endif 4631#endif
4607 4632
4608#ifdef HAVE_TC_RAMCACHE 4633#ifdef HAVE_TC_RAMCACHE
4609 if (ramcache_hdr) 4634 if (tcramcache.hdr)
4610 { 4635 {
4611 /* Import runtime statistics if we just initialized the db. */ 4636 /* Import runtime statistics if we just initialized the db. */
4612 if (current_tcmh.serial == 0) 4637 if (current_tcmh.serial == 0)
@@ -4629,12 +4654,12 @@ void tagcache_build(void)
4629 4654
4630 do_tagcache_build((const char**)vect); 4655 do_tagcache_build((const char**)vect);
4631} 4656}
4632#endif 4657#endif /* __PCTOOL__ */
4633 4658
4634#ifdef HAVE_TC_RAMCACHE 4659#ifdef HAVE_TC_RAMCACHE
4635static void load_ramcache(void) 4660static void load_ramcache(void)
4636{ 4661{
4637 if (!ramcache_hdr) 4662 if (!tcramcache.hdr)
4638 return ; 4663 return ;
4639 4664
4640 cpu_boost(true); 4665 cpu_boost(true);
@@ -4647,7 +4672,7 @@ static void load_ramcache(void)
4647 /* If loading failed, it must indicate some problem with the db 4672 /* If loading failed, it must indicate some problem with the db
4648 * so disable it entirely to prevent further issues. */ 4673 * so disable it entirely to prevent further issues. */
4649 tc_stat.ready = false; 4674 tc_stat.ready = false;
4650 ramcache_hdr = NULL; 4675 tcramcache.hdr = NULL;
4651 } 4676 }
4652 4677
4653 cpu_boost(false); 4678 cpu_boost(false);
@@ -4659,7 +4684,7 @@ void tagcache_unload_ramcache(void)
4659 /* Just to make sure there is no statefile present. */ 4684 /* Just to make sure there is no statefile present. */
4660 // remove(TAGCACHE_STATEFILE); 4685 // remove(TAGCACHE_STATEFILE);
4661} 4686}
4662#endif 4687#endif /* HAVE_TC_RAMCACHE */
4663 4688
4664#ifndef __PCTOOL__ 4689#ifndef __PCTOOL__
4665static void tagcache_thread(void) 4690static void tagcache_thread(void)
@@ -4675,7 +4700,7 @@ static void tagcache_thread(void)
4675 free_tempbuf(); 4700 free_tempbuf();
4676 4701
4677#ifdef HAVE_TC_RAMCACHE 4702#ifdef HAVE_TC_RAMCACHE
4678# ifdef HAVE_EEPROM_SETTINGS 4703#ifdef HAVE_EEPROM_SETTINGS
4679 if (firmware_settings.initialized && firmware_settings.disk_clean 4704 if (firmware_settings.initialized && firmware_settings.disk_clean
4680 && global_settings.tagcache_ram) 4705 && global_settings.tagcache_ram)
4681 { 4706 {
@@ -4683,12 +4708,12 @@ static void tagcache_thread(void)
4683 } 4708 }
4684 4709
4685 remove(TAGCACHE_STATEFILE); 4710 remove(TAGCACHE_STATEFILE);
4686# endif 4711#endif /* HAVE_EEPROM_SETTINGS */
4687 4712
4688 /* Allocate space for the tagcache if found on disk. */ 4713 /* Allocate space for the tagcache if found on disk. */
4689 if (global_settings.tagcache_ram && !tc_stat.ramcache) 4714 if (global_settings.tagcache_ram && !tc_stat.ramcache)
4690 allocate_tagcache(); 4715 allocate_tagcache();
4691#endif 4716#endif /* HAVE_TC_RAMCACHE */
4692 4717
4693 cpu_boost(false); 4718 cpu_boost(false);
4694 tc_stat.initialized = true; 4719 tc_stat.initialized = true;
@@ -4741,7 +4766,7 @@ static void tagcache_thread(void)
4741 tagcache_build(); 4766 tagcache_build();
4742 } 4767 }
4743 else 4768 else
4744#endif 4769#endif /* HAVE_RC_RAMCACHE */
4745 if (global_settings.tagcache_autoupdate) 4770 if (global_settings.tagcache_autoupdate)
4746 { 4771 {
4747 tagcache_build(); 4772 tagcache_build();
@@ -4800,23 +4825,29 @@ static int get_progress(void)
4800 int total_count = -1; 4825 int total_count = -1;
4801 4826
4802#ifdef HAVE_DIRCACHE 4827#ifdef HAVE_DIRCACHE
4803 if (dircache_is_enabled()) 4828 struct dircache_info dcinfo;
4829 dircache_get_info(&dcinfo);
4830 if (dcinfo.status != DIRCACHE_IDLE)
4804 { 4831 {
4805 total_count = dircache_get_entry_count(); 4832 total_count = dcinfo.entry_count;
4806 } 4833 }
4807 else 4834 else
4808#endif 4835#endif /* HAVE_DIRCACHE */
4809#ifdef HAVE_TC_RAMCACHE 4836#ifdef HAVE_TC_RAMCACHE
4810 { 4837 {
4811 if (ramcache_hdr && tc_stat.ramcache) 4838 if (tcramcache.hdr && tc_stat.ramcache)
4812 total_count = current_tcmh.tch.entry_count; 4839 total_count = current_tcmh.tch.entry_count;
4813 } 4840 }
4814#endif 4841#endif /* HAVE_TC_RAMCACHE */
4815 4842
4816 if (total_count < 0) 4843 if (total_count < 0)
4817 return -1; 4844 return -1;
4818 4845 else if (total_count == 0)
4819 return processed_dir_count * 100 / total_count; 4846 return 0;
4847 else if (processed_dir_count > total_count)
4848 return 100;
4849 else
4850 return processed_dir_count * 100 / total_count;
4820} 4851}
4821 4852
4822struct tagcache_stat* tagcache_get_stat(void) 4853struct tagcache_stat* tagcache_get_stat(void)
diff --git a/firmware/common/dir.c b/firmware/common/dir.c
index 59f7bd747a..f89129ae34 100644
--- a/firmware/common/dir.c
+++ b/firmware/common/dir.c
@@ -311,7 +311,8 @@ int mkdir(const char *path)
311 311
312 struct filestr_base stream; 312 struct filestr_base stream;
313 struct path_component_info compinfo; 313 struct path_component_info compinfo;
314 rc = open_stream_internal(path, FF_DIR, &stream, &compinfo); 314 rc = open_stream_internal(path, FF_DIR | FF_PARENTINFO, &stream,
315 &compinfo);
315 if (rc < 0) 316 if (rc < 0)
316 { 317 {
317 DEBUGF("Can't open parent dir or path is not a directory\n"); 318 DEBUGF("Can't open parent dir or path is not a directory\n");
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c
index 0761f837e1..8a75f3bbad 100644
--- a/firmware/common/dircache.c
+++ b/firmware/common/dircache.c
@@ -610,6 +610,19 @@ static int get_index(const struct dircache_entry *ce)
610} 610}
611 611
612/** 612/**
613 * return the frontier flags for the index
614 */
615static uint32_t get_frontier(int idx)
616{
617 if (idx == 0)
618 return UINT32_MAX;
619 else if (idx > 0)
620 return get_entry(idx)->frontier;
621 else /* idx < 0 */
622 return get_idx_dcvolp(idx)->frontier;
623}
624
625/**
613 * return the sublist down pointer for the sublist that contains entry 'idx' 626 * return the sublist down pointer for the sublist that contains entry 'idx'
614 */ 627 */
615static int * get_downidxp(int idx) 628static int * get_downidxp(int idx)
@@ -2515,30 +2528,41 @@ static ssize_t get_path_sub(int idx, struct get_path_sub_data *data)
2515} 2528}
2516 2529
2517/** 2530/**
2518 * retrieve and validate the file's entry/binding serial number 2531 * validate the file's entry/binding serial number
2519 * the dircache file's serial number must match the indexed entry's or the 2532 * the dircache file's serial number must match the indexed entry's or the
2520 * file reference is stale 2533 * file reference is stale
2521 */ 2534 */
2522static dc_serial_t get_file_serialnum(const struct dircache_file *dcfilep) 2535static int check_file_serialnum(const struct dircache_file *dcfilep)
2523{ 2536{
2524 int idx = dcfilep->idx; 2537 int idx = dcfilep->idx;
2525 2538
2526 if (idx == 0 || idx < -NUM_VOLUMES) 2539 if (idx == 0 || idx < -NUM_VOLUMES)
2527 return 0; 2540 return -EBADF;
2541
2542 dc_serial_t serialnum = dcfilep->serialnum;
2528 2543
2529 dc_serial_t serialnum; 2544 if (serialnum == 0)
2545 return -EBADF;
2546
2547 dc_serial_t s;
2530 2548
2531 if (idx > 0) 2549 if (idx > 0)
2532 { 2550 {
2533 struct dircache_entry *ce = get_entry(idx); 2551 struct dircache_entry *ce = get_entry(idx);
2534 serialnum = ce ? ce->serialnum : 0; 2552 if (!ce || !(s = ce->serialnum))
2553 return -EBADF;
2535 } 2554 }
2536 else 2555 else /* idx < 0 */
2537 { 2556 {
2538 serialnum = get_idx_dcvolp(idx)->serialnum; 2557 struct dircache_volume *dcvolp = get_idx_dcvolp(idx);
2558 if (!(s = dcvolp->serialnum))
2559 return -EBADF;
2539 } 2560 }
2540 2561
2541 return serialnum == dcfilep->serialnum ? serialnum : 0; 2562 if (serialnum != s)
2563 return -EBADF;
2564
2565 return 0;
2542} 2566}
2543 2567
2544/** 2568/**
@@ -2582,6 +2606,8 @@ void dircache_fileref_init(struct dircache_fileref *dcfrefp)
2582 * failure - a negative value 2606 * failure - a negative value
2583 * 2607 *
2584 * errors: 2608 * errors:
2609 * EBADF - Bad file number
2610 * EFAULT - Bad address
2585 * ENOENT - No such file or directory 2611 * ENOENT - No such file or directory
2586 */ 2612 */
2587ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char *buf, 2613ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char *buf,
@@ -2589,6 +2615,9 @@ ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char *
2589{ 2615{
2590 ssize_t rc; 2616 ssize_t rc;
2591 2617
2618 if (!dcfrefp)
2619 FILE_ERROR_RETURN(EFAULT, -1);
2620
2592 /* if missing buffer space, still return what's needed a la strlcpy */ 2621 /* if missing buffer space, still return what's needed a la strlcpy */
2593 if (!buf) 2622 if (!buf)
2594 size = 0; 2623 size = 0;
@@ -2600,10 +2629,11 @@ ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char *
2600 /* first and foremost, there must be a cache and the serial number must 2629 /* first and foremost, there must be a cache and the serial number must
2601 check out */ 2630 check out */
2602 if (!dircache_runinfo.handle) 2631 if (!dircache_runinfo.handle)
2603 FILE_ERROR(ENOENT, -1); 2632 FILE_ERROR(EBADF, -2);
2604 2633
2605 if (get_file_serialnum(&dcfrefp->dcfile) == 0) 2634 rc = check_file_serialnum(&dcfrefp->dcfile);
2606 FILE_ERROR(ENOENT, -2); 2635 if (rc < 0)
2636 FILE_ERROR(-rc, -3);
2607 2637
2608 struct get_path_sub_data data = 2638 struct get_path_sub_data data =
2609 { 2639 {
@@ -2614,10 +2644,10 @@ ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char *
2614 2644
2615 rc = get_path_sub(dcfrefp->dcfile.idx, &data); 2645 rc = get_path_sub(dcfrefp->dcfile.idx, &data);
2616 if (rc < 0) 2646 if (rc < 0)
2617 FILE_ERROR(ENOENT, rc * 10 - 3); 2647 FILE_ERROR(ENOENT, rc * 10 - 4);
2618 2648
2619 if (data.serialhash != dcfrefp->serialhash) 2649 if (data.serialhash != dcfrefp->serialhash)
2620 FILE_ERROR(ENOENT, -4); 2650 FILE_ERROR(ENOENT, -5);
2621 2651
2622file_error: 2652file_error:
2623 dircache_unlock(); 2653 dircache_unlock();
@@ -2626,11 +2656,19 @@ file_error:
2626 2656
2627/** 2657/**
2628 * Test a path to various levels of rigor and optionally return dircache file 2658 * Test a path to various levels of rigor and optionally return dircache file
2629 * info for the given path 2659 * info for the given path.
2660 *
2661 * If the file reference is used, it is checked first and the path is checked
2662 * only if all specified file reference checks fail.
2630 * 2663 *
2631 * returns: 2664 * returns:
2632 * success: 0 2665 * success: 0 = not cached (very weak)
2666 * 1 = serial number checks out for the reference (weak)
2667 * 2 = serial number and hash check out for the reference (medium)
2668 * 3 = path is valid; reference updated if specified (strong)
2633 * failure: a negative value 2669 * failure: a negative value
2670 * if file definitely doesn't exist (errno = ENOENT)
2671 * other error
2634 * 2672 *
2635 * errors (including but not limited to): 2673 * errors (including but not limited to):
2636 * EFAULT - Bad address 2674 * EFAULT - Bad address
@@ -2638,78 +2676,121 @@ file_error:
2638 * ENAMETOOLONG - File or path name too long 2676 * ENAMETOOLONG - File or path name too long
2639 * ENOENT - No such file or directory 2677 * ENOENT - No such file or directory
2640 * ENOTDIR - Not a directory 2678 * ENOTDIR - Not a directory
2641 * ENXIO - No such device or address
2642 */ 2679 */
2643int dircache_search(unsigned int flags, struct dircache_fileref *dcfrefp, const char *path) 2680int dircache_search(unsigned int flags, struct dircache_fileref *dcfrefp,
2681 const char *path)
2644{ 2682{
2645 int rc;
2646
2647 if (!(flags & (DCS_FILEREF | DCS_CACHED_PATH))) 2683 if (!(flags & (DCS_FILEREF | DCS_CACHED_PATH)))
2648 FILE_ERROR_RETURN(EINVAL, -1); /* search nothing? */ 2684 FILE_ERROR_RETURN(EINVAL, -1); /* search nothing? */
2649 2685
2650 dircache_lock(); 2686 if (!dcfrefp && (flags & (DCS_FILEREF | DCS_UPDATE_FILEREF)))
2687 FILE_ERROR_RETURN(EFAULT, -2); /* bad! */
2651 2688
2652 if (!dircache_runinfo.handle) 2689 int rc = 0;
2653 FILE_ERROR(ENOENT, -2);
2654 2690
2655 if (flags & DCS_FILEREF) 2691 dircache_lock();
2656 {
2657 if (!dcfrefp)
2658 FILE_ERROR(EFAULT, -3);
2659 2692
2660 if (get_file_serialnum(&dcfrefp->dcfile) != 0) 2693 /* -- File reference search -- */
2694 if (!dircache_runinfo.handle)
2695 ; /* cache not enabled; not cached */
2696 else if (!(flags & DCS_FILEREF))
2697 ; /* don't use fileref */
2698 else if (check_file_serialnum(&dcfrefp->dcfile) < 0)
2699 ; /* serial number bad */
2700 else if (!(flags & _DCS_VERIFY_FLAG))
2701 rc = 1; /* only check idx and serialnum */
2702 else if (get_file_serialhash(&dcfrefp->dcfile) == dcfrefp->serialhash)
2703 rc = 2; /* reference is most likely still valid */
2704
2705 /* -- Path cache and storage search -- */
2706 if (rc > 0)
2707 ; /* rc > 0 */ /* found by file reference */
2708 else if (!(flags & DCS_CACHED_PATH))
2709 ; /* rc = 0 */ /* reference bad/unused and no path */
2710 else
2711 { /* rc = 0 */ /* check path with cache and/or storage */
2712 struct path_component_info compinfo;
2713 struct filestr_base stream;
2714 unsigned int ffcache = (flags & _DCS_STORAGE_FLAG) ? 0 : FF_CACHEONLY;
2715 int err = errno;
2716 int rc2 = open_stream_internal(path, ffcache | FF_ANYTYPE | FF_PROBE |
2717 FF_INFO | FF_PARENTINFO, &stream,
2718 &compinfo);
2719 if (rc2 <= 0)
2661 { 2720 {
2662 if (!(flags & _DCS_VERIFY_FLAG)) 2721 if (ffcache == 0)
2663 goto file_success; /* no robust verification wanted */ 2722 {
2664 2723 /* checked storage too: absent for sure */
2665 if (get_file_serialhash(&dcfrefp->dcfile) == dcfrefp->serialhash) 2724 FILE_ERROR(rc2 ? ERRNO : ENOENT, rc2 * 10 - 5);
2666 goto file_success; /* reference is most likely still valid */ 2725 }
2667 }
2668
2669 if (!(flags & DCS_CACHED_PATH))
2670 FILE_ERROR(ENOENT, -4); /* no path search wanted */
2671 }
2672 2726
2673 if (flags & DCS_CACHED_PATH) 2727 if (rc2 < 0)
2674 { 2728 {
2675 const bool update = flags & DCS_UPDATE_FILEREF; 2729 /* no base info available */
2676 struct path_component_info *compinfop = NULL; 2730 if (errno != ENOENT)
2731 FILE_ERROR(ERRNO, rc2 * 10 - 6);
2677 2732
2678 if (update) 2733 /* only cache; something didn't exist: indecisive */
2679 { 2734 errno = err;
2680 if (!dcfrefp) 2735 FILE_ERROR(ERRNO, RC); /* rc = 0 */
2681 FILE_ERROR(EFAULT, -5); 2736 }
2682 2737
2683 compinfop = alloca(sizeof (*compinfop)); 2738 struct dircache_file *dcfp = &compinfo.parentinfo.dcfile;
2739 if (get_frontier(dcfp->idx) == FRONTIER_SETTLED)
2740 FILE_ERROR(ENOENT, -7); /* parent not a frontier; absent */
2741 /* else checked only cache; parent is incomplete: indecisive */
2684 } 2742 }
2685 2743 else
2686 struct filestr_base stream;
2687 rc = open_stream_internal(path, FF_ANYTYPE | FF_PROBE | FF_SELFINFO |
2688 ((flags & _DCS_STORAGE_FLAG) ? 0 : FF_CACHEONLY),
2689 &stream, compinfop);
2690 if (rc <= 0)
2691 { 2744 {
2692 if (update) 2745 struct dircache_file *dcfp = &compinfo.info.dcfile;
2693 dircache_fileref_init(dcfrefp); 2746 if (dcfp->serialnum != 0)
2694 2747 {
2695 FILE_ERROR(rc ? ERRNO : ENOENT, rc * 10 - 6); 2748 /* found by path in the cache afterall */
2696 } 2749 if (flags & DCS_UPDATE_FILEREF)
2750 {
2751 dcfrefp->dcfile = *dcfp;
2752 dcfrefp->serialhash = get_file_serialhash(dcfp);
2753 }
2697 2754
2698 if (update) 2755 rc = 3;
2699 { 2756 }
2700 dcfrefp->dcfile = compinfop->info.dcfile;
2701 dcfrefp->serialhash = get_file_serialhash(&compinfop->info.dcfile);
2702 } 2757 }
2703 } 2758 }
2704 2759
2705file_success:
2706 rc = 0;
2707
2708file_error: 2760file_error:
2761 if (rc <= 0 && (flags & DCS_UPDATE_FILEREF))
2762 dircache_fileref_init(dcfrefp);
2763
2709 dircache_unlock(); 2764 dircache_unlock();
2710 return rc; 2765 return rc;
2711} 2766}
2712 2767
2768/**
2769 * Compare dircache file references (no validity check is made)
2770 *
2771 * returns: 0 - no match
2772 * 1 - indexes match
2773 * 2 - serial numbers match
2774 * 3 - serial and hashes match
2775 */
2776int dircache_fileref_cmp(const struct dircache_fileref *dcfrefp1,
2777 const struct dircache_fileref *dcfrefp2)
2778{
2779 int cmp = 0;
2780
2781 if (dcfrefp1->dcfile.idx == dcfrefp2->dcfile.idx)
2782 {
2783 cmp++;
2784 if (dcfrefp1->dcfile.serialnum == dcfrefp2->dcfile.serialnum)
2785 {
2786 cmp++;
2787 if (dcfrefp1->serialhash == dcfrefp2->serialhash)
2788 cmp++;
2789 }
2790 }
2791
2792 return cmp;
2793}
2713 2794
2714/** Debug screen/info stuff **/ 2795/** Debug screen/info stuff **/
2715 2796
diff --git a/firmware/common/file.c b/firmware/common/file.c
index 1f93824dc8..028bdbe9f0 100644
--- a/firmware/common/file.c
+++ b/firmware/common/file.c
@@ -354,6 +354,10 @@ static int open_internal_inner2(const char *path,
354 int rc; 354 int rc;
355 355
356 struct path_component_info compinfo; 356 struct path_component_info compinfo;
357
358 if (callflags & FF_CREAT)
359 callflags |= FF_PARENTINFO;
360
357 rc = open_stream_internal(path, callflags, &file->stream, &compinfo); 361 rc = open_stream_internal(path, callflags, &file->stream, &compinfo);
358 if (rc < 0) 362 if (rc < 0)
359 { 363 {
@@ -989,7 +993,8 @@ int rename(const char *old, const char *new)
989 file_internal_lock_WRITER(); 993 file_internal_lock_WRITER();
990 994
991 /* open 'old'; it must exist */ 995 /* open 'old'; it must exist */
992 open1rc = open_stream_internal(old, FF_ANYTYPE, &oldstr, &oldinfo); 996 open1rc = open_stream_internal(old, FF_ANYTYPE | FF_PARENTINFO, &oldstr,
997 &oldinfo);
993 if (open1rc <= 0) 998 if (open1rc <= 0)
994 { 999 {
995 DEBUGF("Failed opening old: %d\n", open1rc); 1000 DEBUGF("Failed opening old: %d\n", open1rc);
@@ -1014,7 +1019,8 @@ int rename(const char *old, const char *new)
1014 newinfo.prefixp = oldstr.infop; 1019 newinfo.prefixp = oldstr.infop;
1015 } 1020 }
1016 1021
1017 open2rc = open_stream_internal(new, callflags, &newstr, &newinfo); 1022 open2rc = open_stream_internal(new, callflags | FF_PARENTINFO, &newstr,
1023 &newinfo);
1018 if (open2rc < 0) 1024 if (open2rc < 0)
1019 { 1025 {
1020 DEBUGF("Failed opening new file: %d\n", open2rc); 1026 DEBUGF("Failed opening new file: %d\n", open2rc);
diff --git a/firmware/common/file_internal.c b/firmware/common/file_internal.c
index 75fb21e8a6..8fee802f6f 100644
--- a/firmware/common/file_internal.c
+++ b/firmware/common/file_internal.c
@@ -351,10 +351,10 @@ static int fill_path_compinfo(struct pathwalk *walkp,
351 compinfo->length = compp->length; 351 compinfo->length = compp->length;
352 compinfo->attr = compp->attr; 352 compinfo->attr = compp->attr;
353 compinfo->filesize = walkp->filesize; 353 compinfo->filesize = walkp->filesize;
354 if (!(walkp->callflags & FF_SELFINFO)) 354 if (walkp->callflags & FF_INFO)
355 compinfo->parentinfo = (compp->nextp ?: compp)->info;
356 else
357 compinfo->info = compp->info; 355 compinfo->info = compp->info;
356 if (walkp->callflags & FF_PARENTINFO)
357 compinfo->parentinfo = (compp->nextp ?: compp)->info;
358 } 358 }
359 359
360 return rc; 360 return rc;
@@ -571,9 +571,9 @@ int open_stream_internal(const char *path, unsigned int callflags,
571 FILE_ERROR(path ? ENOENT : EFAULT, -1); 571 FILE_ERROR(path ? ENOENT : EFAULT, -1);
572 } 572 }
573 573
574 /* if !compinfo, then the result of this check is not visible anyway */ 574 /* if !compinfo then these cannot be returned anyway */
575 if (!compinfo) 575 if (!compinfo)
576 callflags &= ~FF_CHECKPREFIX; 576 callflags &= ~(FF_INFO | FF_PARENTINFO | FF_CHECKPREFIX);
577 577
578 /* This lets it be passed quietly to directory scanning */ 578 /* This lets it be passed quietly to directory scanning */
579 stream->flags = callflags & FF_MASK; 579 stream->flags = callflags & FF_MASK;
diff --git a/firmware/include/dircache.h b/firmware/include/dircache.h
index d73c6f6e81..2cf838e539 100644
--- a/firmware/include/dircache.h
+++ b/firmware/include/dircache.h
@@ -69,6 +69,9 @@ typedef uint32_t dc_serial_t;
69/** 69/**
70 ****************************************************************************/ 70 ****************************************************************************/
71 71
72#define IF_DIRCACHE(...) __VA_ARGS__
73#define IFN_DIRCACHE(...)
74
72#if CONFIG_PLATFORM & PLATFORM_NATIVE 75#if CONFIG_PLATFORM & PLATFORM_NATIVE
73/* native dircache is lower-level than on a hosted target */ 76/* native dircache is lower-level than on a hosted target */
74#define DIRCACHE_NATIVE 77#define DIRCACHE_NATIVE
@@ -169,6 +172,9 @@ enum dircache_search_flags
169int dircache_search(unsigned int flags, struct dircache_fileref *dcfrefp, 172int dircache_search(unsigned int flags, struct dircache_fileref *dcfrefp,
170 const char *path); 173 const char *path);
171 174
175int dircache_fileref_cmp(const struct dircache_fileref *dcfrefp1,
176 const struct dircache_fileref *dcfrefp2);
177
172 178
173/** Debug screen/info stuff **/ 179/** Debug screen/info stuff **/
174 180
@@ -202,6 +208,11 @@ int dircache_save(void);
202 208
203void dircache_init(size_t last_size) INIT_ATTR; 209void dircache_init(size_t last_size) INIT_ATTR;
204 210
211#else /* !HAVE_DIRCACHE */
212
213#define IF_DIRCACHE(...)
214#define IFN_DIRCACHE(...) __VA_ARGS__
215
205#endif /* HAVE_DIRCACHE */ 216#endif /* HAVE_DIRCACHE */
206 217
207#endif /* _DIRCACHE_H */ 218#endif /* _DIRCACHE_H */
diff --git a/firmware/include/file_internal.h b/firmware/include/file_internal.h
index acec81206e..e7edb3a441 100644
--- a/firmware/include/file_internal.h
+++ b/firmware/include/file_internal.h
@@ -136,8 +136,9 @@ enum fildes_and_obj_flags
136 FF_NOISO = 0x00200000, /* do not decode ISO filenames to UTF-8 */ 136 FF_NOISO = 0x00200000, /* do not decode ISO filenames to UTF-8 */
137 FF_PROBE = 0x00400000, /* only test existence; don't open */ 137 FF_PROBE = 0x00400000, /* only test existence; don't open */
138 FF_CACHEONLY = 0x00800000, /* succeed only if in dircache */ 138 FF_CACHEONLY = 0x00800000, /* succeed only if in dircache */
139 FF_SELFINFO = 0x01000000, /* return info on self as well */ 139 FF_INFO = 0x01000000, /* return info on self */
140 FF_MASK = 0x01ff0000, 140 FF_PARENTINFO = 0x02000000, /* return info on parent */
141 FF_MASK = 0x03ff0000,
141}; 142};
142 143
143/** Common data structures used throughout **/ 144/** Common data structures used throughout **/
@@ -244,18 +245,16 @@ static inline void filestr_unlock(struct filestr_base *stream)
244/* structure to return detailed information about what you opened */ 245/* structure to return detailed information about what you opened */
245struct path_component_info 246struct path_component_info
246{ 247{
247 const char *name; /* pointer to name within 'path' (OUT) */ 248 const char *name; /* OUT: pointer to name within 'path' */
248 size_t length; /* length of component within 'path' */ 249 size_t length; /* OUT: length of component within 'path' */
249 file_size_t filesize; /* size of the opened file (0 if dir) */ 250 file_size_t filesize; /* OUT: size of the opened file (0 if dir) */
250 unsigned int attr; /* attributes of this component */ 251 unsigned int attr; /* OUT: attributes of this component */
251 struct file_base_info *prefixp; /* base info to check as prefix 252 struct file_base_info info; /* OUT: base info on file
252 (IN if FF_CHECKPREFIX) */ 253 (FF_INFO) */
253 union { 254 struct file_base_info parentinfo; /* OUT: base parent directory info
254 struct file_base_info parentinfo; /* parent directory base info of file 255 (FF_PARENTINFO) */
255 (if not FF_SELFINFO) */ 256 struct file_base_info *prefixp; /* IN: base info to check as prefix
256 struct file_base_info info; /* base info of file itself 257 (FF_CHECKPREFIX) */
257 (if FF_SELFINFO) */
258 };
259}; 258};
260 259
261int open_stream_internal(const char *path, unsigned int callflags, 260int open_stream_internal(const char *path, unsigned int callflags,