summaryrefslogtreecommitdiff
path: root/firmware/common
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/common')
-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
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 */
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;