diff options
Diffstat (limited to 'firmware/common')
-rw-r--r-- | firmware/common/dir.c | 92 | ||||
-rw-r--r-- | firmware/common/dircache.c | 9 | ||||
-rw-r--r-- | firmware/common/disk.c | 4 | ||||
-rw-r--r-- | firmware/common/file.c | 2 | ||||
-rw-r--r-- | firmware/common/file_internal.c | 95 | ||||
-rw-r--r-- | firmware/common/fileobj_mgr.c | 114 | ||||
-rw-r--r-- | firmware/common/pathfuncs.c | 43 | ||||
-rw-r--r-- | firmware/common/rb_namespace.c | 289 |
8 files changed, 195 insertions, 453 deletions
diff --git a/firmware/common/dir.c b/firmware/common/dir.c index 85e6ff316b..f89129ae34 100644 --- a/firmware/common/dir.c +++ b/firmware/common/dir.c | |||
@@ -27,14 +27,17 @@ | |||
27 | #include "dir.h" | 27 | #include "dir.h" |
28 | #include "pathfuncs.h" | 28 | #include "pathfuncs.h" |
29 | #include "fileobj_mgr.h" | 29 | #include "fileobj_mgr.h" |
30 | #include "rb_namespace.h" | 30 | #include "dircache_redirect.h" |
31 | 31 | ||
32 | /* structure used for open directory streams */ | 32 | /* structure used for open directory streams */ |
33 | static struct dirstr_desc | 33 | static struct dirstr_desc |
34 | { | 34 | { |
35 | struct filestr_base stream; /* basic stream info (first!) */ | 35 | struct filestr_base stream; /* basic stream info (first!) */ |
36 | struct ns_scan_info scan; /* directory scan cursor */ | 36 | struct dirscan_info scan; /* directory scan cursor */ |
37 | struct dirent entry; /* current parsed entry information */ | 37 | struct dirent entry; /* current parsed entry information */ |
38 | #ifdef HAVE_MULTIVOLUME | ||
39 | int volumecounter; /* counter for root volume entries */ | ||
40 | #endif | ||
38 | } open_streams[MAX_OPEN_DIRS]; | 41 | } open_streams[MAX_OPEN_DIRS]; |
39 | 42 | ||
40 | /* check and return a struct dirstr_desc* from a DIR* */ | 43 | /* check and return a struct dirstr_desc* from a DIR* */ |
@@ -44,7 +47,7 @@ static struct dirstr_desc * get_dirstr(DIR *dirp) | |||
44 | 47 | ||
45 | if (!PTR_IN_ARRAY(open_streams, dir, MAX_OPEN_DIRS)) | 48 | if (!PTR_IN_ARRAY(open_streams, dir, MAX_OPEN_DIRS)) |
46 | dir = NULL; | 49 | dir = NULL; |
47 | else if (dir->stream.flags & (FDO_BUSY|FD_VALID)) | 50 | else if (dir->stream.flags & FDO_BUSY) |
48 | return dir; | 51 | return dir; |
49 | 52 | ||
50 | int errnum; | 53 | int errnum; |
@@ -101,6 +104,49 @@ static struct dirstr_desc * alloc_dirstr(void) | |||
101 | return NULL; | 104 | return NULL; |
102 | } | 105 | } |
103 | 106 | ||
107 | #ifdef HAVE_MULTIVOLUME | ||
108 | static int readdir_volume_inner(struct dirstr_desc *dir, struct dirent *entry) | ||
109 | { | ||
110 | /* Volumes (secondary file systems) get inserted into the system root | ||
111 | * directory. If the path specified volume 0, enumeration will not | ||
112 | * include other volumes, but just its own files and directories. | ||
113 | * | ||
114 | * Fake special directories, which don't really exist, that will get | ||
115 | * redirected upon opendir() | ||
116 | */ | ||
117 | while (++dir->volumecounter < NUM_VOLUMES) | ||
118 | { | ||
119 | /* on the system root */ | ||
120 | if (!fat_ismounted(dir->volumecounter)) | ||
121 | continue; | ||
122 | |||
123 | get_volume_name(dir->volumecounter, entry->d_name); | ||
124 | dir->entry.info.attr = ATTR_MOUNT_POINT; | ||
125 | dir->entry.info.size = 0; | ||
126 | dir->entry.info.wrtdate = 0; | ||
127 | dir->entry.info.wrttime = 0; | ||
128 | return 1; | ||
129 | } | ||
130 | |||
131 | /* do normal directory entry fetching */ | ||
132 | return 0; | ||
133 | } | ||
134 | #endif /* HAVE_MULTIVOLUME */ | ||
135 | |||
136 | static inline int readdir_volume(struct dirstr_desc *dir, | ||
137 | struct dirent *entry) | ||
138 | { | ||
139 | #ifdef HAVE_MULTIVOLUME | ||
140 | /* fetch virtual volume entries? */ | ||
141 | if (dir->volumecounter < NUM_VOLUMES) | ||
142 | return readdir_volume_inner(dir, entry); | ||
143 | #endif /* HAVE_MULTIVOLUME */ | ||
144 | |||
145 | /* do normal directory entry fetching */ | ||
146 | return 0; | ||
147 | (void)dir; (void)entry; | ||
148 | } | ||
149 | |||
104 | 150 | ||
105 | /** POSIX interface **/ | 151 | /** POSIX interface **/ |
106 | 152 | ||
@@ -119,13 +165,21 @@ DIR * opendir(const char *dirname) | |||
119 | if (!dir) | 165 | if (!dir) |
120 | FILE_ERROR(EMFILE, RC); | 166 | FILE_ERROR(EMFILE, RC); |
121 | 167 | ||
122 | rc = ns_open_stream(dirname, FF_DIR, &dir->stream, &dir->scan); | 168 | rc = open_stream_internal(dirname, FF_DIR, &dir->stream, NULL); |
123 | if (rc < 0) | 169 | if (rc < 0) |
124 | { | 170 | { |
125 | DEBUGF("Open failed: %d\n", rc); | 171 | DEBUGF("Open failed: %d\n", rc); |
126 | FILE_ERROR(ERRNO, RC); | 172 | FILE_ERROR(ERRNO, RC); |
127 | } | 173 | } |
128 | 174 | ||
175 | #ifdef HAVE_MULTIVOLUME | ||
176 | /* volume counter is relevant only to the system root */ | ||
177 | dir->volumecounter = rc > 1 ? 0 : INT_MAX; | ||
178 | #endif /* HAVE_MULTIVOLUME */ | ||
179 | |||
180 | fat_rewind(&dir->stream.fatstr); | ||
181 | rewinddir_dirent(&dir->scan); | ||
182 | |||
129 | dirp = (DIR *)dir; | 183 | dirp = (DIR *)dir; |
130 | file_error: | 184 | file_error: |
131 | file_internal_unlock_WRITER(); | 185 | file_internal_unlock_WRITER(); |
@@ -150,7 +204,7 @@ int closedir(DIR *dirp) | |||
150 | FILE_ERROR(EBADF, -2); | 204 | FILE_ERROR(EBADF, -2); |
151 | } | 205 | } |
152 | 206 | ||
153 | rc = ns_close_stream(&dir->stream); | 207 | rc = close_stream_internal(&dir->stream); |
154 | if (rc < 0) | 208 | if (rc < 0) |
155 | FILE_ERROR(ERRNO, rc * 10 - 3); | 209 | FILE_ERROR(ERRNO, rc * 10 - 3); |
156 | 210 | ||
@@ -168,11 +222,16 @@ struct dirent * readdir(DIR *dirp) | |||
168 | 222 | ||
169 | struct dirent *res = NULL; | 223 | struct dirent *res = NULL; |
170 | 224 | ||
171 | int rc = ns_readdir_dirent(&dir->stream, &dir->scan, &dir->entry); | 225 | int rc = readdir_volume(dir, &dir->entry); |
226 | if (rc == 0) | ||
227 | { | ||
228 | rc = readdir_dirent(&dir->stream, &dir->scan, &dir->entry); | ||
229 | if (rc < 0) | ||
230 | FILE_ERROR(EIO, RC); | ||
231 | } | ||
232 | |||
172 | if (rc > 0) | 233 | if (rc > 0) |
173 | res = &dir->entry; | 234 | res = &dir->entry; |
174 | else if (rc < 0) | ||
175 | FILE_ERROR(EIO, RC); | ||
176 | 235 | ||
177 | file_error: | 236 | file_error: |
178 | RELEASE_DIRSTR(READER, dir); | 237 | RELEASE_DIRSTR(READER, dir); |
@@ -199,9 +258,13 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) | |||
199 | if (!dir) | 258 | if (!dir) |
200 | FILE_ERROR_RETURN(ERRNO, -1); | 259 | FILE_ERROR_RETURN(ERRNO, -1); |
201 | 260 | ||
202 | int rc = ns_readdir_dirent(&dir->stream, &dir->scan, entry); | 261 | int rc = readdir_volume(dir, entry); |
203 | if (rc < 0) | 262 | if (rc == 0) |
204 | FILE_ERROR(EIO, rc * 10 - 4); | 263 | { |
264 | rc = readdir_dirent(&dir->stream, &dir->scan, entry); | ||
265 | if (rc < 0) | ||
266 | FILE_ERROR(EIO, rc * 10 - 4); | ||
267 | } | ||
205 | 268 | ||
206 | file_error: | 269 | file_error: |
207 | RELEASE_DIRSTR(READER, dir); | 270 | RELEASE_DIRSTR(READER, dir); |
@@ -225,7 +288,12 @@ void rewinddir(DIR *dirp) | |||
225 | if (!dir) | 288 | if (!dir) |
226 | FILE_ERROR_RETURN(ERRNO); | 289 | FILE_ERROR_RETURN(ERRNO); |
227 | 290 | ||
228 | ns_dirscan_rewind(&dir->scan); | 291 | rewinddir_dirent(&dir->scan); |
292 | |||
293 | #ifdef HAVE_MULTIVOLUME | ||
294 | if (dir->volumecounter != INT_MAX) | ||
295 | dir->volumecounter = 0; | ||
296 | #endif /* HAVE_MULTIVOLUME */ | ||
229 | 297 | ||
230 | RELEASE_DIRSTR(READER, dir); | 298 | RELEASE_DIRSTR(READER, dir); |
231 | } | 299 | } |
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index cc65d2d540..0cdaf1bd4a 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c | |||
@@ -2541,10 +2541,13 @@ static ssize_t get_path_sub(int idx, struct get_path_sub_data *data) | |||
2541 | cename = ""; | 2541 | cename = ""; |
2542 | 2542 | ||
2543 | #ifdef HAVE_MULTIVOLUME | 2543 | #ifdef HAVE_MULTIVOLUME |
2544 | /* prepend the volume specifier */ | ||
2545 | int volume = IF_MV_VOL(-idx - 1); | 2544 | int volume = IF_MV_VOL(-idx - 1); |
2546 | cename = alloca(VOL_MAX_LEN+1); | 2545 | if (volume > 0) |
2547 | get_volume_name(volume, cename); | 2546 | { |
2547 | /* prepend the volume specifier for volumes > 0 */ | ||
2548 | cename = alloca(VOL_MAX_LEN+1); | ||
2549 | get_volume_name(volume, cename); | ||
2550 | } | ||
2548 | #endif /* HAVE_MULTIVOLUME */ | 2551 | #endif /* HAVE_MULTIVOLUME */ |
2549 | 2552 | ||
2550 | data->serialhash = dc_hash_serialnum(get_idx_dcvolp(idx)->serialnum, | 2553 | data->serialhash = dc_hash_serialnum(get_idx_dcvolp(idx)->serialnum, |
diff --git a/firmware/common/disk.c b/firmware/common/disk.c index 49137286a3..51d033b678 100644 --- a/firmware/common/disk.c +++ b/firmware/common/disk.c | |||
@@ -30,6 +30,10 @@ | |||
30 | #include "dircache_redirect.h" | 30 | #include "dircache_redirect.h" |
31 | #include "disk.h" | 31 | #include "disk.h" |
32 | 32 | ||
33 | #if defined(HAVE_BOOTDATA) && !defined(SIMULATOR) && !defined(BOOTLOADER) | ||
34 | #include "bootdata.h" | ||
35 | #include "crc32.h" | ||
36 | #endif | ||
33 | 37 | ||
34 | #ifndef CONFIG_DEFAULT_PARTNUM | 38 | #ifndef CONFIG_DEFAULT_PARTNUM |
35 | #define CONFIG_DEFAULT_PARTNUM 0 | 39 | #define CONFIG_DEFAULT_PARTNUM 0 |
diff --git a/firmware/common/file.c b/firmware/common/file.c index 893e475a32..cb918c6eab 100644 --- a/firmware/common/file.c +++ b/firmware/common/file.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #include "file.h" | 28 | #include "file.h" |
29 | #include "fileobj_mgr.h" | 29 | #include "fileobj_mgr.h" |
30 | #include "disk_cache.h" | 30 | #include "disk_cache.h" |
31 | #include "rb_namespace.h" | 31 | #include "dircache_redirect.h" |
32 | #include "string-extra.h" | 32 | #include "string-extra.h" |
33 | 33 | ||
34 | /** | 34 | /** |
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: |
diff --git a/firmware/common/fileobj_mgr.c b/firmware/common/fileobj_mgr.c index 37452fbbe1..e34a460e10 100644 --- a/firmware/common/fileobj_mgr.c +++ b/firmware/common/fileobj_mgr.c | |||
@@ -20,13 +20,12 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "config.h" | 21 | #include "config.h" |
22 | #include "system.h" | 22 | #include "system.h" |
23 | #include <errno.h> | ||
24 | #include "debug.h" | 23 | #include "debug.h" |
25 | #include "file.h" | 24 | #include "file.h" |
26 | #include "dir.h" | 25 | #include "dir.h" |
27 | #include "disk_cache.h" | 26 | #include "disk_cache.h" |
28 | #include "fileobj_mgr.h" | 27 | #include "fileobj_mgr.h" |
29 | #include "rb_namespace.h" | 28 | #include "dircache_redirect.h" |
30 | 29 | ||
31 | /** | 30 | /** |
32 | * Manages file and directory streams on all volumes | 31 | * Manages file and directory streams on all volumes |
@@ -35,8 +34,8 @@ | |||
35 | */ | 34 | */ |
36 | 35 | ||
37 | 36 | ||
38 | /* there will always be enough of these for all user handles, thus most of | 37 | /* there will always be enough of these for all user handles, thus these |
39 | these functions don't return failure codes */ | 38 | functions don't return failure codes */ |
40 | #define MAX_FILEOBJS (MAX_OPEN_HANDLES + AUX_FILEOBJS) | 39 | #define MAX_FILEOBJS (MAX_OPEN_HANDLES + AUX_FILEOBJS) |
41 | 40 | ||
42 | /* describes the file as an image on the storage medium */ | 41 | /* describes the file as an image on the storage medium */ |
@@ -85,15 +84,6 @@ static struct ll_head busy_bindings[NUM_VOLUMES]; | |||
85 | for (struct filestr_base *s = STREAM_##what(start); \ | 84 | for (struct filestr_base *s = STREAM_##what(start); \ |
86 | s; s = STREAM_NEXT(s)) | 85 | s; s = STREAM_NEXT(s)) |
87 | 86 | ||
88 | /* once a file/directory, always a file/directory; such a change | ||
89 | is a bug */ | ||
90 | #define CHECK_FO_DIRECTORY(callflags, fobp) \ | ||
91 | if (((callflags) ^ (fobp)->flags) & FO_DIRECTORY) \ | ||
92 | { \ | ||
93 | DEBUGF("%s - FO_DIRECTORY flag does not match: %p %u\n", \ | ||
94 | __func__, (fobp), (callflags)); \ | ||
95 | } | ||
96 | |||
97 | 87 | ||
98 | /* syncs information for the stream's old and new parent directory if any are | 88 | /* syncs information for the stream's old and new parent directory if any are |
99 | currently opened */ | 89 | currently opened */ |
@@ -106,10 +96,6 @@ static void fileobj_sync_parent(const struct file_base_info *infop[], | |||
106 | continue; /* not directory or removed can't be parent of anything */ | 96 | continue; /* not directory or removed can't be parent of anything */ |
107 | 97 | ||
108 | struct filestr_base *parentstrp = STREAM_FIRST(fobp); | 98 | struct filestr_base *parentstrp = STREAM_FIRST(fobp); |
109 | |||
110 | if (!parentstrp) | ||
111 | continue; | ||
112 | |||
113 | struct fat_file *parentfilep = &parentstrp->infop->fatfile; | 99 | struct fat_file *parentfilep = &parentstrp->infop->fatfile; |
114 | 100 | ||
115 | for (int i = 0; i < count; i++) | 101 | for (int i = 0; i < count; i++) |
@@ -125,7 +111,8 @@ static void fileobj_sync_parent(const struct file_base_info *infop[], | |||
125 | } | 111 | } |
126 | 112 | ||
127 | /* see if this file has open streams and return that fileobj_binding if so, | 113 | /* see if this file has open streams and return that fileobj_binding if so, |
128 | else grab a new one from the free list; returns true if this is new */ | 114 | else grab a new one from the free list; returns true if this stream is |
115 | the only open one */ | ||
129 | static bool binding_assign(const struct file_base_info *srcinfop, | 116 | static bool binding_assign(const struct file_base_info *srcinfop, |
130 | struct fileobj_binding **fobpp) | 117 | struct fileobj_binding **fobpp) |
131 | { | 118 | { |
@@ -136,7 +123,7 @@ static bool binding_assign(const struct file_base_info *srcinfop, | |||
136 | 123 | ||
137 | if (fat_file_is_same(&srcinfop->fatfile, &fobp->bind.info.fatfile)) | 124 | if (fat_file_is_same(&srcinfop->fatfile, &fobp->bind.info.fatfile)) |
138 | { | 125 | { |
139 | /* already has open streams/mounts */ | 126 | /* already has open streams */ |
140 | *fobpp = fobp; | 127 | *fobpp = fobp; |
141 | return false; | 128 | return false; |
142 | } | 129 | } |
@@ -156,23 +143,6 @@ static void binding_add_to_free_list(struct fileobj_binding *fobp) | |||
156 | ll_insert_last(FREE_BINDINGS(), &fobp->bind.node); | 143 | ll_insert_last(FREE_BINDINGS(), &fobp->bind.node); |
157 | } | 144 | } |
158 | 145 | ||
159 | static void bind_source_info(const struct file_base_info *srcinfop, | ||
160 | struct fileobj_binding **fobpp) | ||
161 | { | ||
162 | if (!binding_assign(srcinfop, fobpp)) | ||
163 | return; /* already in use */ | ||
164 | |||
165 | /* is new */ | ||
166 | (*fobpp)->bind.info = *srcinfop; | ||
167 | fileobj_bind_file(&(*fobpp)->bind); | ||
168 | } | ||
169 | |||
170 | static void release_binding(struct fileobj_binding *fobp) | ||
171 | { | ||
172 | fileobj_unbind_file(&fobp->bind); | ||
173 | binding_add_to_free_list(fobp); | ||
174 | } | ||
175 | |||
176 | /** File and directory internal interface **/ | 146 | /** File and directory internal interface **/ |
177 | 147 | ||
178 | void file_binding_insert_last(struct file_base_binding *bindp) | 148 | void file_binding_insert_last(struct file_base_binding *bindp) |
@@ -199,41 +169,6 @@ void file_binding_remove_next(struct file_base_binding *prevp, | |||
199 | } | 169 | } |
200 | #endif /* HAVE_DIRCACHE */ | 170 | #endif /* HAVE_DIRCACHE */ |
201 | 171 | ||
202 | /* mounts a file object as a target from elsewhere */ | ||
203 | bool fileobj_mount(const struct file_base_info *srcinfop, | ||
204 | unsigned int callflags, | ||
205 | struct file_base_binding **bindpp) | ||
206 | { | ||
207 | struct fileobj_binding *fobp; | ||
208 | bind_source_info(srcinfop, &fobp); | ||
209 | |||
210 | CHECK_FO_DIRECTORY(callflags, fobp); | ||
211 | |||
212 | if (fobp->flags & FO_MOUNTTARGET) | ||
213 | return false; /* already mounted */ | ||
214 | |||
215 | fobp->flags |= FDO_BUSY | FO_MOUNTTARGET | | ||
216 | (callflags & FO_DIRECTORY); | ||
217 | |||
218 | *bindpp = &fobp->bind; | ||
219 | |||
220 | return true; | ||
221 | } | ||
222 | |||
223 | /* unmounts the file object and frees it if now unusued */ | ||
224 | void fileobj_unmount(struct file_base_binding *bindp) | ||
225 | { | ||
226 | struct fileobj_binding *fobp = (struct fileobj_binding *)bindp; | ||
227 | |||
228 | if (!(fobp->flags & FO_MOUNTTARGET)) | ||
229 | return; /* not mounted */ | ||
230 | |||
231 | if (STREAM_FIRST(fobp) == NULL) | ||
232 | release_binding(fobp); /* no longer in use */ | ||
233 | else | ||
234 | fobp->flags &= ~FO_MOUNTTARGET; | ||
235 | } | ||
236 | |||
237 | /* opens the file object for a new stream and sets up the caches; | 172 | /* opens the file object for a new stream and sets up the caches; |
238 | * the stream must already be opened at the FS driver level and *stream | 173 | * the stream must already be opened at the FS driver level and *stream |
239 | * initialized. | 174 | * initialized. |
@@ -245,14 +180,10 @@ void fileobj_fileop_open(struct filestr_base *stream, | |||
245 | const struct file_base_info *srcinfop, | 180 | const struct file_base_info *srcinfop, |
246 | unsigned int callflags) | 181 | unsigned int callflags) |
247 | { | 182 | { |
248 | /* assign base file information */ | ||
249 | struct fileobj_binding *fobp; | 183 | struct fileobj_binding *fobp; |
250 | bind_source_info(srcinfop, &fobp); | 184 | bool first = binding_assign(srcinfop, &fobp); |
251 | |||
252 | unsigned int foflags = fobp->flags; | ||
253 | 185 | ||
254 | /* add stream to this file's list */ | 186 | /* add stream to this file's list */ |
255 | bool first = STREAM_FIRST(fobp) == NULL; | ||
256 | ll_insert_last(&fobp->list, &stream->node); | 187 | ll_insert_last(&fobp->list, &stream->node); |
257 | 188 | ||
258 | /* initiate the new stream into the enclave */ | 189 | /* initiate the new stream into the enclave */ |
@@ -266,16 +197,27 @@ void fileobj_fileop_open(struct filestr_base *stream, | |||
266 | if (first) | 197 | if (first) |
267 | { | 198 | { |
268 | /* first stream for file */ | 199 | /* first stream for file */ |
269 | fobp->flags = foflags | FDO_BUSY | FO_SINGLE | | 200 | fobp->bind.info = *srcinfop; |
270 | (callflags & (FO_DIRECTORY|FO_TRUNC)); | 201 | fobp->flags = FDO_BUSY | FO_SINGLE | |
271 | fobp->writers = 0; | 202 | (callflags & (FO_DIRECTORY|FO_TRUNC)); |
272 | fobp->size = 0; | 203 | fobp->writers = 0; |
204 | fobp->size = 0; | ||
205 | |||
206 | fileobj_bind_file(&fobp->bind); | ||
273 | } | 207 | } |
274 | else | 208 | else |
275 | { | 209 | { |
276 | /* additional stream for file */ | 210 | /* additional stream for file */ |
277 | fobp->flags = (foflags & ~FO_SINGLE) | (callflags & FO_TRUNC); | 211 | fobp->flags &= ~FO_SINGLE; |
278 | CHECK_FO_DIRECTORY(callflags, fobp); | 212 | fobp->flags |= callflags & FO_TRUNC; |
213 | |||
214 | /* once a file/directory, always a file/directory; such a change | ||
215 | is a bug */ | ||
216 | if ((callflags ^ fobp->flags) & FO_DIRECTORY) | ||
217 | { | ||
218 | DEBUGF("%s - FO_DIRECTORY flag does not match: %p %u\n", | ||
219 | __func__, stream, callflags); | ||
220 | } | ||
279 | } | 221 | } |
280 | 222 | ||
281 | if ((callflags & FD_WRITE) && ++fobp->writers == 1) | 223 | if ((callflags & FD_WRITE) && ++fobp->writers == 1) |
@@ -315,14 +257,12 @@ void fileobj_fileop_close(struct filestr_base *stream) | |||
315 | if (foflags & FO_SINGLE) | 257 | if (foflags & FO_SINGLE) |
316 | { | 258 | { |
317 | /* last stream for file; close everything */ | 259 | /* last stream for file; close everything */ |
260 | fileobj_unbind_file(&fobp->bind); | ||
261 | |||
318 | if (fobp->writers) | 262 | if (fobp->writers) |
319 | file_cache_free(&fobp->cache); | 263 | file_cache_free(&fobp->cache); |
320 | 264 | ||
321 | /* binding must stay valid if something is mounted to here */ | 265 | binding_add_to_free_list(fobp); |
322 | if (foflags & FO_MOUNTTARGET) | ||
323 | fobp->flags = foflags & (FDO_BUSY|FO_DIRECTORY|FO_MOUNTTARGET); | ||
324 | else | ||
325 | release_binding(fobp); | ||
326 | } | 266 | } |
327 | else | 267 | else |
328 | { | 268 | { |
diff --git a/firmware/common/pathfuncs.c b/firmware/common/pathfuncs.c index 078c0b6938..0935a9a6e3 100644 --- a/firmware/common/pathfuncs.c +++ b/firmware/common/pathfuncs.c | |||
@@ -105,7 +105,7 @@ static const unsigned char storage_dec_indexes[STORAGE_NUM_TYPES+1] = | |||
105 | */ | 105 | */ |
106 | int path_strip_volume(const char *name, const char **nameptr, bool greedy) | 106 | int path_strip_volume(const char *name, const char **nameptr, bool greedy) |
107 | { | 107 | { |
108 | int volume = ROOT_VOLUME; | 108 | int volume = 0; |
109 | const char *t = name; | 109 | const char *t = name; |
110 | int c, v = 0; | 110 | int c, v = 0; |
111 | 111 | ||
@@ -114,16 +114,9 @@ int path_strip_volume(const char *name, const char **nameptr, bool greedy) | |||
114 | * digits within the brackets is parsed as the volume number and of | 114 | * digits within the brackets is parsed as the volume number and of |
115 | * those, only the last ones VOL_MUM_MAX allows. | 115 | * those, only the last ones VOL_MUM_MAX allows. |
116 | */ | 116 | */ |
117 | t = GOBBLE_PATH_SEPCH(t); /* skip all leading slashes */ | 117 | c = *(t = GOBBLE_PATH_SEPCH(t)); /* skip all leading slashes */ |
118 | if (t == name) | ||
119 | { | ||
120 | volume = -1; /* relative path; don't know */ | ||
121 | goto psv_out; | ||
122 | } | ||
123 | |||
124 | c = *t; | ||
125 | if (c != VOL_START_TOK) /* missing start token? no volume */ | 118 | if (c != VOL_START_TOK) /* missing start token? no volume */ |
126 | goto psv_out; | 119 | goto volume0; |
127 | 120 | ||
128 | do | 121 | do |
129 | { | 122 | { |
@@ -134,7 +127,7 @@ int path_strip_volume(const char *name, const char **nameptr, bool greedy) | |||
134 | break; | 127 | break; |
135 | case '\0': | 128 | case '\0': |
136 | case PATH_SEPCH: /* no closing bracket; no volume */ | 129 | case PATH_SEPCH: /* no closing bracket; no volume */ |
137 | goto psv_out; | 130 | goto volume0; |
138 | default: /* something else; reset volume */ | 131 | default: /* something else; reset volume */ |
139 | v = 0; | 132 | v = 0; |
140 | } | 133 | } |
@@ -144,7 +137,7 @@ int path_strip_volume(const char *name, const char **nameptr, bool greedy) | |||
144 | if (!(c = *++t)) /* no more path and no '/' is ok */ | 137 | if (!(c = *++t)) /* no more path and no '/' is ok */ |
145 | ; | 138 | ; |
146 | else if (c != PATH_SEPCH) /* more path and no separator after end */ | 139 | else if (c != PATH_SEPCH) /* more path and no separator after end */ |
147 | goto psv_out; | 140 | goto volume0; |
148 | else if (greedy) | 141 | else if (greedy) |
149 | t = GOBBLE_PATH_SEPCH(++t); /* strip remaining separators */ | 142 | t = GOBBLE_PATH_SEPCH(++t); /* strip remaining separators */ |
150 | 143 | ||
@@ -153,7 +146,7 @@ int path_strip_volume(const char *name, const char **nameptr, bool greedy) | |||
153 | 146 | ||
154 | volume = v; | 147 | volume = v; |
155 | name = t; | 148 | name = t; |
156 | psv_out: | 149 | volume0: |
157 | if (nameptr) | 150 | if (nameptr) |
158 | *nameptr = name; | 151 | *nameptr = name; |
159 | return volume; | 152 | return volume; |
@@ -164,14 +157,10 @@ psv_out: | |||
164 | */ | 157 | */ |
165 | int get_volume_name(int volume, char *buffer) | 158 | int get_volume_name(int volume, char *buffer) |
166 | { | 159 | { |
167 | if (volume < 0 || volume == ROOT_VOLUME) | 160 | if (volume < 0) |
168 | { | 161 | { |
169 | char *t = buffer; | 162 | *buffer = '\0'; |
170 | if (volume == ROOT_VOLUME) | 163 | return 0; |
171 | *t++ = PATH_ROOTCHR; | ||
172 | |||
173 | *t = '\0'; | ||
174 | return t - buffer; | ||
175 | } | 164 | } |
176 | 165 | ||
177 | volume %= VOL_NUM_MAX; /* as path parser would have it */ | 166 | volume %= VOL_NUM_MAX; /* as path parser would have it */ |
@@ -184,20 +173,6 @@ int get_volume_name(int volume, char *buffer) | |||
184 | return snprintf(buffer, VOL_MAX_LEN + 1, "%c%s%d%c", | 173 | return snprintf(buffer, VOL_MAX_LEN + 1, "%c%s%d%c", |
185 | VOL_START_TOK, voldec, volume, VOL_END_TOK); | 174 | VOL_START_TOK, voldec, volume, VOL_END_TOK); |
186 | } | 175 | } |
187 | |||
188 | /* Returns volume name formatted with the root. Assumes buffer size is at | ||
189 | * least {VOL_MAX_LEN}+2 */ | ||
190 | int make_volume_root(int volume, char *buffer) | ||
191 | { | ||
192 | char *t = buffer; | ||
193 | |||
194 | if (volume >= 0 && volume != ROOT_VOLUME) | ||
195 | *t++ = PATH_ROOTCHR; | ||
196 | |||
197 | t += get_volume_name(volume, t); | ||
198 | |||
199 | return t - buffer; | ||
200 | } | ||
201 | #endif /* HAVE_MULTIVOLUME */ | 176 | #endif /* HAVE_MULTIVOLUME */ |
202 | 177 | ||
203 | /* Just like path_strip_volume() but strips a leading drive specifier and | 178 | /* Just like path_strip_volume() but strips a leading drive specifier and |
diff --git a/firmware/common/rb_namespace.c b/firmware/common/rb_namespace.c deleted file mode 100644 index 04f92e97af..0000000000 --- a/firmware/common/rb_namespace.c +++ /dev/null | |||
@@ -1,289 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2017 by Michael Sevakis | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "config.h" | ||
22 | #include <errno.h> | ||
23 | #include "fileobj_mgr.h" | ||
24 | #include "rb_namespace.h" | ||
25 | |||
26 | #define ROOT_CONTENTS_INDEX (NUM_VOLUMES) | ||
27 | #define NUM_ROOT_ITEMS (NUM_VOLUMES+1) | ||
28 | |||
29 | static uint8_t root_entry_flags[NUM_VOLUMES+1]; | ||
30 | static struct file_base_binding *root_bindp; | ||
31 | |||
32 | static inline unsigned int get_root_item_state(int item) | ||
33 | { | ||
34 | return root_entry_flags[item]; | ||
35 | } | ||
36 | |||
37 | static inline void set_root_item_state(int item, unsigned int state) | ||
38 | { | ||
39 | root_entry_flags[item] = state; | ||
40 | } | ||
41 | |||
42 | static void get_mount_point_entry(IF_MV(int volume,) struct dirent *entry) | ||
43 | { | ||
44 | #ifdef HAVE_MULTIVOLUME | ||
45 | get_volume_name(volume, entry->d_name); | ||
46 | #else /* */ | ||
47 | strcpy(entry->d_name, PATH_ROOTSTR); | ||
48 | #endif /* HAVE_MULTIVOLUME */ | ||
49 | |||
50 | /* is dirinfo_native */ | ||
51 | entry->info.attr = ATTR_MOUNT_POINT; | ||
52 | entry->info.size = 0; | ||
53 | entry->info.wrtdate = 0; | ||
54 | entry->info.wrttime = 0; | ||
55 | } | ||
56 | |||
57 | /* unmount the directory that enumerates into the root namespace */ | ||
58 | static void unmount_item(int item) | ||
59 | { | ||
60 | unsigned int state = get_root_item_state(item); | ||
61 | if (!state) | ||
62 | return; | ||
63 | |||
64 | if (state & NSITEM_CONTENTS) | ||
65 | { | ||
66 | fileobj_unmount(root_bindp); | ||
67 | root_bindp = NULL; | ||
68 | } | ||
69 | |||
70 | set_root_item_state(item, 0); | ||
71 | } | ||
72 | |||
73 | /* mount the directory that enumerates into the root namespace */ | ||
74 | int root_mount_path(const char *path, unsigned int flags) | ||
75 | { | ||
76 | #ifdef HAVE_MULTIVOLUME | ||
77 | int volume = path_strip_volume(path, NULL, false); | ||
78 | if (volume == ROOT_VOLUME) | ||
79 | return -EINVAL; | ||
80 | |||
81 | if (!CHECK_VOL(volume)) | ||
82 | return -ENOENT; | ||
83 | #else | ||
84 | if (!path_is_absolute(path)) | ||
85 | return -ENOENT; | ||
86 | #endif /* HAVE_MULTIVOLUME */ | ||
87 | |||
88 | bool contents = flags & NSITEM_CONTENTS; | ||
89 | int item = contents ? ROOT_CONTENTS_INDEX : IF_MV_VOL(volume); | ||
90 | unsigned int state = get_root_item_state(item); | ||
91 | |||
92 | if (state) | ||
93 | return -EBUSY; | ||
94 | |||
95 | if (contents) | ||
96 | { | ||
97 | /* cache information about the target */ | ||
98 | struct filestr_base stream; | ||
99 | struct path_component_info compinfo; | ||
100 | |||
101 | int e = errno; | ||
102 | int rc = open_stream_internal(path, FF_DIR | FF_PROBE | FF_INFO | | ||
103 | FF_DEVPATH, &stream, &compinfo); | ||
104 | if (rc <= 0) | ||
105 | { | ||
106 | rc = rc ? -errno : -ENOENT; | ||
107 | errno = e; | ||
108 | return rc; | ||
109 | } | ||
110 | |||
111 | if (!fileobj_mount(&compinfo.info, FO_DIRECTORY, &root_bindp)) | ||
112 | return -EBUSY; | ||
113 | } | ||
114 | |||
115 | state = NSITEM_MOUNTED | (flags & (NSITEM_HIDDEN|NSITEM_CONTENTS)); | ||
116 | set_root_item_state(item, state); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /* inform root that an entire volume is being unmounted */ | ||
122 | void root_unmount_volume(IF_MV_NONVOID(int volume)) | ||
123 | { | ||
124 | FOR_EACH_VOLUME(volume, item) | ||
125 | { | ||
126 | #ifdef HAVE_MULTIVOLUME | ||
127 | uint32_t state = get_root_item_state(item); | ||
128 | if (state && (volume < 0 || item == volume)) | ||
129 | #endif /* HAVE_MULTIVOLUME */ | ||
130 | unmount_item(item); | ||
131 | } | ||
132 | |||
133 | /* if the volume unmounted contains the root directory contents then | ||
134 | the contents must also be unmounted */ | ||
135 | #ifdef HAVE_MULTIVOLUME | ||
136 | uint32_t state = get_root_item_state(ROOT_CONTENTS_INDEX); | ||
137 | if (state && (volume < 0 || BASEINFO_VOL(&root_bindp->info) == volume)) | ||
138 | #endif | ||
139 | unmount_item(ROOT_CONTENTS_INDEX); | ||
140 | } | ||
141 | |||
142 | /* parse the root part of a path */ | ||
143 | int ns_parse_root(const char *path, const char **pathp, uint16_t *lenp) | ||
144 | { | ||
145 | int volume = ROOT_VOLUME; | ||
146 | |||
147 | #ifdef HAVE_MULTIVOLUME | ||
148 | /* this seamlessly integrates secondary filesystems into the | ||
149 | root namespace (e.g. "/<0>/../../<1>/../foo/." :<=> "/foo") */ | ||
150 | const char *p; | ||
151 | volume = path_strip_volume(path, &p, false); | ||
152 | if (volume != ROOT_VOLUME && !CHECK_VOL(volume)) | ||
153 | return -ENOENT; | ||
154 | #endif /* HAVE_MULTIVOLUME */ | ||
155 | |||
156 | /* set name to start at last leading separator; name of root will | ||
157 | * be returned as "/", volume specifiers as "/<fooN>" */ | ||
158 | *pathp = GOBBLE_PATH_SEPCH(path) - 1; | ||
159 | *lenp = IF_MV( volume < NUM_VOLUMES ? p - *pathp : ) 1; | ||
160 | |||
161 | #ifdef HAVE_MULTIVOLUME | ||
162 | if (*lenp > MAX_COMPNAME+1) | ||
163 | return -ENAMETOOLONG; | ||
164 | #endif | ||
165 | |||
166 | return volume; | ||
167 | } | ||
168 | |||
169 | /* open one of the items in the root */ | ||
170 | int ns_open_root(IF_MV(int volume,) unsigned int *callflagsp, | ||
171 | struct file_base_info *infop, uint16_t *attrp) | ||
172 | { | ||
173 | unsigned int callflags = *callflagsp; | ||
174 | bool devpath = !!(callflags & FF_DEVPATH); | ||
175 | #ifdef HAVE_MULTIVOLUME | ||
176 | bool sysroot = volume == ROOT_VOLUME; | ||
177 | if (devpath && sysroot) | ||
178 | return -ENOENT; /* devpath needs volume spec */ | ||
179 | #else | ||
180 | bool sysroot = !devpath; /* always sysroot unless devpath */ | ||
181 | #endif | ||
182 | |||
183 | int item = sysroot ? ROOT_CONTENTS_INDEX : IF_MV_VOL(volume); | ||
184 | unsigned int state = get_root_item_state(item); | ||
185 | |||
186 | if (sysroot) | ||
187 | { | ||
188 | *attrp = ATTR_SYSTEM_ROOT; | ||
189 | |||
190 | if (state) | ||
191 | *infop = root_bindp->info; | ||
192 | else | ||
193 | *callflagsp = callflags | FF_NOFS; /* contents not mounted */ | ||
194 | } | ||
195 | else | ||
196 | { | ||
197 | *attrp = ATTR_MOUNT_POINT; | ||
198 | |||
199 | if (!devpath && !state) | ||
200 | return -ENOENT; /* regular open requires having been mounted */ | ||
201 | |||
202 | if (fat_open_rootdir(IF_MV(volume,) &infop->fatfile) < 0) | ||
203 | return -ENOENT; /* not mounted */ | ||
204 | |||
205 | get_rootinfo_internal(infop); | ||
206 | } | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | /* read root directory entries */ | ||
212 | int root_readdir_dirent(struct filestr_base *stream, | ||
213 | struct ns_scan_info *scanp, struct dirent *entry) | ||
214 | { | ||
215 | int rc = 0; | ||
216 | |||
217 | int item = scanp->item; | ||
218 | |||
219 | /* skip any not-mounted or hidden items */ | ||
220 | unsigned int state; | ||
221 | while (1) | ||
222 | { | ||
223 | if (item >= NUM_ROOT_ITEMS) | ||
224 | goto file_eod; | ||
225 | |||
226 | state = get_root_item_state(item); | ||
227 | if ((state & (NSITEM_MOUNTED|NSITEM_HIDDEN)) == NSITEM_MOUNTED) | ||
228 | break; | ||
229 | |||
230 | item++; | ||
231 | } | ||
232 | |||
233 | if (item == ROOT_CONTENTS_INDEX) | ||
234 | { | ||
235 | rc = readdir_dirent(stream, &scanp->scan, entry); | ||
236 | if (rc < 0) | ||
237 | FILE_ERROR(ERRNO, rc * 10 - 1); | ||
238 | |||
239 | if (rc == 0) | ||
240 | item++; | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | get_mount_point_entry(IF_MV(item,) entry); | ||
245 | item++; | ||
246 | rc = 1; | ||
247 | } | ||
248 | |||
249 | scanp->item = item; | ||
250 | |||
251 | file_eod: | ||
252 | if (rc == 0) | ||
253 | empty_dirent(entry); | ||
254 | |||
255 | file_error: | ||
256 | return rc; | ||
257 | } | ||
258 | |||
259 | /* opens a stream to enumerate items in a namespace container */ | ||
260 | int ns_open_stream(const char *path, unsigned int callflags, | ||
261 | struct filestr_base *stream, struct ns_scan_info *scanp) | ||
262 | { | ||
263 | /* stream still needs synchronization even if we don't have a stream */ | ||
264 | static struct mutex no_contents_mtx SHAREDBSS_ATTR; | ||
265 | |||
266 | int rc = open_stream_internal(path, callflags, stream, NULL); | ||
267 | if (rc < 0) | ||
268 | FILE_ERROR(ERRNO, rc * 10 - 1); | ||
269 | |||
270 | scanp->item = rc > 1 ? 0 : -1; | ||
271 | |||
272 | if (stream->flags & FDO_BUSY) | ||
273 | { | ||
274 | /* root contents are mounted */ | ||
275 | fat_rewind(&stream->fatstr); | ||
276 | } | ||
277 | else | ||
278 | { | ||
279 | /* root contents not mounted */ | ||
280 | mutex_init(&no_contents_mtx); | ||
281 | stream->mtx = &no_contents_mtx; | ||
282 | } | ||
283 | |||
284 | ns_dirscan_rewind(scanp); | ||
285 | |||
286 | rc = 0; | ||
287 | file_error: | ||
288 | return rc; | ||
289 | } | ||