summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Wilgus <wilgus.william@gmail.com>2020-08-20 21:54:00 -0400
committerWilliam Wilgus <wilgus.william@gmail.com>2020-08-20 21:54:00 -0400
commitf850bbbbc4b7345bebde241f651bad1c5c28df66 (patch)
tree1574bcca604f0617130aa9f1c426cfcdc097c901
parentbd744059cf959c8b9086978b32660efef5925b7d (diff)
downloadrockbox-f850bbbbc4b7345bebde241f651bad1c5c28df66.tar.gz
rockbox-f850bbbbc4b7345bebde241f651bad1c5c28df66.zip
Revert root_redirect :(
This reverts commit 31fc46ded69be7438cca2ba2c2b93c1f200165a6. Change-Id: Ia78618c0e8b25ca65f7c8ae0db1cb9c9b321bad9
-rw-r--r--apps/debug_menu.c19
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/common/dir.c92
-rw-r--r--firmware/common/dircache.c9
-rw-r--r--firmware/common/disk.c4
-rw-r--r--firmware/common/file.c2
-rw-r--r--firmware/common/file_internal.c95
-rw-r--r--firmware/common/fileobj_mgr.c114
-rw-r--r--firmware/common/pathfuncs.c43
-rw-r--r--firmware/common/rb_namespace.c289
-rw-r--r--firmware/export/mv.h4
-rw-r--r--firmware/export/pathfuncs.h6
-rw-r--r--firmware/export/rbpaths.h3
-rw-r--r--firmware/include/dircache_redirect.h58
-rw-r--r--firmware/include/file_internal.h22
-rw-r--r--firmware/include/fileobj_mgr.h5
-rw-r--r--firmware/include/fs_defines.h11
-rw-r--r--firmware/include/rb_namespace.h79
-rw-r--r--uisimulator/common/filesystem-sim.c2
19 files changed, 214 insertions, 644 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index eae389d049..e75fce6d32 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -2453,21 +2453,16 @@ static bool dbg_boot_data(void)
2453 simplelist_set_line_count(0); 2453 simplelist_set_line_count(0);
2454 crc = crc_32(boot_data.payload, boot_data.length, 0xffffffff); 2454 crc = crc_32(boot_data.payload, boot_data.length, 0xffffffff);
2455#if defined(HAVE_MULTIBOOT) 2455#if defined(HAVE_MULTIBOOT)
2456 char rootpath[VOL_MAX_LEN+2] = RB_ROOT_CONTENTS_DIR;
2457 int boot_volume = 0; 2456 int boot_volume = 0;
2458 if(crc == boot_data.crc) 2457 if(crc == boot_data.crc)
2459 { 2458 {
2460 boot_volume = boot_data.boot_volume; /* boot volume contained in uint8_t payload */ 2459 boot_volume = boot_data.boot_volume; /* boot volume contained in uint8_t payload */
2461 get_redirect_dir(rootpath, sizeof(rootpath), boot_volume, "", ""); 2460 }
2462 rootpath[path_strip_trailing_separators(rootpath,NULL)] = '\0'; 2461 simplelist_addline("Boot Volume: <%lu>", boot_volume);
2463 } 2462 simplelist_addline("");
2464 simplelist_addline("Boot Volume: <%lu>", boot_volume);
2465 simplelist_addline("Root:");
2466 simplelist_addline("%s", rootpath);
2467 simplelist_addline("");
2468#endif 2463#endif
2469 simplelist_addline("Bootdata RAW:"); 2464 simplelist_addline("Bootdata RAW:");
2470 if (crc != boot_data.crc) 2465 if (crc != boot_data.crc)
2471 simplelist_addline("Magic: %.8s", boot_data.magic); 2466 simplelist_addline("Magic: %.8s", boot_data.magic);
2472 simplelist_addline("Length: %lu", boot_data.length); 2467 simplelist_addline("Length: %lu", boot_data.length);
2473 simplelist_addline("CRC: %lx", boot_data.crc); 2468 simplelist_addline("CRC: %lx", boot_data.crc);
diff --git a/firmware/SOURCES b/firmware/SOURCES
index f1c7621244..a68d10ec76 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -238,7 +238,6 @@ common/dircache.c
238common/pathfuncs.c 238common/pathfuncs.c
239common/fdprintf.c 239common/fdprintf.c
240common/linked_list.c 240common/linked_list.c
241common/rb_namespace.c
242common/strcasecmp.c 241common/strcasecmp.c
243common/strcasestr.c 242common/strcasestr.c
244common/strnatcmp.c 243common/strnatcmp.c
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 */
33static struct dirstr_desc 33static 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
108static 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
136static 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;
130file_error: 184file_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
177file_error: 236file_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
206file_error: 269file_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
88static inline void filestr_clear(struct filestr_base *stream, 90static 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 */
153void filestr_base_init(struct filestr_base *stream) 154void 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 */
161void filestr_base_destroy(struct filestr_base *stream) 162void 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
623file_error: 664file_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 */
129static bool binding_assign(const struct file_base_info *srcinfop, 116static 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
159static 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
170static 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
178void file_binding_insert_last(struct file_base_binding *bindp) 148void 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 */
203bool 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 */
224void 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 */
106int path_strip_volume(const char *name, const char **nameptr, bool greedy) 106int 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;
156psv_out: 149volume0:
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 */
165int get_volume_name(int volume, char *buffer) 158int 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 */
190int 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
29static uint8_t root_entry_flags[NUM_VOLUMES+1];
30static struct file_base_binding *root_bindp;
31
32static inline unsigned int get_root_item_state(int item)
33{
34 return root_entry_flags[item];
35}
36
37static inline void set_root_item_state(int item, unsigned int state)
38{
39 root_entry_flags[item] = state;
40}
41
42static 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 */
58static 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 */
74int 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 */
122void 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 */
143int 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 */
170int 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 */
212int 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
251file_eod:
252 if (rc == 0)
253 empty_dirent(entry);
254
255file_error:
256 return rc;
257}
258
259/* opens a stream to enumerate items in a namespace container */
260int 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;
287file_error:
288 return rc;
289}
diff --git a/firmware/export/mv.h b/firmware/export/mv.h
index 5aa0ff8b4d..ec7b2efdbd 100644
--- a/firmware/export/mv.h
+++ b/firmware/export/mv.h
@@ -84,10 +84,6 @@
84#define VOL_MAX_LEN (1 + VOL_DEC_MAX_LEN + 2 + 1) 84#define VOL_MAX_LEN (1 + VOL_DEC_MAX_LEN + 2 + 1)
85#define VOL_NUM_MAX 100 85#define VOL_NUM_MAX 100
86 86
87#ifndef ROOT_VOLUME
88#define ROOT_VOLUME INT_MAX
89#endif
90
91#else /* empty definitions if no multi-volume */ 87#else /* empty definitions if no multi-volume */
92#define IF_MV(x...) 88#define IF_MV(x...)
93#define IF_MV_NONVOID(x...) void 89#define IF_MV_NONVOID(x...) void
diff --git a/firmware/export/pathfuncs.h b/firmware/export/pathfuncs.h
index 8858d85d24..92539c54c1 100644
--- a/firmware/export/pathfuncs.h
+++ b/firmware/export/pathfuncs.h
@@ -30,15 +30,10 @@
30/* useful char constants that could be reconfigured if desired */ 30/* useful char constants that could be reconfigured if desired */
31#define PATH_SEPCH '/' 31#define PATH_SEPCH '/'
32#define PATH_SEPSTR "/" 32#define PATH_SEPSTR "/"
33#define PATH_ROOTCHR '/'
34#define PATH_ROOTSTR "/" 33#define PATH_ROOTSTR "/"
35#define PATH_BADSEPCH '\\' 34#define PATH_BADSEPCH '\\'
36#define PATH_DRVSEPCH ':' 35#define PATH_DRVSEPCH ':'
37 36
38#ifndef ROOT_VOLUME
39#define ROOT_VOLUME INT_MAX
40#endif
41
42/* a nicer way to check for "." and ".." than two strcmp() calls */ 37/* a nicer way to check for "." and ".." than two strcmp() calls */
43static inline bool is_dotdir_name(const char *name) 38static inline bool is_dotdir_name(const char *name)
44{ 39{
@@ -80,7 +75,6 @@ static inline bool name_is_dot_dot(const char *name)
80#ifdef HAVE_MULTIVOLUME 75#ifdef HAVE_MULTIVOLUME
81int path_strip_volume(const char *name, const char **nameptr, bool greedy); 76int path_strip_volume(const char *name, const char **nameptr, bool greedy);
82int get_volume_name(int volume, char *name); 77int get_volume_name(int volume, char *name);
83int make_volume_root(int volume, char *dst);
84#endif 78#endif
85 79
86int path_strip_drive(const char *name, const char **nameptr, bool greedy); 80int path_strip_drive(const char *name, const char **nameptr, bool greedy);
diff --git a/firmware/export/rbpaths.h b/firmware/export/rbpaths.h
index 458a070f92..de591f0ec1 100644
--- a/firmware/export/rbpaths.h
+++ b/firmware/export/rbpaths.h
@@ -64,9 +64,6 @@
64#define PLUGIN_DIR ROCKBOX_DIR "/rocks" 64#define PLUGIN_DIR ROCKBOX_DIR "/rocks"
65#define CODECS_DIR ROCKBOX_DIR "/codecs" 65#define CODECS_DIR ROCKBOX_DIR "/codecs"
66 66
67#define RB_ROOT_VOL_HIDDEN(v) (IF_MV_VOL(v) == 0)
68#define RB_ROOT_CONTENTS_DIR "/" IF_MV("<0>")
69
70#else /* APPLICATION */ 67#else /* APPLICATION */
71 68
72#define HOME_DIR "<HOME>" /* replaced at runtime */ 69#define HOME_DIR "<HOME>" /* replaced at runtime */
diff --git a/firmware/include/dircache_redirect.h b/firmware/include/dircache_redirect.h
index e8cf8dc8f5..9fae16b551 100644
--- a/firmware/include/dircache_redirect.h
+++ b/firmware/include/dircache_redirect.h
@@ -20,16 +20,7 @@
20 ****************************************************************************/ 20 ****************************************************************************/
21#ifndef _DIRCACHE_REDIRECT_H_ 21#ifndef _DIRCACHE_REDIRECT_H_
22 22
23#include "rbpaths.h"
24#include "pathfuncs.h"
25#include "dir.h" 23#include "dir.h"
26#include "dircache.h"
27
28#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR)
29#include "rb-loader.h"
30#include "bootdata.h"
31#include "crc32.h"
32#endif
33 24
34/*** 25/***
35 ** Internal redirects that depend upon whether or not dircache is made 26 ** Internal redirects that depend upon whether or not dircache is made
@@ -132,56 +123,10 @@ static inline void fileop_onsync_internal(struct filestr_base *stream)
132 123
133static inline void volume_onmount_internal(IF_MV_NONVOID(int volume)) 124static inline void volume_onmount_internal(IF_MV_NONVOID(int volume))
134{ 125{
135#ifdef HAVE_MULTIVOLUME
136 char path[VOL_MAX_LEN+2];
137 make_volume_root(volume, path);
138#else
139 const char *path = PATH_ROOTSTR;
140#endif
141
142#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR)
143 static char rtpath[VOL_MAX_LEN+2] = RB_ROOT_CONTENTS_DIR;
144 static bool redirected = false;
145 int boot_volume = 0;
146 unsigned int crc = 0;
147
148 crc = crc_32(boot_data.payload, boot_data.length, 0xffffffff);
149 if (crc == boot_data.crc)
150 {
151 root_mount_path(path, 0); /*root could be different folder don't hide*/
152 boot_volume = boot_data.boot_volume; /* boot volume contained in uint8_t payload */
153 //root_mount_path(path, volume == boot_volume ? NSITEM_HIDDEN : 0);
154 if (!redirected && volume == boot_volume)
155 {
156 if (get_redirect_dir(rtpath, sizeof(rtpath), volume, "", "") < 0)
157 { /* Error occurred, card removed? Set root to default */
158 root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS);
159 }
160 else
161 redirected = true;
162 }
163 if (redirected && volume == boot_volume)
164 root_mount_path(rtpath, NSITEM_CONTENTS);
165 } /*CRC OK*/
166 else
167 {
168 root_mount_path(path, RB_ROOT_VOL_HIDDEN(volume) ? NSITEM_HIDDEN : 0);
169 if (volume == path_strip_volume(RB_ROOT_CONTENTS_DIR, NULL, false))
170 root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS);
171 }
172#else
173
174 root_mount_path(path, RB_ROOT_VOL_HIDDEN(volume) ? NSITEM_HIDDEN : 0);
175#ifdef HAVE_MULTIVOLUME
176 if (volume == path_strip_volume(RB_ROOT_CONTENTS_DIR, NULL, false))
177#endif
178 root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS);
179
180#endif /* HAVE_MULTIBOOT */
181
182#ifdef HAVE_DIRCACHE 126#ifdef HAVE_DIRCACHE
183 dircache_mount(); 127 dircache_mount();
184#endif 128#endif
129 IF_MV( (void)volume; )
185} 130}
186 131
187static inline void volume_onunmount_internal(IF_MV_NONVOID(int volume)) 132static inline void volume_onunmount_internal(IF_MV_NONVOID(int volume))
@@ -190,7 +135,6 @@ static inline void volume_onunmount_internal(IF_MV_NONVOID(int volume))
190 /* First, to avoid update of something about to be destroyed anyway */ 135 /* First, to avoid update of something about to be destroyed anyway */
191 dircache_unmount(IF_MV(volume)); 136 dircache_unmount(IF_MV(volume));
192#endif 137#endif
193 root_unmount_volume(IF_MV(volume));
194 fileobj_mgr_unmount(IF_MV(volume)); 138 fileobj_mgr_unmount(IF_MV(volume));
195} 139}
196 140
diff --git a/firmware/include/file_internal.h b/firmware/include/file_internal.h
index f4bd8bb8c2..d62b5a8541 100644
--- a/firmware/include/file_internal.h
+++ b/firmware/include/file_internal.h
@@ -72,18 +72,16 @@ enum fildes_and_obj_flags
72 /* used in descriptor and common */ 72 /* used in descriptor and common */
73 FDO_BUSY = 0x0001, /* descriptor/object is in use */ 73 FDO_BUSY = 0x0001, /* descriptor/object is in use */
74 /* only used in individual stream descriptor */ 74 /* only used in individual stream descriptor */
75 FD_VALID = 0x0002, /* descriptor is valid but not registered */ 75 FD_WRITE = 0x0002, /* descriptor has write mode */
76 FD_WRITE = 0x0004, /* descriptor has write mode */ 76 FD_WRONLY = 0x0004, /* descriptor is write mode only */
77 FD_WRONLY = 0x0008, /* descriptor is write mode only */ 77 FD_APPEND = 0x0008, /* descriptor is append mode */
78 FD_APPEND = 0x0010, /* descriptor is append mode */
79 FD_NONEXIST = 0x8000, /* closed but not freed (uncombined) */ 78 FD_NONEXIST = 0x8000, /* closed but not freed (uncombined) */
80 /* only used as common flags */ 79 /* only used as common flags */
81 FO_DIRECTORY = 0x0020, /* fileobj is a directory */ 80 FO_DIRECTORY = 0x0010, /* fileobj is a directory */
82 FO_TRUNC = 0x0040, /* fileobj is opened to be truncated */ 81 FO_TRUNC = 0x0020, /* fileobj is opened to be truncated */
83 FO_REMOVED = 0x0080, /* fileobj was deleted while open */ 82 FO_REMOVED = 0x0040, /* fileobj was deleted while open */
84 FO_SINGLE = 0x0100, /* fileobj has only one stream open */ 83 FO_SINGLE = 0x0080, /* fileobj has only one stream open */
85 FO_MOUNTTARGET = 0x0200, /* fileobj kept open as a mount target */ 84 FDO_MASK = 0x00ff,
86 FDO_MASK = 0x03ff,
87 FDO_CHG_MASK = FO_TRUNC, /* fileobj permitted external change */ 85 FDO_CHG_MASK = FO_TRUNC, /* fileobj permitted external change */
88 /* bitflags that instruct various 'open' functions how to behave; 86 /* bitflags that instruct various 'open' functions how to behave;
89 * saved in stream flags (only) but not used by manager */ 87 * saved in stream flags (only) but not used by manager */
@@ -97,9 +95,7 @@ enum fildes_and_obj_flags
97 FF_CACHEONLY = 0x00200000, /* succeed only if in dircache */ 95 FF_CACHEONLY = 0x00200000, /* succeed only if in dircache */
98 FF_INFO = 0x00400000, /* return info on self */ 96 FF_INFO = 0x00400000, /* return info on self */
99 FF_PARENTINFO = 0x00800000, /* return info on parent */ 97 FF_PARENTINFO = 0x00800000, /* return info on parent */
100 FF_DEVPATH = 0x01000000, /* path is a device path, not root-based */ 98 FF_MASK = 0x00ff0000,
101 FF_NOFS = 0x02000000, /* no filesystem mounted here */
102 FF_MASK = 0x03ff0000,
103}; 99};
104 100
105/** Common data structures used throughout **/ 101/** Common data structures used throughout **/
diff --git a/firmware/include/fileobj_mgr.h b/firmware/include/fileobj_mgr.h
index 0db3520d34..627d2df341 100644
--- a/firmware/include/fileobj_mgr.h
+++ b/firmware/include/fileobj_mgr.h
@@ -29,11 +29,6 @@ void file_binding_remove(struct file_base_binding *bindp);
29void file_binding_remove_next(struct file_base_binding *prevp, 29void file_binding_remove_next(struct file_base_binding *prevp,
30 struct file_base_binding *bindp); 30 struct file_base_binding *bindp);
31 31
32bool fileobj_mount(const struct file_base_info *srcinfop,
33 unsigned int callflags,
34 struct file_base_binding **bindpp);
35void fileobj_unmount(struct file_base_binding *bindp);
36
37void fileobj_fileop_open(struct filestr_base *stream, 32void fileobj_fileop_open(struct filestr_base *stream,
38 const struct file_base_info *srcinfop, 33 const struct file_base_info *srcinfop,
39 unsigned int callflags); 34 unsigned int callflags);
diff --git a/firmware/include/fs_defines.h b/firmware/include/fs_defines.h
index aee6daff6a..538c4b36cd 100644
--- a/firmware/include/fs_defines.h
+++ b/firmware/include/fs_defines.h
@@ -51,19 +51,12 @@
51/* internal functions open streams as well; make sure they don't fail if all 51/* internal functions open streams as well; make sure they don't fail if all
52 user descs are busy; this needs to be at least the greatest quantity needed 52 user descs are busy; this needs to be at least the greatest quantity needed
53 at once by all internal functions */ 53 at once by all internal functions */
54/* internal functions open streams as well; make sure they don't fail if all
55 user descs are busy; this needs to be at least the greatest quantity needed
56 at once by all internal functions */
57#define MOUNT_AUX_FILEOBJS 1
58
59#ifdef HAVE_DIRCACHE 54#ifdef HAVE_DIRCACHE
60#define DIRCACHE_AUX_FILEOBJS 1 55#define AUX_FILEOBJS 3
61#else 56#else
62#define DIRCACHE_AUX_FILEOBJS 0 57#define AUX_FILEOBJS 2
63#endif 58#endif
64 59
65#define AUX_FILEOBJS (2+DIRCACHE_AUX_FILEOBJS+MOUNT_AUX_FILEOBJS)
66
67/* number of components statically allocated to handle the vast majority 60/* number of components statically allocated to handle the vast majority
68 of path depths; should maybe be tuned for >= 90th percentile but for now, 61 of path depths; should maybe be tuned for >= 90th percentile but for now,
69 imma just guessing based on something like: 62 imma just guessing based on something like:
diff --git a/firmware/include/rb_namespace.h b/firmware/include/rb_namespace.h
deleted file mode 100644
index 4d7a125c7b..0000000000
--- a/firmware/include/rb_namespace.h
+++ /dev/null
@@ -1,79 +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#ifndef RB_NAMESPACE_H
22#define RB_NAMESPACE_H
23
24#include "file_internal.h"
25
26enum ns_item_flags
27{
28 NSITEM_MOUNTED = 0x01, /* item is mounted */
29 NSITEM_HIDDEN = 0x02, /* item is not enumerated */
30 NSITEM_CONTENTS = 0x04, /* contents enumerate */
31};
32
33struct ns_scan_info
34{
35 struct dirscan_info scan; /* dirscan info - first! */
36 int item; /* current item in parent */
37};
38
39/* root functions */
40int root_mount_path(const char *path, unsigned int flags);
41void root_unmount_volume(IF_MV_NONVOID(int volume));
42int root_readdir_dirent(struct filestr_base *stream,
43 struct ns_scan_info *scanp,
44 struct dirent *entry);
45
46/* namespace functions */
47int ns_parse_root(const char *path, const char **pathp, uint16_t *lenp);
48int ns_open_root(IF_MV(int volume,) unsigned int *callflagsp,
49 struct file_base_info *infop, uint16_t *attrp);
50int ns_open_stream(const char *path, unsigned int callflags,
51 struct filestr_base *stream, struct ns_scan_info *scanp);
52
53/* closes the namespace stream */
54static inline int ns_close_stream(struct filestr_base *stream)
55{
56 return close_stream_internal(stream);
57}
58
59#include "dircache_redirect.h"
60
61static inline void ns_dirscan_rewind(struct ns_scan_info *scanp)
62{
63 rewinddir_dirent(&scanp->scan);
64 if (scanp->item != -1)
65 scanp->item = 0;
66}
67
68static inline int ns_readdir_dirent(struct filestr_base *stream,
69 struct ns_scan_info *scanp,
70 struct dirent *entry)
71
72{
73 if (scanp->item == -1)
74 return readdir_dirent(stream, &scanp->scan, entry);
75 else
76 return root_readdir_dirent(stream, scanp, entry);
77}
78
79#endif /* RB_NAMESPACE_H */
diff --git a/uisimulator/common/filesystem-sim.c b/uisimulator/common/filesystem-sim.c
index 45483b7172..766beb3fda 100644
--- a/uisimulator/common/filesystem-sim.c
+++ b/uisimulator/common/filesystem-sim.c
@@ -309,8 +309,6 @@ int sim_get_os_path(char *buffer, const char *path, size_t bufsize)
309 309
310 const char *next; 310 const char *next;
311 volume = path_strip_volume(p, &next, true); 311 volume = path_strip_volume(p, &next, true);
312 if (volume == ROOT_VOLUME)
313 volume = 0; /* FIXME: root no longer implies volume 0 */
314 312
315 if (next > p) 313 if (next > p)
316 { 314 {