diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index 6ecfa6b10..8cdf78617 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -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; } diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index a00d58d2f..d1c2ba73a 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -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); }