diff --git a/applications/main/archive/archive.c b/applications/main/archive/archive.c index 4121af77b..1b46548f7 100644 --- a/applications/main/archive/archive.c +++ b/applications/main/archive/archive.c @@ -77,6 +77,13 @@ void archive_free(ArchiveApp* archive) { archive->thread = NULL; } + if(archive->browser->disk_image) { + storage_virtual_quit(furi_record_open(RECORD_STORAGE)); + furi_record_close(RECORD_STORAGE); + storage_file_free(archive->browser->disk_image); + archive->browser->disk_image = NULL; + } + // Loading loading_free(archive->loading); diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index e0bfa96b9..6bf479ea3 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -19,7 +19,8 @@ static void browser->is_root = is_root; ArchiveTabEnum tab = archive_get_tab(browser); - if((item_cnt == 0) && (archive_is_home(browser)) && (tab != ArchiveTabBrowser)) { + if((item_cnt == 0) && (archive_is_home(browser)) && (tab != ArchiveTabBrowser) && + (tab != ArchiveTabDiskImage || !browser->disk_image)) { archive_switch_tab(browser, browser->last_tab_switch_dir); } else if(!furi_string_start_with_str(browser->path, "/app:")) { with_view_model( @@ -512,7 +513,8 @@ void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) { static bool archive_is_dir_exists(FuriString* path) { if(furi_string_equal(path, STORAGE_INT_PATH_PREFIX) || - furi_string_equal(path, STORAGE_EXT_PATH_PREFIX)) { + furi_string_equal(path, STORAGE_EXT_PATH_PREFIX) || + furi_string_equal(path, STORAGE_MNT_PATH_PREFIX)) { return true; } bool state = false; @@ -592,7 +594,8 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { } } - if(tab_empty && tab != ArchiveTabBrowser && tab != ArchiveTabInternal) { + if(tab_empty && tab != ArchiveTabBrowser && tab != ArchiveTabInternal && + (tab != ArchiveTabDiskImage || !browser->disk_image)) { archive_switch_tab(browser, key); } else { with_view_model( diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index f67781889..232ca5c60 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -18,6 +18,7 @@ static const char* tab_default_paths[] = { [ArchiveTabU2f] = "/app:u2f", [ArchiveTabApplications] = EXT_PATH("apps"), [ArchiveTabSearch] = "/app:search", + [ArchiveTabDiskImage] = STORAGE_MNT_PATH_PREFIX, [ArchiveTabInternal] = STORAGE_INT_PATH_PREFIX, [ArchiveTabBrowser] = STORAGE_EXT_PATH_PREFIX, }; @@ -54,6 +55,7 @@ static const ArchiveFileTypeEnum known_type[] = { [ArchiveTabU2f] = ArchiveFileTypeU2f, [ArchiveTabApplications] = ArchiveFileTypeAppOrJs, [ArchiveTabSearch] = ArchiveFileTypeSearch, + [ArchiveTabDiskImage] = ArchiveFileTypeUnknown, [ArchiveTabInternal] = ArchiveFileTypeUnknown, [ArchiveTabBrowser] = ArchiveFileTypeUnknown, }; diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index b7f077d66..0bfde1d9d 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -81,6 +81,50 @@ static void archive_show_file(Loader* loader, const char* path) { } } +static void archive_mount_disk_image(ArchiveBrowserView* browser, ArchiveFile_t* selected) { + Storage* storage = furi_record_open(RECORD_STORAGE); + File* disk_image = NULL; + do { + if(browser->disk_image) { + // Deinit and recycle File object + if(storage_virtual_quit(storage) != FSE_OK) break; + storage_file_close(browser->disk_image); + disk_image = browser->disk_image; + browser->disk_image = NULL; + } else { + disk_image = storage_file_alloc(storage); + } + + if(!storage_file_open( + disk_image, + furi_string_get_cstr(selected->path), + FSAM_READ | FSAM_WRITE, + FSOM_OPEN_EXISTING)) + break; + + FS_Error init = storage_virtual_init(storage, disk_image); + if(init == FSE_ALREADY_OPEN) { + if(storage_virtual_quit(storage) == FSE_OK) { + init = storage_virtual_init(storage, disk_image); + } + } + if(init != FSE_OK) break; + + if(storage_virtual_mount(storage) != FSE_OK) { + storage_virtual_quit(storage); + break; + } + + browser->disk_image = disk_image; + + while(archive_get_tab(browser) != ArchiveTabDiskImage) { + archive_switch_tab(browser, TAB_LEFT); + } + } while(0); + if(disk_image && !browser->disk_image) storage_file_free(disk_image); + furi_record_close(RECORD_STORAGE); +} + static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected, bool favorites) { Loader* loader = furi_record_open(RECORD_LOADER); @@ -226,9 +270,14 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case ArchiveBrowserEventFileMenuShow: - archive_show_file( - furi_record_open(RECORD_LOADER), furi_string_get_cstr(selected->path)); - furi_record_close(RECORD_LOADER); + if(selected->type == ArchiveFileTypeDiskImage && + archive_get_tab(browser) != ArchiveTabDiskImage) { + archive_mount_disk_image(browser, selected); + } else { + archive_show_file( + furi_record_open(RECORD_LOADER), furi_string_get_cstr(selected->path)); + furi_record_close(RECORD_LOADER); + } archive_show_file_menu(browser, false, false); consumed = true; break; diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index b896e662d..57eb8310d 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -19,6 +19,7 @@ static const char* ArchiveTabNames[] = { [ArchiveTabU2f] = "U2F", [ArchiveTabApplications] = "Apps", [ArchiveTabSearch] = "Search", + [ArchiveTabDiskImage] = "Disk Image", [ArchiveTabInternal] = "Internal", [ArchiveTabBrowser] = "Browser", }; @@ -119,7 +120,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { if(selected->type != ArchiveFileTypeFolder) { archive_menu_add_item( menu_array_push_raw(model->context_menu), - "Show", + selected->type == ArchiveFileTypeDiskImage ? "Mount" : "Show", ArchiveBrowserEventFileMenuShow); } } @@ -209,7 +210,8 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) { model->files, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0)); file_type = file->type; bool ext = model->tab_idx == ArchiveTabBrowser || - model->tab_idx == ArchiveTabInternal || model->tab_idx == ArchiveTabSearch; + model->tab_idx == ArchiveTabInternal || + model->tab_idx == ArchiveTabDiskImage || model->tab_idx == ArchiveTabSearch; if(file_type == ArchiveFileTypeApplication) { if(file->custom_icon_data) { custom_icon_data = file->custom_icon_data; diff --git a/applications/main/archive/views/archive_browser_view.h b/applications/main/archive/views/archive_browser_view.h index 2cfa65145..7a6163f4d 100644 --- a/applications/main/archive/views/archive_browser_view.h +++ b/applications/main/archive/views/archive_browser_view.h @@ -31,6 +31,7 @@ typedef enum { ArchiveTabU2f, ArchiveTabApplications, ArchiveTabSearch, + ArchiveTabDiskImage, ArchiveTabInternal, ArchiveTabBrowser, ArchiveTabTotal, @@ -90,6 +91,7 @@ struct ArchiveBrowserView { InputKey last_tab_switch_dir; bool is_root; FuriTimer* scroll_timer; + File* disk_image; }; typedef struct {