summaryrefslogtreecommitdiff
path: root/firmware/common/dircache.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/common/dircache.c')
-rw-r--r--firmware/common/dircache.c89
1 files changed, 63 insertions, 26 deletions
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c
index 41564194d0..c5062d47ed 100644
--- a/firmware/common/dircache.c
+++ b/firmware/common/dircache.c
@@ -2488,44 +2488,81 @@ struct get_path_sub_data
2488 2488
2489static ssize_t get_path_sub(int idx, struct get_path_sub_data *data) 2489static ssize_t get_path_sub(int idx, struct get_path_sub_data *data)
2490{ 2490{
2491
2492#ifdef HAVE_MULTIVOLUME
2493#define NAMEBUFLEN (MAX(VOL_MAX_LEN+1, MAX_TINYNAME+1))
2494#else
2495#define NAMEBUFLEN (MAX_TINYNAME+1)
2496#endif
2497 char namebuf[NAMEBUFLEN];
2498#undef NAMEBUFLEN
2499
2491 if (idx == 0) 2500 if (idx == 0)
2492 return -1; /* entry is an orphan split from any root */ 2501 return -1; /* entry is an orphan split from any root */
2493 2502
2494 ssize_t len; 2503 char *cename = "";
2495 char *cename; 2504 size_t cename_len = (-1u);
2505 ssize_t len = 0;
2506 int next_idx = idx;
2507 int count = 1; /* +1 for the idx incoming */
2508 int remain;
2496 2509
2497 if (idx > 0) 2510 do /* go all the way up to the root */
2498 { 2511 {
2499 struct dircache_entry *ce = get_entry(idx); 2512 count++;
2513 if (next_idx > (int)dircache.numentries)
2514 return -1; /* ERROR! */
2515 next_idx = dircache_runinfo.pentry[next_idx].up;
2516 } while (next_idx > 0);
2500 2517
2501 data->serialhash = dc_hash_serialnum(ce->serialnum, data->serialhash); 2518 if (next_idx < 0) /* root */
2519 {
2520 data->serialhash = dc_hash_serialnum(get_idx_dcvolp(next_idx)->serialnum,
2521 data->serialhash);
2522#ifdef HAVE_MULTIVOLUME
2523 /* prepend the volume specifier */
2524 cename = namebuf;
2525 get_volume_name(IF_MV_VOL(-next_idx - 1), cename);
2526#endif /* HAVE_MULTIVOLUME */
2527 }
2502 2528
2503 /* go all the way up then move back down from the root */ 2529 /* we have the volume name write it to the buffer */
2504 len = get_path_sub(ce->up, data) - 1; 2530 goto write_path_component;
2505 if (len < 0) 2531 /* if not MULTIVOLUME it will just be adding '/' */
2506 return -2;
2507 2532
2508 cename = alloca(DC_MAX_NAME + 1); 2533 while (next_idx > 0 && count > 0)
2509 entry_name_copy(cename, ce);
2510 }
2511 else /* idx < 0 */
2512 { 2534 {
2513 len = 0; 2535 struct dircache_entry *ce = &dircache_runinfo.pentry[next_idx];
2514 cename = ""; 2536 if (remain <= 0)
2537 {
2538 data->serialhash = dc_hash_serialnum(ce->serialnum, data->serialhash);
2539 if (LIKELY(!ce->tinyname))
2540 {
2541 cename = get_name(ce->name);
2542 cename_len = CE_NAMESIZE(ce->namelen);
2543 }
2544 else
2545 {
2546 cename = namebuf;
2547 entry_name_copy(cename, ce);
2548 cename_len = -1u;
2549 }
2550write_path_component:
2551 len += path_append_ex(data->buf + len, PA_SEP_HARD, -1u, cename, cename_len,
2552 data->size > (size_t)len ? data->size - len : 0);
2515 2553
2516 #ifdef HAVE_MULTIVOLUME 2554 count--;
2517 /* prepend the volume specifier */ 2555 remain = count - 1;
2518 int volume = IF_MV_VOL(-idx - 1); 2556 next_idx = idx;
2519 cename = alloca(VOL_MAX_LEN+1); 2557 }
2520 get_volume_name(volume, cename); 2558 else
2521 #endif /* HAVE_MULTIVOLUME */ 2559 {
2560 remain--;
2561 next_idx = ce->up;
2562 }
2522 2563
2523 data->serialhash = dc_hash_serialnum(get_idx_dcvolp(idx)->serialnum,
2524 data->serialhash);
2525 } 2564 }
2526 2565 return len;
2527 return len + path_append(data->buf + len, PA_SEP_HARD, cename,
2528 data->size > (size_t)len ? data->size - len : 0);
2529} 2566}
2530 2567
2531/** 2568/**