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 | |
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')
-rw-r--r-- | firmware/common/dir.c | 3 | ||||
-rw-r--r-- | firmware/common/dircache.c | 209 | ||||
-rw-r--r-- | firmware/common/file.c | 10 | ||||
-rw-r--r-- | firmware/common/file_internal.c | 10 |
4 files changed, 160 insertions, 72 deletions
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 | */ | ||
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 | ||
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; |