diff options
Diffstat (limited to 'firmware/common/file_internal.c')
-rw-r--r-- | firmware/common/file_internal.c | 95 |
1 files changed, 68 insertions, 27 deletions
diff --git a/firmware/common/file_internal.c b/firmware/common/file_internal.c index 45f412e166..fe18f90056 100644 --- a/firmware/common/file_internal.c +++ b/firmware/common/file_internal.c | |||
@@ -26,7 +26,9 @@ | |||
26 | #include "pathfuncs.h" | 26 | #include "pathfuncs.h" |
27 | #include "disk_cache.h" | 27 | #include "disk_cache.h" |
28 | #include "fileobj_mgr.h" | 28 | #include "fileobj_mgr.h" |
29 | #include "rb_namespace.h" | 29 | #include "dir.h" |
30 | #include "dircache_redirect.h" | ||
31 | #include "dircache.h" | ||
30 | #include "string-extra.h" | 32 | #include "string-extra.h" |
31 | #include "rbunicode.h" | 33 | #include "rbunicode.h" |
32 | 34 | ||
@@ -85,10 +87,9 @@ void file_cache_free(struct filestr_cache *cachep) | |||
85 | 87 | ||
86 | /** Stream base APIs **/ | 88 | /** Stream base APIs **/ |
87 | 89 | ||
88 | static inline void filestr_clear(struct filestr_base *stream, | 90 | static inline void filestr_clear(struct filestr_base *stream) |
89 | unsigned int flags) | ||
90 | { | 91 | { |
91 | stream->flags = flags; | 92 | stream->flags = 0; |
92 | stream->bindp = NULL; | 93 | stream->bindp = NULL; |
93 | #if 0 | 94 | #if 0 |
94 | stream->mtx = NULL; | 95 | stream->mtx = NULL; |
@@ -152,7 +153,7 @@ void filestr_discard_cache(struct filestr_base *stream) | |||
152 | /* Initialize the base descriptor */ | 153 | /* Initialize the base descriptor */ |
153 | void filestr_base_init(struct filestr_base *stream) | 154 | void filestr_base_init(struct filestr_base *stream) |
154 | { | 155 | { |
155 | filestr_clear(stream, FD_VALID); | 156 | filestr_clear(stream); |
156 | file_cache_init(&stream->cache); | 157 | file_cache_init(&stream->cache); |
157 | stream->cachep = &stream->cache; | 158 | stream->cachep = &stream->cache; |
158 | } | 159 | } |
@@ -160,7 +161,7 @@ void filestr_base_init(struct filestr_base *stream) | |||
160 | /* free base descriptor resources */ | 161 | /* free base descriptor resources */ |
161 | void filestr_base_destroy(struct filestr_base *stream) | 162 | void filestr_base_destroy(struct filestr_base *stream) |
162 | { | 163 | { |
163 | filestr_clear(stream, 0); | 164 | filestr_clear(stream); |
164 | filestr_free_cache(stream); | 165 | filestr_free_cache(stream); |
165 | } | 166 | } |
166 | 167 | ||
@@ -292,7 +293,7 @@ struct pathwalk_component | |||
292 | 293 | ||
293 | #define WALK_RC_NOT_FOUND 0 /* successfully not found (aid for file creation) */ | 294 | #define WALK_RC_NOT_FOUND 0 /* successfully not found (aid for file creation) */ |
294 | #define WALK_RC_FOUND 1 /* found and opened */ | 295 | #define WALK_RC_FOUND 1 /* found and opened */ |
295 | #define WALK_RC_FOUND_ROOT 2 /* found and opened sys root */ | 296 | #define WALK_RC_FOUND_ROOT 2 /* found and opened sys/volume root */ |
296 | #define WALK_RC_CONT_AT_ROOT 3 /* continue at root level */ | 297 | #define WALK_RC_CONT_AT_ROOT 3 /* continue at root level */ |
297 | 298 | ||
298 | /* return another struct pathwalk_component from the pool, or NULL if the | 299 | /* return another struct pathwalk_component from the pool, or NULL if the |
@@ -396,10 +397,10 @@ static int walk_open_info(struct pathwalk *walkp, | |||
396 | 397 | ||
397 | /* make open official if not simply probing for presence - must do it here | 398 | /* make open official if not simply probing for presence - must do it here |
398 | or compp->info on stack will get destroyed before it was copied */ | 399 | or compp->info on stack will get destroyed before it was copied */ |
399 | if (!(callflags & (FF_PROBE|FF_NOFS))) | 400 | if (!(callflags & FF_PROBE)) |
400 | fileop_onopen_internal(stream, &compp->info, callflags); | 401 | fileop_onopen_internal(stream, &compp->info, callflags); |
401 | 402 | ||
402 | return compp->attr == ATTR_SYSTEM_ROOT ? WALK_RC_FOUND_ROOT : WALK_RC_FOUND; | 403 | return compp->nextp ? WALK_RC_FOUND : WALK_RC_FOUND_ROOT; |
403 | } | 404 | } |
404 | 405 | ||
405 | /* check the component against the prefix test info */ | 406 | /* check the component against the prefix test info */ |
@@ -506,10 +507,6 @@ walk_path(struct pathwalk *walkp, struct pathwalk_component *compp, | |||
506 | if (len > MAX_COMPNAME) | 507 | if (len > MAX_COMPNAME) |
507 | return -ENAMETOOLONG; | 508 | return -ENAMETOOLONG; |
508 | 509 | ||
509 | /* no filesystem is mounted here */ | ||
510 | if (walkp->callflags & FF_NOFS) | ||
511 | return -ENOENT; | ||
512 | |||
513 | /* check for "." and ".." */ | 510 | /* check for "." and ".." */ |
514 | if (name[0] == '.') | 511 | if (name[0] == '.') |
515 | { | 512 | { |
@@ -578,7 +575,7 @@ int open_stream_internal(const char *path, unsigned int callflags, | |||
578 | callflags &= ~(FF_INFO | FF_PARENTINFO | FF_CHECKPREFIX); | 575 | callflags &= ~(FF_INFO | FF_PARENTINFO | FF_CHECKPREFIX); |
579 | 576 | ||
580 | /* This lets it be passed quietly to directory scanning */ | 577 | /* This lets it be passed quietly to directory scanning */ |
581 | stream->flags |= callflags & FF_MASK; | 578 | stream->flags = callflags & FF_MASK; |
582 | 579 | ||
583 | struct pathwalk walk; | 580 | struct pathwalk walk; |
584 | walk.path = path; | 581 | walk.path = path; |
@@ -588,36 +585,80 @@ int open_stream_internal(const char *path, unsigned int callflags, | |||
588 | 585 | ||
589 | struct pathwalk_component *rootp = pathwalk_comp_alloc(NULL); | 586 | struct pathwalk_component *rootp = pathwalk_comp_alloc(NULL); |
590 | rootp->nextp = NULL; | 587 | rootp->nextp = NULL; |
588 | rootp->attr = ATTR_SYSTEM_ROOT; | ||
589 | |||
590 | #ifdef HAVE_MULTIVOLUME | ||
591 | int volume = 0, rootrc = WALK_RC_FOUND; | ||
592 | #endif /* HAVE_MULTIVOLUME */ | ||
591 | 593 | ||
592 | while (1) | 594 | while (1) |
593 | { | 595 | { |
594 | rc = ns_parse_root(walk.path, &rootp->name, &rootp->length); | 596 | const char *pathptr = walk.path; |
595 | if (rc < 0) | 597 | |
596 | break; | 598 | #ifdef HAVE_MULTIVOLUME |
599 | /* this seamlessly integrates secondary filesystems into the | ||
600 | root namespace (e.g. "/<0>/../../<1>/../foo/." :<=> "/foo") */ | ||
601 | const char *p; | ||
602 | volume = path_strip_volume(pathptr, &p, false); | ||
603 | if (!CHECK_VOL(volume)) | ||
604 | { | ||
605 | DEBUGF("No such device or address: %d\n", volume); | ||
606 | FILE_ERROR(ENXIO, -2); | ||
607 | } | ||
608 | |||
609 | if (p == pathptr) | ||
610 | { | ||
611 | /* the root of this subpath is the system root */ | ||
612 | rootp->attr = ATTR_SYSTEM_ROOT; | ||
613 | rootrc = WALK_RC_FOUND_ROOT; | ||
614 | } | ||
615 | else | ||
616 | { | ||
617 | /* this subpath specifies a mount point */ | ||
618 | rootp->attr = ATTR_MOUNT_POINT; | ||
619 | rootrc = WALK_RC_FOUND; | ||
620 | } | ||
597 | 621 | ||
598 | rc = ns_open_root(IF_MV(rc,) &walk.callflags, &rootp->info, &rootp->attr); | 622 | walk.path = p; |
623 | #endif /* HAVE_MULTIVOLUME */ | ||
624 | |||
625 | /* set name to start at last leading separator; names of volume | ||
626 | specifiers will be returned as "/<fooN>" */ | ||
627 | rootp->name = GOBBLE_PATH_SEPCH(pathptr) - 1; | ||
628 | rootp->length = | ||
629 | IF_MV( rootrc == WALK_RC_FOUND ? p - rootp->name : ) 1; | ||
630 | |||
631 | rc = fat_open_rootdir(IF_MV(volume,) &rootp->info.fatfile); | ||
599 | if (rc < 0) | 632 | if (rc < 0) |
633 | { | ||
634 | /* not mounted */ | ||
635 | DEBUGF("No such device or address: %d\n", IF_MV_VOL(volume)); | ||
636 | rc = -ENXIO; | ||
600 | break; | 637 | break; |
638 | } | ||
601 | 639 | ||
602 | walk.path = rootp->name + rootp->length; | 640 | get_rootinfo_internal(&rootp->info); |
603 | |||
604 | rc = walk_path(&walk, rootp, stream); | 641 | rc = walk_path(&walk, rootp, stream); |
605 | if (rc != WALK_RC_CONT_AT_ROOT) | 642 | if (rc != WALK_RC_CONT_AT_ROOT) |
606 | break; | 643 | break; |
607 | } | 644 | } |
608 | 645 | ||
609 | if (rc >= 0) | 646 | switch (rc) |
610 | { | 647 | { |
648 | case WALK_RC_FOUND_ROOT: | ||
649 | IF_MV( rc = rootrc; ) | ||
650 | case WALK_RC_NOT_FOUND: | ||
651 | case WALK_RC_FOUND: | ||
611 | /* FF_PROBE leaves nothing for caller to clean up */ | 652 | /* FF_PROBE leaves nothing for caller to clean up */ |
612 | if (walk.callflags & FF_PROBE) | 653 | if (callflags & FF_PROBE) |
613 | filestr_base_destroy(stream); | 654 | filestr_base_destroy(stream); |
614 | } | 655 | |
615 | else | 656 | break; |
616 | { | 657 | |
617 | /* utter, abject failure :`( */ | 658 | default: /* utter, abject failure :`( */ |
618 | DEBUGF("Open failed: rc=%d, errno=%d\n", rc, errno); | 659 | DEBUGF("Open failed: rc=%d, errno=%d\n", rc, errno); |
619 | filestr_base_destroy(stream); | 660 | filestr_base_destroy(stream); |
620 | FILE_ERROR(-rc, -1); | 661 | FILE_ERROR(-rc, -3); |
621 | } | 662 | } |
622 | 663 | ||
623 | file_error: | 664 | file_error: |