diff options
author | William Wilgus <me.theuser@yahoo.com> | 2017-02-03 17:13:58 -0500 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2020-08-20 23:08:57 +0000 |
commit | 5ef28cccf92f5eada6d502fa4b0e16a13e94be5b (patch) | |
tree | 05f9d2f8bdf3c0cc54c5893159a7dcf07c7e3e55 /firmware/common/file_internal.c | |
parent | 31fc46ded69be7438cca2ba2c2b93c1f200165a6 (diff) | |
download | rockbox-5ef28cccf92f5eada6d502fa4b0e16a13e94be5b.tar.gz rockbox-5ef28cccf92f5eada6d502fa4b0e16a13e94be5b.zip |
Allow mounting of any directory as the root directory.
Provide definitions for the macros:
* RB_ROOT_VOL_HIDDEN(v) to exclude certain items from the root.
* RB_ROOT_CONTENTS to return a string with the name of the
directory to mount in the root.
Defaults are in export/rbpaths.h
It's a bit much for those that don't need the full functionality.
Some conditional define can cut it back a lot to cut out things only
needed if alternate root mounts are required. I'm just not bothering
yet. The basic concept would be applied to all targets to keep file
code from forking too much.
Change-Id: I90b5c0a1c949283d3102c16734b0b6ac73901a30
Diffstat (limited to 'firmware/common/file_internal.c')
-rw-r--r-- | firmware/common/file_internal.c | 95 |
1 files changed, 27 insertions, 68 deletions
diff --git a/firmware/common/file_internal.c b/firmware/common/file_internal.c index fe18f90056..45f412e166 100644 --- a/firmware/common/file_internal.c +++ b/firmware/common/file_internal.c | |||
@@ -26,9 +26,7 @@ | |||
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 "dir.h" | 29 | #include "rb_namespace.h" |
30 | #include "dircache_redirect.h" | ||
31 | #include "dircache.h" | ||
32 | #include "string-extra.h" | 30 | #include "string-extra.h" |
33 | #include "rbunicode.h" | 31 | #include "rbunicode.h" |
34 | 32 | ||
@@ -87,9 +85,10 @@ void file_cache_free(struct filestr_cache *cachep) | |||
87 | 85 | ||
88 | /** Stream base APIs **/ | 86 | /** Stream base APIs **/ |
89 | 87 | ||
90 | static inline void filestr_clear(struct filestr_base *stream) | 88 | static inline void filestr_clear(struct filestr_base *stream, |
89 | unsigned int flags) | ||
91 | { | 90 | { |
92 | stream->flags = 0; | 91 | stream->flags = flags; |
93 | stream->bindp = NULL; | 92 | stream->bindp = NULL; |
94 | #if 0 | 93 | #if 0 |
95 | stream->mtx = NULL; | 94 | stream->mtx = NULL; |
@@ -153,7 +152,7 @@ void filestr_discard_cache(struct filestr_base *stream) | |||
153 | /* Initialize the base descriptor */ | 152 | /* Initialize the base descriptor */ |
154 | void filestr_base_init(struct filestr_base *stream) | 153 | void filestr_base_init(struct filestr_base *stream) |
155 | { | 154 | { |
156 | filestr_clear(stream); | 155 | filestr_clear(stream, FD_VALID); |
157 | file_cache_init(&stream->cache); | 156 | file_cache_init(&stream->cache); |
158 | stream->cachep = &stream->cache; | 157 | stream->cachep = &stream->cache; |
159 | } | 158 | } |
@@ -161,7 +160,7 @@ void filestr_base_init(struct filestr_base *stream) | |||
161 | /* free base descriptor resources */ | 160 | /* free base descriptor resources */ |
162 | void filestr_base_destroy(struct filestr_base *stream) | 161 | void filestr_base_destroy(struct filestr_base *stream) |
163 | { | 162 | { |
164 | filestr_clear(stream); | 163 | filestr_clear(stream, 0); |
165 | filestr_free_cache(stream); | 164 | filestr_free_cache(stream); |
166 | } | 165 | } |
167 | 166 | ||
@@ -293,7 +292,7 @@ struct pathwalk_component | |||
293 | 292 | ||
294 | #define WALK_RC_NOT_FOUND 0 /* successfully not found (aid for file creation) */ | 293 | #define WALK_RC_NOT_FOUND 0 /* successfully not found (aid for file creation) */ |
295 | #define WALK_RC_FOUND 1 /* found and opened */ | 294 | #define WALK_RC_FOUND 1 /* found and opened */ |
296 | #define WALK_RC_FOUND_ROOT 2 /* found and opened sys/volume root */ | 295 | #define WALK_RC_FOUND_ROOT 2 /* found and opened sys root */ |
297 | #define WALK_RC_CONT_AT_ROOT 3 /* continue at root level */ | 296 | #define WALK_RC_CONT_AT_ROOT 3 /* continue at root level */ |
298 | 297 | ||
299 | /* return another struct pathwalk_component from the pool, or NULL if the | 298 | /* return another struct pathwalk_component from the pool, or NULL if the |
@@ -397,10 +396,10 @@ static int walk_open_info(struct pathwalk *walkp, | |||
397 | 396 | ||
398 | /* make open official if not simply probing for presence - must do it here | 397 | /* make open official if not simply probing for presence - must do it here |
399 | or compp->info on stack will get destroyed before it was copied */ | 398 | or compp->info on stack will get destroyed before it was copied */ |
400 | if (!(callflags & FF_PROBE)) | 399 | if (!(callflags & (FF_PROBE|FF_NOFS))) |
401 | fileop_onopen_internal(stream, &compp->info, callflags); | 400 | fileop_onopen_internal(stream, &compp->info, callflags); |
402 | 401 | ||
403 | return compp->nextp ? WALK_RC_FOUND : WALK_RC_FOUND_ROOT; | 402 | return compp->attr == ATTR_SYSTEM_ROOT ? WALK_RC_FOUND_ROOT : WALK_RC_FOUND; |
404 | } | 403 | } |
405 | 404 | ||
406 | /* check the component against the prefix test info */ | 405 | /* check the component against the prefix test info */ |
@@ -507,6 +506,10 @@ walk_path(struct pathwalk *walkp, struct pathwalk_component *compp, | |||
507 | if (len > MAX_COMPNAME) | 506 | if (len > MAX_COMPNAME) |
508 | return -ENAMETOOLONG; | 507 | return -ENAMETOOLONG; |
509 | 508 | ||
509 | /* no filesystem is mounted here */ | ||
510 | if (walkp->callflags & FF_NOFS) | ||
511 | return -ENOENT; | ||
512 | |||
510 | /* check for "." and ".." */ | 513 | /* check for "." and ".." */ |
511 | if (name[0] == '.') | 514 | if (name[0] == '.') |
512 | { | 515 | { |
@@ -575,7 +578,7 @@ int open_stream_internal(const char *path, unsigned int callflags, | |||
575 | callflags &= ~(FF_INFO | FF_PARENTINFO | FF_CHECKPREFIX); | 578 | callflags &= ~(FF_INFO | FF_PARENTINFO | FF_CHECKPREFIX); |
576 | 579 | ||
577 | /* This lets it be passed quietly to directory scanning */ | 580 | /* This lets it be passed quietly to directory scanning */ |
578 | stream->flags = callflags & FF_MASK; | 581 | stream->flags |= callflags & FF_MASK; |
579 | 582 | ||
580 | struct pathwalk walk; | 583 | struct pathwalk walk; |
581 | walk.path = path; | 584 | walk.path = path; |
@@ -585,80 +588,36 @@ int open_stream_internal(const char *path, unsigned int callflags, | |||
585 | 588 | ||
586 | struct pathwalk_component *rootp = pathwalk_comp_alloc(NULL); | 589 | struct pathwalk_component *rootp = pathwalk_comp_alloc(NULL); |
587 | rootp->nextp = NULL; | 590 | 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 */ | ||
593 | 591 | ||
594 | while (1) | 592 | while (1) |
595 | { | 593 | { |
596 | const char *pathptr = walk.path; | 594 | rc = ns_parse_root(walk.path, &rootp->name, &rootp->length); |
597 | 595 | if (rc < 0) | |
598 | #ifdef HAVE_MULTIVOLUME | 596 | break; |
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 | } | ||
621 | |||
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 | 597 | ||
631 | rc = fat_open_rootdir(IF_MV(volume,) &rootp->info.fatfile); | 598 | rc = ns_open_root(IF_MV(rc,) &walk.callflags, &rootp->info, &rootp->attr); |
632 | if (rc < 0) | 599 | if (rc < 0) |
633 | { | ||
634 | /* not mounted */ | ||
635 | DEBUGF("No such device or address: %d\n", IF_MV_VOL(volume)); | ||
636 | rc = -ENXIO; | ||
637 | break; | 600 | break; |
638 | } | ||
639 | 601 | ||
640 | get_rootinfo_internal(&rootp->info); | 602 | walk.path = rootp->name + rootp->length; |
603 | |||
641 | rc = walk_path(&walk, rootp, stream); | 604 | rc = walk_path(&walk, rootp, stream); |
642 | if (rc != WALK_RC_CONT_AT_ROOT) | 605 | if (rc != WALK_RC_CONT_AT_ROOT) |
643 | break; | 606 | break; |
644 | } | 607 | } |
645 | 608 | ||
646 | switch (rc) | 609 | if (rc >= 0) |
647 | { | 610 | { |
648 | case WALK_RC_FOUND_ROOT: | ||
649 | IF_MV( rc = rootrc; ) | ||
650 | case WALK_RC_NOT_FOUND: | ||
651 | case WALK_RC_FOUND: | ||
652 | /* FF_PROBE leaves nothing for caller to clean up */ | 611 | /* FF_PROBE leaves nothing for caller to clean up */ |
653 | if (callflags & FF_PROBE) | 612 | if (walk.callflags & FF_PROBE) |
654 | filestr_base_destroy(stream); | 613 | filestr_base_destroy(stream); |
655 | 614 | } | |
656 | break; | 615 | else |
657 | 616 | { | |
658 | default: /* utter, abject failure :`( */ | 617 | /* utter, abject failure :`( */ |
659 | DEBUGF("Open failed: rc=%d, errno=%d\n", rc, errno); | 618 | DEBUGF("Open failed: rc=%d, errno=%d\n", rc, errno); |
660 | filestr_base_destroy(stream); | 619 | filestr_base_destroy(stream); |
661 | FILE_ERROR(-rc, -3); | 620 | FILE_ERROR(-rc, -1); |
662 | } | 621 | } |
663 | 622 | ||
664 | file_error: | 623 | file_error: |