diff --git a/apps/filetree.c b/apps/filetree.c index eb429c83e3..4f59804686 100644 --- a/apps/filetree.c +++ b/apps/filetree.c @@ -46,6 +46,10 @@ #include "strnatcmp.h" #include "keyboard.h" +#ifdef HAVE_MULTIVOLUME +#include "mv.h" +#endif + #if CONFIG_TUNER #include "radio.h" #endif @@ -471,6 +475,45 @@ static void ft_apply_skin_file(char *buf, char *file, const int maxlen) settings_apply_skins(); } +int ft_assemble_path(char *buf, size_t bufsz, const char* currdir, const char* filename) +{ + int len; + if (!filename) + filename = ""; +#ifdef HAVE_MULTIVOLUME + if (currdir && currdir[0] && currdir[1]) /* Not in / */ + { + if (currdir[1] != VOL_START_TOK) + { + len = snprintf(buf, bufsz, "%s%s/%s", root_realpath(), currdir, filename); + } + else + len = snprintf(buf, bufsz, "%s/%s", currdir, filename); + } + else /* In / */ + { + if (filename[0] != VOL_START_TOK) + { + len = snprintf(buf, bufsz, "%s/%s",root_realpath(), filename); + } + else + len = snprintf(buf, bufsz, "/%s", filename); + } +#else + if (currdir && currdir[0] && currdir[1]) /* Not in / */ + { + len = snprintf(buf, bufsz, "%s%s/%s", root_realpath(), currdir, filename); + } + else /* In / */ + { + len = snprintf(buf, bufsz, "%s/%s",root_realpath(), filename); + } +#endif + if ((unsigned) len > bufsz) + splash(HZ, ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); + return len; +} + int ft_enter(struct tree_context* c) { int rc = GO_TO_PREVIOUS; @@ -484,16 +527,7 @@ int ft_enter(struct tree_context* c) } int file_attr = file->attr; - int len; - - if (c->currdir[1]) - { - len = snprintf(buf,sizeof(buf),"%s/%s",c->currdir, file->name); - if ((unsigned) len > sizeof(buf)) - splash(HZ, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); - } - else - snprintf(buf,sizeof(buf),"/%s",file->name); + ft_assemble_path(buf, sizeof(buf), c->currdir, file->name); if (file_attr & ATTR_DIRECTORY) { memcpy(c->currdir, buf, sizeof(c->currdir)); @@ -537,22 +571,27 @@ int ft_enter(struct tree_context* c) PLAYLIST_INSERT_LAST, true, true); splash(HZ, ID2P(LANG_QUEUE_LAST)); } - else if (playlist_create(c->currdir, NULL) != -1) + else { - start_index = ft_build_playlist(c, c->selected_item); - if (global_settings.playlist_shuffle) + /* use the assembled path sans filename */ + char * fp = strrchr(buf, PATH_SEPCH); + if (fp) + *fp = '\0'; + if (playlist_create(buf, NULL) != -1) { - start_index = playlist_shuffle(seed, start_index); - - /* when shuffling dir.: play all files - even if the file selected by user is - not the first one */ - if (!global_settings.play_selected) - start_index = 0; + start_index = ft_build_playlist(c, c->selected_item); + if (global_settings.playlist_shuffle) + { + start_index = playlist_shuffle(seed, start_index); + /* when shuffling dir.: play all files + even if the file selected by user is + not the first one */ + if (!global_settings.play_selected) + start_index = 0; + } + playlist_start(start_index, 0, 0); + play = true; } - - playlist_start(start_index, 0, 0); - play = true; } break; } diff --git a/apps/filetree.h b/apps/filetree.h index 7931c3c454..3ec7846d2c 100644 --- a/apps/filetree.h +++ b/apps/filetree.h @@ -25,6 +25,8 @@ int ft_load(struct tree_context* c, const char* tempdir); int ft_enter(struct tree_context* c); int ft_exit(struct tree_context* c); +int ft_assemble_path(char *buf, size_t bufsz, + const char* currdir, const char* filename); int ft_build_playlist(struct tree_context* c, int start_index); bool ft_play_playlist(char* pathname, char* dirname, char* filename, bool skip_warn_and_bookmarks); diff --git a/apps/tagcache.c b/apps/tagcache.c index 40f9c28c33..c8900f5c38 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -4990,10 +4990,56 @@ void do_tagcache_build(const char *path[]) roots_ll[0].path = path[0]; roots_ll[0].next = NULL; + +#if defined HAVE_MULTIVOLUME && !defined(SIMULATOR) && !defined(__PCTOOL__) + extern bool ns_volume_is_visible(int volume); /*rb_namespace.c*/ + /* i is for the path vector, j for the roots_ll array */ + int i = 1, j = 1; + bool added = false; + char volnamebuf[NUM_VOLUMES][VOL_MAX_LEN + 1]; + /* we can just parse the root directory ('/') and get to any mounted + * volume but we can also enumerate a volume in the root directory + * when this occurs it leads to multiple entries since the files can + * be reached through multiple paths ex, /Foo could also be /SD1/Foo + * we used to hide the volume that was mapped but then when you switch + * from the sd to the internal the paths don't map to the right volume + * instead we will attempt to rewrite the root with any non-hidden volumes + * failing that just leave the paths alone */ + if (!strcmp(PATH_ROOTSTR, path[0])) + { + i = 0; + j = 0; + } + /* path can be skipped , but root_ll entries can't */ + for(; path[i] && j < MAX_STATIC_ROOTS; i++) + { + /* check if the link target is inside of an existing search root + * don't add if target is inside, we'll scan it later */ + if (!added && !strcmp(PATH_ROOTSTR, path[i])) + { + for (int v = 0; v < NUM_VOLUMES; v++) + { + if (ns_volume_is_visible(v)) + { + make_volume_root(v, volnamebuf[v]); + roots_ll[j].path = volnamebuf[v]; + if (j > 0) + roots_ll[j-1].next = &roots_ll[j]; + j++; + added = true; + } + } + if(!added) + j = 1; + added = true; + continue; + } +#else /* i is for the path vector, j for the roots_ll array * path can be skipped , but root_ll entries can't */ for(int i = 1, j = 1; path[i] && j < MAX_STATIC_ROOTS; i++) { +#endif /*def HAVE_MULTIVOLUME*/ if (search_root_exists(path[i])) /* skip this path */ continue; @@ -5006,6 +5052,7 @@ void do_tagcache_build(const char *path[]) /* check_dir might add new roots */ for(this = &roots_ll[0]; this; this = this->next) { + logf("Search root %s", this->path); strmemccpy(curpath, this->path, sizeof(curpath)); ret = ret && check_dir(this->path, true); } diff --git a/apps/tree.c b/apps/tree.c index 7563c1ef6e..ea2ef23e71 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -646,7 +646,6 @@ static int dirbrowse(void) { int numentries=0; char buf[MAX_PATH]; - int len; int button; int oldbutton; bool reload_root = false; @@ -857,16 +856,8 @@ static int dirbrowse(void) attr = entry->attr; - if (currdir[1]) /* Not in / */ - { - len = snprintf(buf, sizeof buf, "%s/%s", - currdir, entry->name); + ft_assemble_path(buf, sizeof(buf), currdir, entry->name); - if ((unsigned) len > sizeof(buf)) - splash(HZ, ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); - } - else /* In / */ - snprintf(buf, sizeof buf, "/%s", entry->name); } onplay_result = onplay(buf, attr, curr_context, hotkey); } diff --git a/firmware/common/dir.c b/firmware/common/dir.c index 45749b8474..9a78d910a7 100644 --- a/firmware/common/dir.c +++ b/firmware/common/dir.c @@ -344,3 +344,9 @@ struct dirinfo dir_get_info(DIR *dirp, struct dirent *entry) file_error: return (struct dirinfo){ .attribute = 0 }; } + +const char* root_realpath(void) +{ + /* Native only, for APP and SIM see respective filesystem-.c files */ + return root_get_realpath(); /* rb_namespace.c */ +} diff --git a/firmware/common/rb_namespace.c b/firmware/common/rb_namespace.c index ff5ad0f6db..52b2205f40 100644 --- a/firmware/common/rb_namespace.c +++ b/firmware/common/rb_namespace.c @@ -23,6 +23,7 @@ #include "fileobj_mgr.h" #include "rb_namespace.h" #include "file_internal.h" +#include /*snprintf*/ /* Define LOGF_ENABLE to enable logf output in this file */ //#define LOGF_ENABLE @@ -82,39 +83,48 @@ static void unmount_item(int item) set_root_item_state(item, 0); } +static char *root_realpath_internal(void) +{ + static char root_realpath[ROOT_MAX_REALPATH]; + return root_realpath; +} +const char* root_get_realpath(void) +{ + return root_realpath_internal(); +} + /* mount the directory that enumerates into the root namespace */ int root_mount_path(const char *path, unsigned int flags) { + const char *folder = NULL; /* is a folder enumerated in the root? */ #ifdef HAVE_MULTIVOLUME - int volume = path_strip_volume(path, NULL, false); + int volume = path_strip_volume(path, &folder, false); if (volume == ROOT_VOLUME) return -EINVAL; - if (!CHECK_VOL(volume)) return -ENOENT; + char volname[VOL_MAX_LEN+2]; + make_volume_root(volume, volname); #else + const char volname = PATH_ROOTSTR; if (!path_is_absolute(path)) { logf("Path not absolute %s", path); return -ENOENT; } + path_dirname(path, &folder); #endif /* HAVE_MULTIVOLUME */ - bool contents = flags & NSITEM_CONTENTS; - int item = contents ? ROOT_CONTENTS_INDEX : IF_MV_VOL(volume); + int item = IF_MV_VOL(volume); unsigned int state = get_root_item_state(item); - logf("%s: item:%d, st:%u, %s", __func__, item, state, path); - - if (state) - return -EBUSY; - - if (contents) + if (contents && state) /* volume must be mounted to enumerate into the root namespace */ { + if (get_root_item_state(ROOT_CONTENTS_INDEX)) + return -EBUSY; /* error something is already enumerated */ /* cache information about the target */ struct filestr_base stream; struct path_component_info compinfo; - int e = errno; int rc = open_stream_internal(path, FF_DIR | FF_PROBE | FF_INFO | FF_DEVPATH, &stream, &compinfo); @@ -124,17 +134,41 @@ int root_mount_path(const char *path, unsigned int flags) errno = e; return rc; } - if (!fileobj_mount(&compinfo.info, FO_DIRECTORY, &root_bindp)) return -EBUSY; - } + int root_state = NSITEM_MOUNTED | (flags & (NSITEM_HIDDEN|NSITEM_CONTENTS)); + set_root_item_state(ROOT_CONTENTS_INDEX, root_state); + flags |= state; /* preserve the state of the mounted volume */ + if (!folder) + { + folder = ""; + } + else + { + /*if a folder has been enumerated don't mark the whole volume */ + if (folder[0] != '\0' && folder[1] != '\0') + flags &= ~NSITEM_CONTENTS; + } + snprintf(root_realpath_internal(), ROOT_MAX_REALPATH,"%s%s", volname, folder); + } + else if (state) /* error volume already mounted */ + return -EBUSY; state = NSITEM_MOUNTED | (flags & (NSITEM_HIDDEN|NSITEM_CONTENTS)); set_root_item_state(item, state); - return 0; } +/* check if volume in path is mounted in the root namespace */ +bool ns_volume_is_visible(IF_MV_NONVOID(int volume)) +{ + int item = IF_MV_VOL(volume); + if ((item == ROOT_VOLUME) || !CHECK_VOL(item)) + return false; + unsigned int state = get_root_item_state(item); + return state && (((state & NSITEM_HIDDEN) == 0) || (state & NSITEM_CONTENTS)); +} + /* inform root that an entire volume is being unmounted */ void root_unmount_volume(IF_MV_NONVOID(int volume)) { @@ -154,7 +188,10 @@ void root_unmount_volume(IF_MV_NONVOID(int volume)) uint32_t state = get_root_item_state(ROOT_CONTENTS_INDEX); if (state && (volume < 0 || BASEINFO_VOL(&root_bindp->info) == volume)) #endif + { unmount_item(ROOT_CONTENTS_INDEX); + root_realpath_internal()[0] = '\0'; + } } /* parse the root part of a path */ @@ -268,8 +305,13 @@ int root_readdir_dirent(struct filestr_base *stream, state = get_root_item_state(item); if ((state & (NSITEM_MOUNTED|NSITEM_HIDDEN)) == NSITEM_MOUNTED) { - logf("Found mounted item: %d %s", item, entry->d_name); - break; +#if 1 /* hide the volume enumerated into the root namespace */ + if (item == ROOT_CONTENTS_INDEX || (state & NSITEM_CONTENTS) == 0) + { + logf("Found mounted item: %d %s", item, entry->d_name); + break; + } +#endif } item++; diff --git a/firmware/include/dir.h b/firmware/include/dir.h index 2f78b11cf5..4599877ede 100644 --- a/firmware/include/dir.h +++ b/firmware/include/dir.h @@ -63,6 +63,9 @@ #ifndef dir_exists #define dir_exists FS_PREFIX(dir_exists) #endif +#ifndef root_realpath +#define root_realpath FS_PREFIX(root_realpath) +#endif #endif /* !DIRFUNCTIONS_DEFINED */ #ifndef DIRENT_DEFINED @@ -83,6 +86,9 @@ struct dirinfo #ifndef DIRFUNCTIONS_DECLARED /* TIP: set errno to zero before calling to see if anything failed */ struct dirinfo dir_get_info(DIR *dirp, struct DIRENT *entry); +const char* root_realpath(void); #endif /* !DIRFUNCTIONS_DECLARED */ + + #endif /* _DIR_H_ */ diff --git a/firmware/include/dircache_redirect.h b/firmware/include/dircache_redirect.h index f51ce70690..36f68b7251 100644 --- a/firmware/include/dircache_redirect.h +++ b/firmware/include/dircache_redirect.h @@ -139,8 +139,10 @@ static inline void fileop_onsync_internal(struct filestr_base *stream) static inline void volume_onmount_internal(IF_MV_NONVOID(int volume)) { -#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER) +#if (defined(HAVE_MULTIVOLUME) || (defined(HAVE_MULTIBOOT) && !defined(BOOTLOADER))) char path[VOL_MAX_LEN+2]; +#endif +#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER) char rtpath[MAX_PATH / 2]; make_volume_root(volume, path); @@ -183,7 +185,6 @@ standard_redirect: root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS); } #elif defined(HAVE_MULTIVOLUME) - char path[VOL_MAX_LEN+2]; make_volume_root(volume, path); root_mount_path(path, RB_ROOT_VOL_HIDDEN(volume) ? NSITEM_HIDDEN : 0); if (volume == path_strip_volume(RB_ROOT_CONTENTS_DIR, NULL, false)) diff --git a/firmware/include/rb_namespace.h b/firmware/include/rb_namespace.h index 7bc711b5a6..5cd8c2dd29 100644 --- a/firmware/include/rb_namespace.h +++ b/firmware/include/rb_namespace.h @@ -37,6 +37,8 @@ struct ns_scan_info }; /* root functions */ +#define ROOT_MAX_REALPATH 80 +const char* root_get_realpath(void); int root_mount_path(const char *path, unsigned int flags); void root_unmount_volume(IF_MV_NONVOID(int volume)); int root_readdir_dirent(struct filestr_base *stream, @@ -49,6 +51,7 @@ int ns_open_root(IF_MV(int volume,) unsigned int *callflagsp, struct file_base_info *infop, uint16_t *attrp); int ns_open_stream(const char *path, unsigned int callflags, struct filestr_base *stream, struct ns_scan_info *scanp); +bool ns_volume_is_visible(IF_MV_NONVOID(int volume)); /* closes the namespace stream */ static inline int ns_close_stream(struct filestr_base *stream) diff --git a/firmware/target/hosted/filesystem-app.c b/firmware/target/hosted/filesystem-app.c index cfe4e65fe9..09b3365a9e 100644 --- a/firmware/target/hosted/filesystem-app.c +++ b/firmware/target/hosted/filesystem-app.c @@ -600,3 +600,8 @@ int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize) return 0; } + +const char* app_root_realpath(void) +{ + return PATH_ROOTSTR; +} diff --git a/uisimulator/common/filesystem-sim.c b/uisimulator/common/filesystem-sim.c index 0a5df0c742..f4f6321b7d 100644 --- a/uisimulator/common/filesystem-sim.c +++ b/uisimulator/common/filesystem-sim.c @@ -843,3 +843,8 @@ int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize) return sim_get_os_path(buffer, tmpbuf, bufsize); } + +const char* sim_root_realpath(void) +{ + return PATH_ROOTSTR; +}