diff --git a/applications/services/rpc/rpc_storage.c b/applications/services/rpc/rpc_storage.c index 151d73d61..306b25777 100644 --- a/applications/services/rpc/rpc_storage.c +++ b/applications/services/rpc/rpc_storage.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -50,7 +51,6 @@ static void rpc_system_storage_reset_state( if(rpc_storage->state == RpcStorageStateWriting) { storage_file_close(rpc_storage->file); storage_file_free(rpc_storage->file); - furi_record_close(RECORD_STORAGE); } rpc_storage->state = RpcStorageStateIdle; @@ -118,10 +118,8 @@ static void rpc_system_storage_info_process(const PB_Main* request, void* contex PB_Main* response = malloc(sizeof(PB_Main)); response->command_id = request->command_id; - Storage* fs_api = furi_record_open(RECORD_STORAGE); - FS_Error error = storage_common_fs_info( - fs_api, + rpc_storage->api, request->content.storage_info_request.path, &response->content.storage_info_response.total_space, &response->content.storage_info_response.free_space); @@ -135,7 +133,6 @@ static void rpc_system_storage_info_process(const PB_Main* request, void* contex rpc_send_and_release(session, response); free(response); - furi_record_close(RECORD_STORAGE); } static void rpc_system_storage_timestamp_process(const PB_Main* request, void* context) { @@ -154,11 +151,9 @@ static void rpc_system_storage_timestamp_process(const PB_Main* request, void* c PB_Main* response = malloc(sizeof(PB_Main)); response->command_id = request->command_id; - Storage* fs_api = furi_record_open(RECORD_STORAGE); - const char* path = request->content.storage_timestamp_request.path; uint32_t timestamp = 0; - FS_Error error = storage_common_timestamp(fs_api, path, ×tamp); + FS_Error error = storage_common_timestamp(rpc_storage->api, path, ×tamp); response->command_status = rpc_system_storage_get_error(error); response->which_content = PB_Main_empty_tag; @@ -170,7 +165,6 @@ static void rpc_system_storage_timestamp_process(const PB_Main* request, void* c rpc_send_and_release(session, response); free(response); - furi_record_close(RECORD_STORAGE); } static void rpc_system_storage_stat_process(const PB_Main* request, void* context) { @@ -189,11 +183,9 @@ static void rpc_system_storage_stat_process(const PB_Main* request, void* contex PB_Main* response = malloc(sizeof(PB_Main)); response->command_id = request->command_id; - Storage* fs_api = furi_record_open(RECORD_STORAGE); - const char* path = request->content.storage_stat_request.path; FileInfo fileinfo; - FS_Error error = storage_common_stat(fs_api, path, &fileinfo); + FS_Error error = storage_common_stat(rpc_storage->api, path, &fileinfo); response->command_status = rpc_system_storage_get_error(error); response->which_content = PB_Main_empty_tag; @@ -209,12 +201,12 @@ static void rpc_system_storage_stat_process(const PB_Main* request, void* contex rpc_send_and_release(session, response); free(response); - furi_record_close(RECORD_STORAGE); } static void rpc_system_storage_list_root(const PB_Main* request, void* context) { furi_assert(request); furi_assert(context); + RpcStorageSystem* rpc_storage = context; RpcSession* session = rpc_storage->session; furi_assert(session); @@ -279,8 +271,7 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex return; } - Storage* fs_api = furi_record_open(RECORD_STORAGE); - File* dir = storage_file_alloc(fs_api); + File* dir = storage_file_alloc(rpc_storage->api); PB_Main response = { .command_id = request->command_id, @@ -293,7 +284,7 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex bool include_md5 = list_request->include_md5; FuriString* md5 = furi_string_alloc(); FuriString* md5_path = furi_string_alloc(); - File* file = storage_file_alloc(fs_api); + File* file = storage_file_alloc(rpc_storage->api); bool finish = false; int i = 0; @@ -350,8 +341,6 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex storage_dir_close(dir); storage_file_free(dir); storage_file_free(file); - - furi_record_close(RECORD_STORAGE); } static void rpc_system_storage_read_process(const PB_Main* request, void* context) { @@ -370,8 +359,7 @@ static void rpc_system_storage_read_process(const PB_Main* request, void* contex /* use same message memory to send response */ PB_Main* response = malloc(sizeof(PB_Main)); const char* path = request->content.storage_read_request.path; - Storage* fs_api = furi_record_open(RECORD_STORAGE); - File* file = storage_file_alloc(fs_api); + File* file = storage_file_alloc(rpc_storage->api); bool fs_operation_success = storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING); if(fs_operation_success) { @@ -420,8 +408,6 @@ static void rpc_system_storage_read_process(const PB_Main* request, void* contex free(response); storage_file_close(file); storage_file_free(file); - - furi_record_close(RECORD_STORAGE); } static void rpc_system_storage_write_process(const PB_Main* request, void* context) { @@ -451,7 +437,6 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte } if(rpc_storage->state != RpcStorageStateWriting) { - rpc_storage->api = furi_record_open(RECORD_STORAGE); rpc_storage->file = storage_file_alloc(rpc_storage->api); rpc_storage->current_command_id = request->command_id; rpc_storage->state = RpcStorageStateWriting; @@ -492,14 +477,15 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte } } -static bool rpc_system_storage_is_dir_is_empty(Storage* fs_api, const char* path) { - furi_assert(fs_api); +static bool rpc_system_storage_is_dir_is_empty(Storage* storage, const char* path) { + furi_assert(storage); furi_assert(path); + FileInfo fileinfo; bool is_dir_is_empty = true; - FS_Error error = storage_common_stat(fs_api, path, &fileinfo); + FS_Error error = storage_common_stat(storage, path, &fileinfo); if((error == FSE_OK) && file_info_is_dir(&fileinfo)) { - File* dir = storage_file_alloc(fs_api); + File* dir = storage_file_alloc(storage); if(storage_dir_open(dir, path)) { char* name = malloc(MAX_NAME_LENGTH); while(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) { @@ -531,18 +517,17 @@ static void rpc_system_storage_delete_process(const PB_Main* request, void* cont PB_CommandStatus status = PB_CommandStatus_ERROR; rpc_system_storage_reset_state(rpc_storage, session, true); - Storage* fs_api = furi_record_open(RECORD_STORAGE); - char* path = request->content.storage_delete_request.path; if(!path) { status = PB_CommandStatus_ERROR_INVALID_PARAMETERS; } else { - FS_Error error_remove = storage_common_remove(fs_api, path); + FS_Error error_remove = storage_common_remove(rpc_storage->api, path); // FSE_DENIED is for empty directory, but not only for this // that's why we have to check it - if((error_remove == FSE_DENIED) && !rpc_system_storage_is_dir_is_empty(fs_api, path)) { + if((error_remove == FSE_DENIED) && + !rpc_system_storage_is_dir_is_empty(rpc_storage->api, path)) { if(request->content.storage_delete_request.recursive) { - bool deleted = storage_simply_remove_recursive(fs_api, path); + bool deleted = storage_simply_remove_recursive(rpc_storage->api, path); status = deleted ? PB_CommandStatus_OK : PB_CommandStatus_ERROR; } else { status = PB_CommandStatus_ERROR_STORAGE_DIR_NOT_EMPTY; @@ -554,7 +539,6 @@ static void rpc_system_storage_delete_process(const PB_Main* request, void* cont } } - furi_record_close(RECORD_STORAGE); rpc_send_and_release_empty(session, request->command_id, status); } @@ -572,11 +556,10 @@ static void rpc_system_storage_mkdir_process(const PB_Main* request, void* conte PB_CommandStatus status; rpc_system_storage_reset_state(rpc_storage, session, true); - Storage* fs_api = furi_record_open(RECORD_STORAGE); char* path = request->content.storage_mkdir_request.path; if(path) { if(path_contains_only_ascii(path)) { - FS_Error error = storage_common_mkdir(fs_api, path); + FS_Error error = storage_common_mkdir(rpc_storage->api, path); status = rpc_system_storage_get_error(error); } else { status = PB_CommandStatus_ERROR_STORAGE_INVALID_NAME; @@ -584,7 +567,6 @@ static void rpc_system_storage_mkdir_process(const PB_Main* request, void* conte } else { status = PB_CommandStatus_ERROR_INVALID_PARAMETERS; } - furi_record_close(RECORD_STORAGE); rpc_send_and_release_empty(session, request->command_id, status); } @@ -608,8 +590,7 @@ static void rpc_system_storage_md5sum_process(const PB_Main* request, void* cont return; } - Storage* fs_api = furi_record_open(RECORD_STORAGE); - File* file = storage_file_alloc(fs_api); + File* file = storage_file_alloc(rpc_storage->api); FuriString* md5 = furi_string_alloc(); FS_Error file_error; @@ -633,8 +614,6 @@ static void rpc_system_storage_md5sum_process(const PB_Main* request, void* cont furi_string_free(md5); storage_file_free(file); - - furi_record_close(RECORD_STORAGE); } static void rpc_system_storage_rename_process(const PB_Main* request, void* context) { @@ -651,11 +630,9 @@ static void rpc_system_storage_rename_process(const PB_Main* request, void* cont PB_CommandStatus status; rpc_system_storage_reset_state(rpc_storage, session, true); - Storage* fs_api = furi_record_open(RECORD_STORAGE); - if(path_contains_only_ascii(request->content.storage_rename_request.new_path)) { FS_Error error = storage_common_rename( - fs_api, + rpc_storage->api, request->content.storage_rename_request.old_path, request->content.storage_rename_request.new_path); status = rpc_system_storage_get_error(error); @@ -663,7 +640,6 @@ static void rpc_system_storage_rename_process(const PB_Main* request, void* cont status = PB_CommandStatus_ERROR_STORAGE_INVALID_NAME; } - furi_record_close(RECORD_STORAGE); rpc_send_and_release_empty(session, request->command_id, status); } @@ -678,12 +654,10 @@ static void rpc_system_storage_backup_create_process(const PB_Main* request, voi RpcSession* session = rpc_storage->session; furi_assert(session); - Storage* fs_api = furi_record_open(RECORD_STORAGE); + rpc_system_storage_reset_state(rpc_storage, session, true); - bool backup_ok = - lfs_backup_create(fs_api, request->content.storage_backup_create_request.archive_path); - - furi_record_close(RECORD_STORAGE); + bool backup_ok = lfs_backup_create( + rpc_storage->api, request->content.storage_backup_create_request.archive_path); rpc_send_and_release_empty( session, request->command_id, backup_ok ? PB_CommandStatus_OK : PB_CommandStatus_ERROR); @@ -700,17 +674,58 @@ static void rpc_system_storage_backup_restore_process(const PB_Main* request, vo RpcSession* session = rpc_storage->session; furi_assert(session); - Storage* fs_api = furi_record_open(RECORD_STORAGE); + rpc_system_storage_reset_state(rpc_storage, session, true); - bool backup_ok = - lfs_backup_unpack(fs_api, request->content.storage_backup_restore_request.archive_path); - - furi_record_close(RECORD_STORAGE); + bool backup_ok = lfs_backup_unpack( + rpc_storage->api, request->content.storage_backup_restore_request.archive_path); rpc_send_and_release_empty( session, request->command_id, backup_ok ? PB_CommandStatus_OK : PB_CommandStatus_ERROR); } +static void rpc_system_storage_tar_extract_process(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(request->which_content == PB_Main_storage_tar_extract_request_tag); + furi_assert(context); + + FURI_LOG_D(TAG, "TarExtract"); + + RpcStorageSystem* rpc_storage = context; + RpcSession* session = rpc_storage->session; + furi_assert(session); + + PB_CommandStatus status; + rpc_system_storage_reset_state(rpc_storage, session, true); + + TarArchive* archive = tar_archive_alloc(rpc_storage->api); + + do { + if(!path_contains_only_ascii(request->content.storage_tar_extract_request.out_path)) { + status = PB_CommandStatus_ERROR_STORAGE_INVALID_NAME; + break; + } + + if(!tar_archive_open( + archive, + request->content.storage_tar_extract_request.tar_path, + TAR_OPEN_MODE_READ)) { + status = PB_CommandStatus_ERROR_STORAGE_INVALID_PARAMETER; + break; + } + + if(!tar_archive_unpack_to( + archive, request->content.storage_tar_extract_request.out_path, NULL)) { + status = PB_CommandStatus_ERROR_STORAGE_INTERNAL; + break; + } + + status = PB_CommandStatus_OK; + } while(0); + + tar_archive_free(archive); + rpc_send_and_release_empty(session, request->command_id, status); +} + void* rpc_system_storage_alloc(RpcSession* session) { furi_assert(session); @@ -761,6 +776,9 @@ void* rpc_system_storage_alloc(RpcSession* session) { rpc_handler.message_handler = rpc_system_storage_backup_restore_process; rpc_add_handler(session, PB_Main_storage_backup_restore_request_tag, &rpc_handler); + rpc_handler.message_handler = rpc_system_storage_tar_extract_process; + rpc_add_handler(session, PB_Main_storage_tar_extract_request_tag, &rpc_handler); + return rpc_storage; } @@ -771,5 +789,8 @@ void rpc_system_storage_free(void* context) { furi_assert(session); rpc_system_storage_reset_state(rpc_storage, session, false); + + furi_record_close(RECORD_STORAGE); + rpc_storage->api = NULL; free(rpc_storage); } diff --git a/assets/protobuf b/assets/protobuf index 1956b83bb..816de200a 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit 1956b83bba99313ee8d8386e5d35d0549341ca26 +Subproject commit 816de200a4a43efc25c5b92d6a57fc982d7e988a diff --git a/lib/toolbox/tar/tar_archive.c b/lib/toolbox/tar/tar_archive.c index 639f2eaec..25084aaa0 100644 --- a/lib/toolbox/tar/tar_archive.c +++ b/lib/toolbox/tar/tar_archive.c @@ -224,6 +224,11 @@ static int archive_extract_foreach_cb(mtar_t* tar, const mtar_header_t* header, FuriString* full_extracted_fname; if(header->type == MTAR_TDIR) { + // Skip "/" entry since concat would leave it dangling, also want caller to mkdir destination + if(strcmp(header->name, "/") == 0) { + return 0; + } + full_extracted_fname = furi_string_alloc(); path_concat(op_params->work_dir, header->name, full_extracted_fname);