Skip to content

Commit

Permalink
[FL-2633] Move files from /int to /ext on SD mount #1384
Browse files Browse the repository at this point in the history
Co-authored-by: あく <[email protected]>
  • Loading branch information
nminaylov and skotopes authored Jul 14, 2022
1 parent fd498bd commit 2caa5c3
Show file tree
Hide file tree
Showing 11 changed files with 545 additions and 0 deletions.
8 changes: 8 additions & 0 deletions applications/storage/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,14 @@ FS_Error storage_common_rename(Storage* storage, const char* old_path, const cha
*/
FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* new_path);

/** Copy one folder contents into another with rename of all conflicting files
* @param app pointer to the api
* @param old_path old path
* @param new_path new path
* @return FS_Error operation result
*/
FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path);

/** Creates a directory
* @param app pointer to the api
* @param path directory path
Expand Down
128 changes: 128 additions & 0 deletions applications/storage/storage_external_api.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#include "furi/log.h"
#include <furi/record.h>
#include <m-string.h>
#include "storage.h"
#include "storage_i.h"
#include "storage_message.h"
#include <toolbox/stream/file_stream.h>
#include <toolbox/dir_walk.h>
#include "toolbox/path.h"

#define MAX_NAME_LENGTH 256
#define MAX_EXT_LEN 16

#define TAG "StorageAPI"

Expand Down Expand Up @@ -436,6 +439,131 @@ FS_Error storage_common_copy(Storage* storage, const char* old_path, const char*
return error;
}

static FS_Error
storage_merge_recursive(Storage* storage, const char* old_path, const char* new_path) {
FS_Error error = storage_common_mkdir(storage, new_path);
DirWalk* dir_walk = dir_walk_alloc(storage);
string_t path;
string_t tmp_new_path;
string_t tmp_old_path;
FileInfo fileinfo;
string_init(path);
string_init(tmp_new_path);
string_init(tmp_old_path);

do {
if((error != FSE_OK) && (error != FSE_EXIST)) break;

if(!dir_walk_open(dir_walk, old_path)) {
error = dir_walk_get_error(dir_walk);
break;
}

while(1) {
DirWalkResult res = dir_walk_read(dir_walk, path, &fileinfo);

if(res == DirWalkError) {
error = dir_walk_get_error(dir_walk);
break;
} else if(res == DirWalkLast) {
break;
} else {
string_set(tmp_old_path, path);
string_right(path, strlen(old_path));
string_printf(tmp_new_path, "%s%s", new_path, string_get_cstr(path));

if(fileinfo.flags & FSF_DIRECTORY) {
if(storage_common_stat(storage, string_get_cstr(tmp_new_path), &fileinfo) ==
FSE_OK) {
if(fileinfo.flags & FSF_DIRECTORY) {
error = storage_common_mkdir(storage, string_get_cstr(tmp_new_path));
}
}
} else {
error = storage_common_merge(
storage, string_get_cstr(tmp_old_path), string_get_cstr(tmp_new_path));
}

if(error != FSE_OK) break;
}
}

} while(false);

string_clear(tmp_new_path);
string_clear(tmp_old_path);
string_clear(path);
dir_walk_free(dir_walk);
return error;
}

FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path) {
FS_Error error;
const char* new_path_tmp;
string_t new_path_next;
string_init(new_path_next);

FileInfo fileinfo;
error = storage_common_stat(storage, old_path, &fileinfo);

if(error == FSE_OK) {
if(fileinfo.flags & FSF_DIRECTORY) {
error = storage_merge_recursive(storage, old_path, new_path);
} else {
error = storage_common_stat(storage, new_path, &fileinfo);
if(error == FSE_OK) {
string_set_str(new_path_next, new_path);
string_t dir_path;
string_t filename;
char extension[MAX_EXT_LEN];

string_init(dir_path);
string_init(filename);

path_extract_filename(new_path_next, filename, true);
path_extract_dirname(new_path, dir_path);
path_extract_extension(new_path_next, extension, MAX_EXT_LEN);

storage_get_next_filename(
storage,
string_get_cstr(dir_path),
string_get_cstr(filename),
extension,
new_path_next,
255);
string_cat_printf(dir_path, "/%s%s", string_get_cstr(new_path_next), extension);
string_set(new_path_next, dir_path);

string_clear(dir_path);
string_clear(filename);
new_path_tmp = string_get_cstr(new_path_next);
} else {
new_path_tmp = new_path;
}
Stream* stream_from = file_stream_alloc(storage);
Stream* stream_to = file_stream_alloc(storage);

do {
if(!file_stream_open(stream_from, old_path, FSAM_READ, FSOM_OPEN_EXISTING)) break;
if(!file_stream_open(stream_to, new_path_tmp, FSAM_WRITE, FSOM_CREATE_NEW)) break;
stream_copy_full(stream_from, stream_to);
} while(false);

error = file_stream_get_error(stream_from);
if(error == FSE_OK) {
error = file_stream_get_error(stream_to);
}

stream_free(stream_from);
stream_free(stream_to);
}
}

string_clear(new_path_next);

return error;
}

FS_Error storage_common_mkdir(Storage* storage, const char* path) {
S_API_PROLOGUE;
S_API_DATA_PATH;
Expand Down
19 changes: 19 additions & 0 deletions applications/storage_move_to_sd/application.fam
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
App(
appid="storage_move_to_sd",
name="StorageMoveToSd",
apptype=FlipperAppType.SYSTEM,
entry_point="storage_move_to_sd_app",
requires=["gui","storage"],
provides=["storage_move_to_sd_start"],
stack_size=2 * 1024,
order=30,
)

App(
appid="storage_move_to_sd_start",
apptype=FlipperAppType.STARTUP,
entry_point="storage_move_to_sd_start",
requires=["storage"],
order=120,
)

30 changes: 30 additions & 0 deletions applications/storage_move_to_sd/scenes/storage_move_to_sd_scene.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "storage_move_to_sd_scene.h"

// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const storage_move_to_sd_on_enter_handlers[])(void*) = {
#include "storage_move_to_sd_scene_config.h"
};
#undef ADD_SCENE

// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const storage_move_to_sd_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "storage_move_to_sd_scene_config.h"
};
#undef ADD_SCENE

// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const storage_move_to_sd_on_exit_handlers[])(void* context) = {
#include "storage_move_to_sd_scene_config.h"
};
#undef ADD_SCENE

// Initialize scene handlers configuration structure
const SceneManagerHandlers storage_move_to_sd_scene_handlers = {
.on_enter_handlers = storage_move_to_sd_on_enter_handlers,
.on_event_handlers = storage_move_to_sd_on_event_handlers,
.on_exit_handlers = storage_move_to_sd_on_exit_handlers,
.scene_num = StorageMoveToSdSceneNum,
};
29 changes: 29 additions & 0 deletions applications/storage_move_to_sd/scenes/storage_move_to_sd_scene.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <gui/scene_manager.h>

// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) StorageMoveToSd##id,
typedef enum {
#include "storage_move_to_sd_scene_config.h"
StorageMoveToSdSceneNum,
} StorageMoveToSdScene;
#undef ADD_SCENE

extern const SceneManagerHandlers storage_move_to_sd_scene_handlers;

// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "storage_move_to_sd_scene_config.h"
#undef ADD_SCENE

// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "storage_move_to_sd_scene_config.h"
#undef ADD_SCENE

// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "storage_move_to_sd_scene_config.h"
#undef ADD_SCENE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ADD_SCENE(storage_move_to_sd, confirm, Confirm)
ADD_SCENE(storage_move_to_sd, progress, Progress)
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include "../storage_move_to_sd.h"
#include "gui/canvas.h"
#include "gui/modules/widget_elements/widget_element_i.h"
#include "storage/storage.h"

static void storage_move_to_sd_scene_confirm_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
StorageMoveToSd* app = context;
furi_assert(app);
if(type == InputTypeShort) {
if(result == GuiButtonTypeRight) {
view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventConfirm);
} else if(result == GuiButtonTypeLeft) {
view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit);
}
}
}

void storage_move_to_sd_scene_confirm_on_enter(void* context) {
StorageMoveToSd* app = context;

widget_add_button_element(
app->widget,
GuiButtonTypeLeft,
"Cancel",
storage_move_to_sd_scene_confirm_widget_callback,
app);
widget_add_button_element(
app->widget,
GuiButtonTypeRight,
"Confirm",
storage_move_to_sd_scene_confirm_widget_callback,
app);

widget_add_string_element(
app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "SD card inserted");
widget_add_string_multiline_element(
app->widget,
64,
32,
AlignCenter,
AlignCenter,
FontSecondary,
"Move data from\ninternal storage to SD card?");

view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget);
}

bool storage_move_to_sd_scene_confirm_on_event(void* context, SceneManagerEvent event) {
StorageMoveToSd* app = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
if(event.event == MoveToSdCustomEventConfirm) {
scene_manager_next_scene(app->scene_manager, StorageMoveToSdProgress);
consumed = true;
} else if(event.event == MoveToSdCustomEventExit) {
view_dispatcher_stop(app->view_dispatcher);
}
}

return consumed;
}

void storage_move_to_sd_scene_confirm_on_exit(void* context) {
StorageMoveToSd* app = context;
widget_reset(app->widget);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "../storage_move_to_sd.h"
#include "cmsis_os2.h"

void storage_move_to_sd_scene_progress_on_enter(void* context) {
StorageMoveToSd* app = context;

widget_add_string_element(
app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "Moving...");

view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget);

storage_move_to_sd_perform();
view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit);
}

bool storage_move_to_sd_scene_progress_on_event(void* context, SceneManagerEvent event) {
StorageMoveToSd* app = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
view_dispatcher_stop(app->view_dispatcher);
} else if(event.type == SceneManagerEventTypeBack) {
consumed = true;
}

return consumed;
}

void storage_move_to_sd_scene_progress_on_exit(void* context) {
StorageMoveToSd* app = context;
widget_reset(app->widget);
}
Loading

0 comments on commit 2caa5c3

Please sign in to comment.