Merge and improve new storage rename/move

This commit is contained in:
Willy-JL
2023-11-16 02:40:36 +00:00
parent a4d01d5d88
commit 09c6cf168e
2 changed files with 127 additions and 87 deletions

View File

@@ -470,91 +470,125 @@ FS_Error storage_common_remove(Storage* storage, const char* path) {
return S_RETURN_ERROR;
}
bool storage_is_subdir(const char* a, const char* b) {
size_t len = strlen(b) + 2;
char test[len];
strncpy(test, b, len);
if(test[len - 3] != '/') {
test[len - 2] = '/';
test[len - 1] = '\0';
}
return strncmp(a, test, len - 1) == 0;
}
FS_Error storage_common_rename(Storage* storage, const char* old_path, const char* new_path) {
if(!storage_common_exists(storage, old_path)) {
return FSE_NOT_EXIST;
}
FS_Error error;
if(storage_is_subdir(new_path, old_path)) {
return FSE_INVALID_NAME;
}
do {
if(!storage_common_exists(storage, old_path)) {
error = FSE_NOT_EXIST;
break;
}
S_API_PROLOGUE;
SAData data = {
.rename = {
.old = old_path,
.new = new_path,
.thread_id = furi_thread_get_current_id(),
}};
if(storage_common_exists(storage, new_path)) {
error = FSE_EXIST;
break;
}
S_API_MESSAGE(StorageCommandCommonRename);
S_API_EPILOGUE;
FS_Error ret = S_RETURN_ERROR;
if(storage_dir_exists(storage, old_path)) {
// Cannot rename a directory to itself or to a nested directory
if(storage_common_equivalent_path(storage, old_path, new_path, true)) {
error = FSE_INVALID_NAME;
break;
}
// Renaming a regular file to itself does nothing and always succeeds
} else if(storage_common_equivalent_path(storage, old_path, new_path, false)) {
error = FSE_OK;
break;
}
S_API_PROLOGUE;
SAData data = {
.rename = {
.old = old_path,
.new = new_path,
.thread_id = furi_thread_get_current_id(),
}};
S_API_MESSAGE(StorageCommandCommonRename);
S_API_EPILOGUE;
error = S_RETURN_ERROR;
if(error == FSE_NOT_IMPLEMENTED) {
// Different filesystems, use copy + remove
error = storage_common_copy(storage, old_path, new_path);
if(error != FSE_OK) {
break;
}
if(ret == FSE_NOT_IMPLEMENTED) {
// Different filesystems, use copy + remove
ret = storage_common_copy(storage, old_path, new_path);
if(ret == FSE_OK) {
if(!storage_simply_remove_recursive(storage, old_path)) {
ret = FSE_INTERNAL;
error = FSE_INTERNAL;
}
}
}
return ret;
} while(false);
return error;
}
FS_Error storage_common_move(Storage* storage, const char* old_path, const char* new_path) {
if(!storage_common_exists(storage, old_path)) {
return FSE_NOT_EXIST;
}
FS_Error error;
if(storage_is_subdir(new_path, old_path)) {
return FSE_INVALID_NAME;
}
if(storage_file_exists(storage, new_path)) {
FS_Error error = storage_common_remove(storage, new_path);
if(error != FSE_OK) {
return error;
do {
if(!storage_common_exists(storage, old_path)) {
error = FSE_NOT_EXIST;
break;
}
}
S_API_PROLOGUE;
SAData data = {
.rename = {
.old = old_path,
.new = new_path,
.thread_id = furi_thread_get_current_id(),
}};
if(storage_dir_exists(storage, old_path)) {
// Cannot overwrite a file with a directory
if(storage_file_exists(storage, new_path)) {
error = FSE_INVALID_NAME;
break;
}
S_API_MESSAGE(StorageCommandCommonRename);
S_API_EPILOGUE;
FS_Error ret = S_RETURN_ERROR;
// Cannot move a directory to itself or to a nested directory
if(storage_common_equivalent_path(storage, old_path, new_path, true)) {
error = FSE_INVALID_NAME;
break;
}
if(ret == FSE_NOT_IMPLEMENTED) {
// Different filesystems, use copy + remove
ret = storage_common_copy(storage, old_path, new_path);
if(ret == FSE_OK) {
ret = storage_simply_remove_recursive(storage, old_path);
// Moving a regular file to itself does nothing and always succeeds
} else if(storage_common_equivalent_path(storage, old_path, new_path, false)) {
error = FSE_OK;
break;
}
}
return ret;
if(storage_common_exists(storage, new_path)) {
error = storage_simply_remove_recursive(storage, new_path);
if(error != FSE_OK) break;
}
S_API_PROLOGUE;
SAData data = {
.rename = {
.old = old_path,
.new = new_path,
.thread_id = furi_thread_get_current_id(),
}};
S_API_MESSAGE(StorageCommandCommonRename);
S_API_EPILOGUE;
error = S_RETURN_ERROR;
if(error == FSE_NOT_IMPLEMENTED) {
// Different filesystems, use copy + remove
error = storage_common_copy(storage, old_path, new_path);
if(error != FSE_OK) {
break;
}
if(!storage_simply_remove_recursive(storage, old_path)) {
error = FSE_INTERNAL;
}
}
} while(false);
return error;
}
static FS_Error
storage_copy_recursive(Storage* storage, const char* old_path, const char* new_path) {
if(storage_is_subdir(new_path, old_path)) {
if(storage_common_equivalent_path(storage, old_path, new_path, true)) {
return FSE_INVALID_NAME;
}

View File

@@ -391,12 +391,27 @@ static FS_Error storage_process_common_remove(Storage* app, FuriString* path) {
}
static FS_Error storage_process_common_rename(Storage* app, FuriString* old, FuriString* new) {
StorageData* storage;
FS_Error ret = storage_get_data(app, old, &storage);
FS_Error ret = FSE_OK;
do {
const StorageType storage_type_old = storage_get_type_by_path(old);
const StorageType storage_type_new = storage_get_type_by_path(new);
// Different filesystems, return to caller to do copy + remove
if(storage_type_old != storage_type_new) {
ret = FSE_NOT_IMPLEMENTED;
break;
}
// Same filesystem, use fast rename
StorageData* storage;
ret = storage_get_data(app, old, &storage);
if(ret != FSE_OK) break;
if(ret == FSE_OK) {
if(storage_path_already_open(old, storage)) {
return FSE_ALREADY_OPEN;
ret = FSE_ALREADY_OPEN;
break;
}
storage_data_timestamp(storage);
@@ -404,7 +419,7 @@ static FS_Error storage_process_common_rename(Storage* app, FuriString* old, Fur
storage,
common.rename(
storage, cstr_path_without_vfs_prefix(old), cstr_path_without_vfs_prefix(new)));
}
} while(false);
return ret;
}
@@ -605,7 +620,6 @@ void storage_process_alias(
void storage_process_message_internal(Storage* app, StorageMessage* message) {
FuriString* path = NULL;
FuriString* opath = NULL;
switch(message->command) {
// File operations
@@ -710,21 +724,16 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) {
storage_process_alias(app, path, message->data->path.thread_id, false);
message->return_data->error_value = storage_process_common_remove(app, path);
break;
case StorageCommandCommonRename:
opath = furi_string_alloc_set(message->data->rename.old);
storage_process_alias(app, opath, message->data->rename.thread_id, false);
path = furi_string_alloc_set(message->data->rename.new);
storage_process_alias(app, path, message->data->rename.thread_id, false);
// Paths are resolved, no aliases
if(strncmp(
furi_string_get_cstr(opath), furi_string_get_cstr(path), STORAGE_PATH_PREFIX_LEN)) {
// Different filesystems, return to caller
message->return_data->error_value = FSE_NOT_IMPLEMENTED;
break;
}
// Same filesystem, use rename
message->return_data->error_value = storage_process_common_rename(app, opath, path);
case StorageCommandCommonRename: {
FuriString* old_path = furi_string_alloc_set(message->data->rename.old);
FuriString* new_path = furi_string_alloc_set(message->data->rename.new);
storage_process_alias(app, old_path, message->data->cequivpath.thread_id, false);
storage_process_alias(app, new_path, message->data->cequivpath.thread_id, false);
message->return_data->error_value = storage_process_common_rename(app, old_path, new_path);
furi_string_free(old_path);
furi_string_free(new_path);
break;
}
case StorageCommandCommonMkDir:
path = furi_string_alloc_set(message->data->path.path);
storage_process_alias(app, path, message->data->path.thread_id, true);
@@ -780,9 +789,6 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) {
if(path != NULL) { //-V547
furi_string_free(path);
}
if(opath != NULL) { //-V547
furi_string_free(opath);
}
api_lock_unlock(message->lock);
}