Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FL-2633] Move files from /int to /ext on SD mount #1384

Merged
merged 2 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
)

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,
};
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