diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2017-01-08 17:14:10 -0500 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2017-01-17 14:35:36 -0500 |
commit | a931c76b3a46d1884e985a3bfc82b947521dab97 (patch) | |
tree | 1141cf9a9a8c123bde3d76d147ee1e910c7c6045 /firmware/common/dircache.c | |
parent | 0056ea8a256af0e2daaf451af43c00708a31d4df (diff) | |
download | rockbox-a931c76b3a46d1884e985a3bfc82b947521dab97.tar.gz rockbox-a931c76b3a46d1884e985a3bfc82b947521dab97.zip |
Do some debug and preparatory work for ramcache and playlist
The file system rework introduced incompatibility between dircache
and the tagcache ramcache and playlist dircache path caching. This
update makes changes to filesystem code to reintegrate all that.
It also fixes a couple bugs that were found when vetting all the
code. The filestream cache was being reset without regard to
the stream even if it was shared in write mode (made work of
.playlist_control). Better handling of unmounting gives files a
better go at force-closing them without risk to disk integrity.
Did some miscellaneous pedantic changes. Improved efficiency of
testing a file's existence (a little) since the path parser will
be shared between file code and parsing for the sake of finding
dircache references, not duplicated as before.
This commit doesn't reenable said items just for the sake of
keeping changes separate and related.
Plan for the next is to enable dircache again for the playlists
(easy peasy) and reenable tagcache ramcache but *without* the
dircache path caching because it's rather substantial to change
in itself. The ramcache will still function without dircache.
Change-Id: I7e2a9910b866251fa8333e1275f72fcfc8425d2d
Diffstat (limited to 'firmware/common/dircache.c')
-rw-r--r-- | firmware/common/dircache.c | 351 |
1 files changed, 178 insertions, 173 deletions
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index b93ee73fc6..a3538ff96f 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c | |||
@@ -41,9 +41,7 @@ | |||
41 | #include "audio.h" | 41 | #include "audio.h" |
42 | #include "rbpaths.h" | 42 | #include "rbpaths.h" |
43 | #include "linked_list.h" | 43 | #include "linked_list.h" |
44 | #ifdef HAVE_EEPROM_SETTINGS | ||
45 | #include "crc32.h" | 44 | #include "crc32.h" |
46 | #endif | ||
47 | 45 | ||
48 | /** | 46 | /** |
49 | * Cache memory layout: | 47 | * Cache memory layout: |
@@ -1457,7 +1455,7 @@ int dircache_readdir_dirent(struct filestr_base *stream, | |||
1457 | unsigned int direntry = scanp->fatscan.entry; | 1455 | unsigned int direntry = scanp->fatscan.entry; |
1458 | while (1) | 1456 | while (1) |
1459 | { | 1457 | { |
1460 | if (idx == 0 || direntry == FAT_RW_VAL) /* rewound? */ | 1458 | if (idx == 0 || direntry == FAT_DIRSCAN_RW_VAL) /* rewound? */ |
1461 | { | 1459 | { |
1462 | idx = diridx <= 0 ? dcvolp->root_down : get_entry(diridx)->down; | 1460 | idx = diridx <= 0 ? dcvolp->root_down : get_entry(diridx)->down; |
1463 | break; | 1461 | break; |
@@ -1487,7 +1485,7 @@ int dircache_readdir_dirent(struct filestr_base *stream, | |||
1487 | return 0; /* end of dir */ | 1485 | return 0; /* end of dir */ |
1488 | } | 1486 | } |
1489 | 1487 | ||
1490 | if (ce->direntry > direntry || direntry == FAT_RW_VAL) | 1488 | if (ce->direntry > direntry || direntry == FAT_DIRSCAN_RW_VAL) |
1491 | break; /* cache reader is caught up to FS scan */ | 1489 | break; /* cache reader is caught up to FS scan */ |
1492 | 1490 | ||
1493 | idx = ce->next; | 1491 | idx = ce->next; |
@@ -1549,7 +1547,12 @@ int dircache_readdir_internal(struct filestr_base *stream, | |||
1549 | 1547 | ||
1550 | /* is parent cached? if not, readthrough because nothing is here yet */ | 1548 | /* is parent cached? if not, readthrough because nothing is here yet */ |
1551 | if (!dirinfop->dcfile.serialnum) | 1549 | if (!dirinfop->dcfile.serialnum) |
1550 | { | ||
1551 | if (stream->flags & FF_CACHEONLY) | ||
1552 | goto read_eod; | ||
1553 | |||
1552 | return uncached_readdir_internal(stream, infop, fatent); | 1554 | return uncached_readdir_internal(stream, infop, fatent); |
1555 | } | ||
1553 | 1556 | ||
1554 | int diridx = dirinfop->dcfile.idx; | 1557 | int diridx = dirinfop->dcfile.idx; |
1555 | unsigned int frontier = diridx < 0 ? | 1558 | unsigned int frontier = diridx < 0 ? |
@@ -1562,7 +1565,8 @@ int dircache_readdir_internal(struct filestr_base *stream, | |||
1562 | idx = get_entry(idx)->next; | 1565 | idx = get_entry(idx)->next; |
1563 | 1566 | ||
1564 | struct dircache_entry *ce = get_entry(idx); | 1567 | struct dircache_entry *ce = get_entry(idx); |
1565 | if (frontier != FRONTIER_SETTLED) | 1568 | |
1569 | if (frontier != FRONTIER_SETTLED && !(stream->flags & FF_CACHEONLY)) | ||
1566 | { | 1570 | { |
1567 | /* the directory being read is reported to be incompletely cached; | 1571 | /* the directory being read is reported to be incompletely cached; |
1568 | readthrough and if the entry exists, return it with its binding | 1572 | readthrough and if the entry exists, return it with its binding |
@@ -1577,9 +1581,7 @@ int dircache_readdir_internal(struct filestr_base *stream, | |||
1577 | else if (!ce) | 1581 | else if (!ce) |
1578 | { | 1582 | { |
1579 | /* end of dir */ | 1583 | /* end of dir */ |
1580 | fat_empty_fat_direntry(fatent); | 1584 | goto read_eod; |
1581 | infop->fatfile.e.entries = 0; | ||
1582 | return 0; | ||
1583 | } | 1585 | } |
1584 | 1586 | ||
1585 | /* FS entry information that we maintain */ | 1587 | /* FS entry information that we maintain */ |
@@ -1612,6 +1614,11 @@ int dircache_readdir_internal(struct filestr_base *stream, | |||
1612 | } | 1614 | } |
1613 | 1615 | ||
1614 | return rc; | 1616 | return rc; |
1617 | |||
1618 | read_eod: | ||
1619 | fat_empty_fat_direntry(fatent); | ||
1620 | infop->fatfile.e.entries = 0; | ||
1621 | return 0; | ||
1615 | } | 1622 | } |
1616 | 1623 | ||
1617 | /** | 1624 | /** |
@@ -2451,30 +2458,41 @@ void dircache_fileop_sync(struct file_base_binding *bindp, | |||
2451 | 2458 | ||
2452 | /** Dircache paths and files **/ | 2459 | /** Dircache paths and files **/ |
2453 | 2460 | ||
2454 | #ifdef DIRCACHE_DUMPSTER | 2461 | /** |
2455 | /* helper for dircache_get_path() */ | 2462 | * helper for returning a path and serial hash represented by an index |
2456 | static ssize_t get_path_sub(int idx, char *buf, size_t size) | 2463 | */ |
2464 | struct get_path_sub_data | ||
2465 | { | ||
2466 | char *buf; | ||
2467 | size_t size; | ||
2468 | dc_serial_t serialhash; | ||
2469 | }; | ||
2470 | |||
2471 | static ssize_t get_path_sub(int idx, struct get_path_sub_data *data) | ||
2457 | { | 2472 | { |
2458 | if (idx == 0) | 2473 | if (idx == 0) |
2459 | return -2; /* entry is an orphan split from any root */ | 2474 | return -1; /* entry is an orphan split from any root */ |
2460 | 2475 | ||
2461 | ssize_t offset; | 2476 | ssize_t len; |
2462 | char *cename; | 2477 | char *cename; |
2463 | 2478 | ||
2464 | if (idx > 0) | 2479 | if (idx > 0) |
2465 | { | 2480 | { |
2466 | /* go all the way up then move back down from the root */ | ||
2467 | struct dircache_entry *ce = get_entry(idx); | 2481 | struct dircache_entry *ce = get_entry(idx); |
2468 | offset = get_path_sub(ce->up, buf, size) - 1; | 2482 | |
2469 | if (offset < 0) | 2483 | data->serialhash = dc_hash_serialnum(ce->serialnum, data->serialhash); |
2470 | return -3; | 2484 | |
2485 | /* go all the way up then move back down from the root */ | ||
2486 | len = get_path_sub(ce->up, data) - 1; | ||
2487 | if (len < 0) | ||
2488 | return -2; | ||
2471 | 2489 | ||
2472 | cename = alloca(MAX_NAME + 1); | 2490 | cename = alloca(MAX_NAME + 1); |
2473 | entry_name_copy(cename, ce); | 2491 | entry_name_copy(cename, ce); |
2474 | } | 2492 | } |
2475 | else /* idx < 0 */ | 2493 | else /* idx < 0 */ |
2476 | { | 2494 | { |
2477 | offset = 0; | 2495 | len = 0; |
2478 | cename = ""; | 2496 | cename = ""; |
2479 | 2497 | ||
2480 | #ifdef HAVE_MULTIVOLUME | 2498 | #ifdef HAVE_MULTIVOLUME |
@@ -2486,14 +2504,14 @@ static ssize_t get_path_sub(int idx, char *buf, size_t size) | |||
2486 | get_volume_name(volume, cename); | 2504 | get_volume_name(volume, cename); |
2487 | } | 2505 | } |
2488 | #endif /* HAVE_MULTIVOLUME */ | 2506 | #endif /* HAVE_MULTIVOLUME */ |
2507 | |||
2508 | data->serialhash = dc_hash_serialnum(get_idx_dcvolp(idx)->serialnum, | ||
2509 | data->serialhash); | ||
2489 | } | 2510 | } |
2490 | 2511 | ||
2491 | return offset + path_append(buf + offset, PA_SEP_HARD, cename, | 2512 | return len + path_append(data->buf + len, PA_SEP_HARD, cename, |
2492 | size > (size_t)offset ? size - offset : 0); | 2513 | data->size > (size_t)len ? data->size - len : 0); |
2493 | } | 2514 | } |
2494 | #endif /* DIRCACHE_DUMPSTER */ | ||
2495 | |||
2496 | #if 0 | ||
2497 | 2515 | ||
2498 | /** | 2516 | /** |
2499 | * retrieve and validate the file's entry/binding serial number | 2517 | * retrieve and validate the file's entry/binding serial number |
@@ -2523,201 +2541,173 @@ static dc_serial_t get_file_serialnum(const struct dircache_file *dcfilep) | |||
2523 | } | 2541 | } |
2524 | 2542 | ||
2525 | /** | 2543 | /** |
2544 | * Obtain the hash of the serial numbers of the canonical path, index to root | ||
2545 | */ | ||
2546 | static dc_serial_t get_file_serialhash(const struct dircache_file *dcfilep) | ||
2547 | { | ||
2548 | int idx = dcfilep->idx; | ||
2549 | |||
2550 | dc_serial_t h = DC_SERHASH_START; | ||
2551 | |||
2552 | while (idx > 0) | ||
2553 | { | ||
2554 | struct dircache_entry *ce = get_entry(idx); | ||
2555 | h = dc_hash_serialnum(ce->serialnum, h); | ||
2556 | idx = ce->up; | ||
2557 | } | ||
2558 | |||
2559 | h = dc_hash_serialnum(get_idx_dcvolp(idx)->serialnum, h); | ||
2560 | |||
2561 | return h; | ||
2562 | } | ||
2563 | |||
2564 | /** | ||
2565 | * Initialize the fileref | ||
2566 | */ | ||
2567 | void dircache_fileref_init(struct dircache_fileref *dcfrefp) | ||
2568 | { | ||
2569 | dircache_dcfile_init(&dcfrefp->dcfile); | ||
2570 | dcfrefp->serialhash = DC_SERHASH_START; | ||
2571 | } | ||
2572 | |||
2573 | /** | ||
2526 | * usermode function to construct a full absolute path from dircache into the | 2574 | * usermode function to construct a full absolute path from dircache into the |
2527 | * given buffer given the dircache file info | 2575 | * given buffer given the dircache file info |
2528 | * | 2576 | * |
2529 | * returns: | 2577 | * returns: |
2530 | * success - the length of the string, not including the trailing null | 2578 | * success - the length of the string, not including the trailing null or the |
2579 | * buffer length required if the buffer is too small (return is >= | ||
2580 | * size) | ||
2531 | * failure - a negative value | 2581 | * failure - a negative value |
2532 | * | 2582 | * |
2533 | * successful return value is as strlcpy() | ||
2534 | * | ||
2535 | * errors: | 2583 | * errors: |
2536 | * ENOENT - the file or directory does not exist | 2584 | * ENOENT - No such file or directory |
2537 | */ | 2585 | */ |
2538 | ssize_t dircache_get_path(const struct dircache_file *dcfilep, char *buf, | 2586 | ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char *buf, |
2539 | size_t size) | 2587 | size_t size) |
2540 | { | 2588 | { |
2589 | ssize_t rc; | ||
2590 | |||
2541 | /* if missing buffer space, still return what's needed a la strlcpy */ | 2591 | /* if missing buffer space, still return what's needed a la strlcpy */ |
2542 | if (!buf) | 2592 | if (!buf) |
2543 | size = 0; | 2593 | size = 0; |
2544 | else if (size) | 2594 | else if (size) |
2545 | *buf = '\0'; | 2595 | *buf = '\0'; |
2546 | 2596 | ||
2547 | ssize_t len = -1; | ||
2548 | |||
2549 | dircache_lock(); | 2597 | dircache_lock(); |
2550 | 2598 | ||
2551 | /* first and foremost, there must be a cache and the serial number must | 2599 | /* first and foremost, there must be a cache and the serial number must |
2552 | check out */ | 2600 | check out */ |
2553 | if (dircache_runinfo.handle && get_file_serialnum(dcfilep)) | 2601 | if (!dircache_runinfo.handle) |
2554 | len = get_path_sub(dcfilep->idx, buf, size); | 2602 | FILE_ERROR(ENOENT, -1); |
2555 | |||
2556 | if (len < 0) | ||
2557 | errno = ENOENT; | ||
2558 | |||
2559 | dircache_unlock(); | ||
2560 | return len; | ||
2561 | } | ||
2562 | 2603 | ||
2563 | /** | 2604 | if (get_file_serialnum(&dcfrefp->dcfile) == 0) |
2564 | * searches the sublist starting at 'idx' for the named component | 2605 | FILE_ERROR(ENOENT, -2); |
2565 | */ | ||
2566 | 2606 | ||
2567 | /* helper for get_file_sub() */ | 2607 | struct get_path_sub_data data = |
2568 | static struct dircache_entry * | ||
2569 | get_file_sub_scan(int idx, const char *name, size_t length, int *idxp) | ||
2570 | { | ||
2571 | struct dircache_entry *ce = get_entry(idx); | ||
2572 | if (ce) | ||
2573 | { | 2608 | { |
2574 | char entname[MAX_NAME+1]; | 2609 | .buf = buf, |
2575 | name = strmemdupa(name, length); | 2610 | .size = size, |
2576 | 2611 | .serialhash = DC_SERHASH_START, | |
2577 | do | 2612 | }; |
2578 | { | ||
2579 | entry_name_copy(entname, ce); | ||
2580 | if (!strcasecmp(entname, name)) | ||
2581 | { | ||
2582 | *idxp = idx; | ||
2583 | break; | ||
2584 | } | ||
2585 | |||
2586 | idx = ce->next; | ||
2587 | } | ||
2588 | while ((ce = get_entry(idx))); | ||
2589 | } | ||
2590 | |||
2591 | return ce; | ||
2592 | } | ||
2593 | |||
2594 | /** | ||
2595 | * searches for the subcomponent of *pathp | ||
2596 | */ | ||
2597 | |||
2598 | /* helper for dircache_get_file() */ | ||
2599 | static int get_file_sub(const char **pathp, int *downp, int *idxp) | ||
2600 | { | ||
2601 | int rc; | ||
2602 | const char *name; | ||
2603 | rc = parse_path_component(pathp, &name, false); | ||
2604 | if (rc <= 0) | ||
2605 | return rc; | ||
2606 | else if (rc >= MAX_PATH) | ||
2607 | return ENAMETOOLONG; /* that's just unpossible, man */ | ||
2608 | 2613 | ||
2609 | struct dircache_entry *ce = get_file_sub_scan(*downp, name, rc, idxp); | 2614 | rc = get_path_sub(dcfrefp->dcfile.idx, &data); |
2615 | if (rc < 0) | ||
2616 | FILE_ERROR(ENOENT, rc * 10 - 3); | ||
2610 | 2617 | ||
2611 | if (!ce) | 2618 | if (data.serialhash != dcfrefp->serialhash) |
2612 | rc = RC_NOT_FOUND; /* not there; tellibry solly */ | 2619 | FILE_ERROR(ENOENT, -4); |
2613 | else if (!*pathp) | ||
2614 | rc = RC_PATH_ENDED; /* done */ | ||
2615 | else if (!(ce->attr & ATTR_DIRECTORY)) | ||
2616 | rc = ENOTDIR; /* a parent component must be a directory */ | ||
2617 | else | ||
2618 | while ((rc = get_file_sub(pathp, &ce->down, idxp)) == RC_CONTINUE); | ||
2619 | 2620 | ||
2620 | switch (rc) | 2621 | file_error: |
2621 | { | 2622 | dircache_unlock(); |
2622 | case RC_GO_UP: /* hit ".."; drop to previous level */ | 2623 | return rc; |
2623 | return RC_CONTINUE; | ||
2624 | case RC_PATH_ENDED: /* success! */ | ||
2625 | return RC_FOUND; | ||
2626 | default: /* component not found or error */ | ||
2627 | return rc; | ||
2628 | } | ||
2629 | } | 2624 | } |
2630 | 2625 | ||
2631 | /** | 2626 | /** |
2632 | * usermode function to return dircache file info for the given path | 2627 | * Test a path to various levels of rigor and optionally return dircache file |
2628 | * info for the given path | ||
2633 | * | 2629 | * |
2634 | * returns: | 2630 | * returns: |
2635 | * success: the volume number that is specified for the file | 2631 | * success: 0 |
2636 | * failure: a negative value | 2632 | * failure: a negative value |
2637 | * | 2633 | * |
2638 | * errors: | 2634 | * errors (including but not limited to): |
2639 | * ENOENT - the file or directory does not exist or path is empty | 2635 | * EFAULT - Bad address |
2640 | * ENAMETOOLONG - a component of the path is too long | 2636 | * EINVAL - Invalid argument |
2641 | * ENOTDIR - a component of the path is not a directory | 2637 | * ENAMETOOLONG - File or path name too long |
2638 | * ENOENT - No such file or directory | ||
2639 | * ENOTDIR - Not a directory | ||
2640 | * ENXIO - No such device or address | ||
2642 | */ | 2641 | */ |
2643 | int dircache_get_file(const char *path, struct dircache_file *dcfilep) | 2642 | int dircache_search(unsigned int flags, struct dircache_fileref *dcfrefp, const char *path) |
2644 | { | 2643 | { |
2645 | if (!path_is_absolute(path) || !dcfilep) | 2644 | int rc; |
2646 | { | 2645 | |
2647 | errno = ENOENT; | 2646 | if (!(flags & (DCS_FILEREF | DCS_CACHED_PATH))) |
2648 | return -1; | 2647 | FILE_ERROR_RETURN(EINVAL, -1); /* search nothing? */ |
2649 | } | ||
2650 | 2648 | ||
2651 | dircache_lock(); | 2649 | dircache_lock(); |
2652 | 2650 | ||
2653 | if (!dircache_runinfo.handle) | 2651 | if (!dircache_runinfo.handle) |
2652 | FILE_ERROR(ENOENT, -2); | ||
2653 | |||
2654 | if (flags & DCS_FILEREF) | ||
2654 | { | 2655 | { |
2655 | dircache_unlock(); | 2656 | if (!dcfrefp) |
2656 | errno = ENOENT; | 2657 | FILE_ERROR(EFAULT, -3); |
2657 | return -2; | ||
2658 | } | ||
2659 | 2658 | ||
2660 | int volume = 0; | 2659 | if (get_file_serialnum(&dcfrefp->dcfile) != 0) |
2661 | int idx = 0; | 2660 | { |
2662 | dc_serial_t serialnum = 0; | 2661 | if (!(flags & _DCS_VERIFY_FLAG)) |
2663 | struct dircache_volume *dcvolp = NULL; | 2662 | goto file_success; /* no robust verification wanted */ |
2664 | struct dircache_entry *ce = NULL; | 2663 | |
2664 | if (get_file_serialhash(&dcfrefp->dcfile) == dcfrefp->serialhash) | ||
2665 | goto file_success; /* reference is most likely still valid */ | ||
2666 | } | ||
2665 | 2667 | ||
2666 | int rc = RC_GO_UP; | 2668 | if (!(flags & DCS_CACHED_PATH)) |
2669 | FILE_ERROR(ENOENT, -4); /* no path search wanted */ | ||
2670 | } | ||
2667 | 2671 | ||
2668 | while (rc == RC_CONTINUE || rc == RC_GO_UP) | 2672 | if (flags & DCS_CACHED_PATH) |
2669 | { | 2673 | { |
2670 | #ifdef HAVE_MULTIVOLUME | 2674 | const bool update = flags & DCS_UPDATE_FILEREF; |
2671 | if (rc == RC_GO_UP) | 2675 | struct path_component_info *compinfop = NULL; |
2676 | |||
2677 | if (update) | ||
2672 | { | 2678 | { |
2673 | volume = path_strip_volume(path, &path, false); | 2679 | if (!dcfrefp) |
2674 | if (!CHECK_VOL(volume)) | 2680 | FILE_ERROR(EFAULT, -5); |
2675 | { | ||
2676 | rc = ENXIO; | ||
2677 | break; | ||
2678 | } | ||
2679 | } | ||
2680 | #endif /* HAVE_MULTIVOLUME */ | ||
2681 | 2681 | ||
2682 | dcvolp = DCVOL(volume); | 2682 | compinfop = alloca(sizeof (*compinfop)); |
2683 | } | ||
2683 | 2684 | ||
2684 | int *downp = &dcvolp->root_down; | 2685 | struct filestr_base stream; |
2685 | if (*downp <= 0) | 2686 | rc = open_stream_internal(path, FF_ANYTYPE | FF_PROBE | FF_SELFINFO | |
2687 | ((flags & _DCS_STORAGE_FLAG) ? 0 : FF_CACHEONLY), | ||
2688 | &stream, compinfop); | ||
2689 | if (rc <= 0) | ||
2686 | { | 2690 | { |
2687 | rc = ENXIO; | 2691 | if (update) |
2688 | break; | 2692 | dircache_fileref_init(dcfrefp); |
2693 | |||
2694 | FILE_ERROR(rc ? ERRNO : ENOENT, rc * 10 - 6); | ||
2689 | } | 2695 | } |
2690 | 2696 | ||
2691 | rc = get_file_sub(&path, downp, &idx); | 2697 | if (update) |
2692 | } | 2698 | { |
2693 | 2699 | dcfrefp->dcfile = compinfop->info.dcfile; | |
2694 | switch (rc) | 2700 | dcfrefp->serialhash = get_file_serialhash(&compinfop->info.dcfile); |
2695 | { | 2701 | } |
2696 | case RC_FOUND: /* hit: component found */ | ||
2697 | serialnum = ce->serialnum; | ||
2698 | rc = volume; | ||
2699 | break; | ||
2700 | case RC_PATH_ENDED: /* hit: it's a root (volume or system) */ | ||
2701 | idx = -volume - 1; | ||
2702 | serialnum = dcvolp->serialnum; | ||
2703 | rc = volume; | ||
2704 | break; | ||
2705 | case RC_NOT_FOUND: /* miss */ | ||
2706 | rc = ENOENT; | ||
2707 | default: | ||
2708 | idx = 0; | ||
2709 | errno = rc; | ||
2710 | rc = -3; | ||
2711 | break; | ||
2712 | } | 2702 | } |
2713 | 2703 | ||
2714 | dcfilep->idx = idx; | 2704 | file_success: |
2715 | dcfilep->serialnum = serialnum; | 2705 | rc = 0; |
2716 | 2706 | ||
2707 | file_error: | ||
2717 | dircache_unlock(); | 2708 | dircache_unlock(); |
2718 | return rc; | 2709 | return rc; |
2719 | } | 2710 | } |
2720 | #endif /* 0 */ | ||
2721 | 2711 | ||
2722 | 2712 | ||
2723 | /** Debug screen/info stuff **/ | 2713 | /** Debug screen/info stuff **/ |
@@ -2737,13 +2727,12 @@ void dircache_get_info(struct dircache_info *info) | |||
2737 | if (!info) | 2727 | if (!info) |
2738 | return; | 2728 | return; |
2739 | 2729 | ||
2740 | memset(info, 0, sizeof (*info)); | ||
2741 | |||
2742 | dircache_lock(); | 2730 | dircache_lock(); |
2743 | 2731 | ||
2744 | enum dircache_status status = DIRCACHE_IDLE; | 2732 | enum dircache_status status = DIRCACHE_IDLE; |
2733 | info->build_ticks = 0; | ||
2745 | 2734 | ||
2746 | for (unsigned int volume = 0; volume < NUM_VOLUMES; volume++) | 2735 | FOR_EACH_VOLUME(-1, volume) |
2747 | { | 2736 | { |
2748 | struct dircache_volume *dcvolp = DCVOL(volume); | 2737 | struct dircache_volume *dcvolp = DCVOL(volume); |
2749 | enum dircache_status volstatus = dcvolp->status; | 2738 | enum dircache_status volstatus = dcvolp->status; |
@@ -2781,11 +2770,18 @@ void dircache_get_info(struct dircache_info *info) | |||
2781 | /* report usage only if there is something ready or being built */ | 2770 | /* report usage only if there is something ready or being built */ |
2782 | if (status != DIRCACHE_IDLE) | 2771 | if (status != DIRCACHE_IDLE) |
2783 | { | 2772 | { |
2784 | info->reserve_used = reserve_buf_used(); | ||
2785 | info->size = dircache.size; | 2773 | info->size = dircache.size; |
2786 | info->sizeused = dircache.sizeused; | 2774 | info->sizeused = dircache.sizeused; |
2775 | info->reserve_used = reserve_buf_used(); | ||
2787 | info->entry_count = dircache.numentries; | 2776 | info->entry_count = dircache.numentries; |
2788 | } | 2777 | } |
2778 | else | ||
2779 | { | ||
2780 | info->size = 0; | ||
2781 | info->sizeused = 0; | ||
2782 | info->reserve_used = 0; | ||
2783 | info->entry_count = 0; | ||
2784 | } | ||
2789 | 2785 | ||
2790 | dircache_unlock(); | 2786 | dircache_unlock(); |
2791 | } | 2787 | } |
@@ -2817,7 +2813,7 @@ void dircache_dump(void) | |||
2817 | dircache_runinfo.bufsize + 1); | 2813 | dircache_runinfo.bufsize + 1); |
2818 | 2814 | ||
2819 | /* CSV */ | 2815 | /* CSV */ |
2820 | fdprintf(fdcsv, "\"Index\",\"Serialnum\"," | 2816 | fdprintf(fdcsv, "\"Index\",\"Serialnum\",\"Serialhash\"," |
2821 | "\"Path\",\"Frontier\"," | 2817 | "\"Path\",\"Frontier\"," |
2822 | "\"Attribute\",\"File Size\"," | 2818 | "\"Attribute\",\"File Size\"," |
2823 | "\"Mod Date\",\"Mod Time\"\n"); | 2819 | "\"Mod Date\",\"Mod Time\"\n"); |
@@ -2833,11 +2829,12 @@ void dircache_dump(void) | |||
2833 | get_volume_name(volume, name); | 2829 | get_volume_name(volume, name); |
2834 | #endif | 2830 | #endif |
2835 | fdprintf(fdcsv, | 2831 | fdprintf(fdcsv, |
2836 | "%d,%lu," | 2832 | "%d," DC_SERIAL_FMT "," DC_SERIAL_FMT "," |
2837 | "\"%c" IF_MV("%s") "\",%u," | 2833 | "\"%c" IF_MV("%s") "\",%u," |
2838 | "0x%08X,0," | 2834 | "0x%08X,0," |
2839 | "\"\",\"\"\n", | 2835 | "\"\",\"\"\n", |
2840 | -volume-1, dcvolp->serialnum, | 2836 | -volume-1, dcvolp->serialnum, |
2837 | dc_hash_serialnum(dcvolp->serialnum, DC_SERHASH_START), | ||
2841 | PATH_SEPCH, IF_MV(name,) dcvolp->frontier, | 2838 | PATH_SEPCH, IF_MV(name,) dcvolp->frontier, |
2842 | ATTR_DIRECTORY | ATTR_VOLUME); | 2839 | ATTR_DIRECTORY | ATTR_VOLUME); |
2843 | } | 2840 | } |
@@ -2855,15 +2852,23 @@ void dircache_dump(void) | |||
2855 | char buf[DC_MAX_NAME + 2]; | 2852 | char buf[DC_MAX_NAME + 2]; |
2856 | *buf = '\0'; | 2853 | *buf = '\0'; |
2857 | int idx = get_index(ce); | 2854 | int idx = get_index(ce); |
2858 | get_path_sub(idx, buf, sizeof (buf)); | 2855 | |
2856 | struct get_path_sub_data data = | ||
2857 | { | ||
2858 | .buf = buf, | ||
2859 | .size = sizeof (buf), | ||
2860 | .serialhash = DC_SERHASH_START, | ||
2861 | }; | ||
2862 | |||
2863 | get_path_sub(idx, &data); | ||
2859 | 2864 | ||
2860 | fdprintf(fdcsv, | 2865 | fdprintf(fdcsv, |
2861 | "%d,%lu," | 2866 | "%d," DC_SERIAL_FMT "," DC_SERIAL_FMT "," |
2862 | "\"%s\",%u," | 2867 | "\"%s\",%u," |
2863 | "0x%08X,%lu," | 2868 | "0x%08X,%lu," |
2864 | "%04d/%02d/%02d," | 2869 | "%04d/%02d/%02d," |
2865 | "%02d:%02d:%02d\n", | 2870 | "%02d:%02d:%02d\n", |
2866 | idx, ce->serialnum, | 2871 | idx, ce->serialnum, data.serialhash, |
2867 | buf, ce->frontier, | 2872 | buf, ce->frontier, |
2868 | ce->attr, (ce->attr & ATTR_DIRECTORY) ? | 2873 | ce->attr, (ce->attr & ATTR_DIRECTORY) ? |
2869 | 0ul : (unsigned long)ce->filesize, | 2874 | 0ul : (unsigned long)ce->filesize, |