diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2017-01-18 04:39:35 -0500 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2017-02-10 05:05:23 -0500 |
commit | 7373cf518f4d4c47f49693690c2ab8ec29bb8510 (patch) | |
tree | 0a3c025749be24561e952078e83c5f2e8b838900 /firmware/common/dircache.c | |
parent | abd75a17d18c0779b59f64a612f9226b62af5823 (diff) | |
download | rockbox-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
Diffstat (limited to 'firmware/common/dircache.c')
-rw-r--r-- | firmware/common/dircache.c | 209 |
1 files changed, 145 insertions, 64 deletions
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 | */ | ||
615 | static 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 | */ |
615 | static int * get_downidxp(int idx) | 628 | static 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 | */ |
2522 | static dc_serial_t get_file_serialnum(const struct dircache_file *dcfilep) | 2535 | static 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 | */ |
2587 | ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char *buf, | 2613 | ssize_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 | ||
2622 | file_error: | 2652 | file_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 | */ |
2643 | int dircache_search(unsigned int flags, struct dircache_fileref *dcfrefp, const char *path) | 2680 | int 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 | ||
2705 | file_success: | ||
2706 | rc = 0; | ||
2707 | |||
2708 | file_error: | 2760 | file_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 | */ | ||
2776 | int 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 | ||