diff --git a/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c b/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c index e88441d87..a2ad46ef6 100644 --- a/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c +++ b/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c @@ -139,7 +139,7 @@ bool mass_storage_scene_create_image_on_event(void* context, SceneManagerEvent e uint64_t size = image_sizes[app->create_image_size].value; if(size == app->create_image_max) size--; - if(!storage_file_seek(app->file, size, true)) break; + if(!storage_file_expand(app->file, size)) break; // Zero out first 4k - partition table and adjacent data if(!storage_file_seek(app->file, 0, true)) break; diff --git a/applications/services/storage/filesystem_api_internal.h b/applications/services/storage/filesystem_api_internal.h index 6aa296662..f86e77614 100644 --- a/applications/services/storage/filesystem_api_internal.h +++ b/applications/services/storage/filesystem_api_internal.h @@ -62,6 +62,12 @@ struct File { * @param file pointer to file object * @return current r/w pointer position * + * @var FS_File_Api::expand + * @brief Expand the file (allocate space for it) + * @param file pointer to file object + * @param size how many bytes to allocate + * @return success flag + * * @var FS_File_Api::truncate * @brief Truncate file size to current r/w pointer position * @param file pointer to file object @@ -98,6 +104,8 @@ typedef struct { uint64_t (*size)(void* context, File* file); bool (*const sync)(void* context, File* file); bool (*const eof)(void* context, File* file); + + bool (*const expand)(void* context, File* file, uint64_t size); } FS_File_Api; /** Dir api structure diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index 1ee4ab820..2743255cd 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -117,6 +117,13 @@ bool storage_file_seek(File* file, uint32_t offset, bool from_start); */ uint64_t storage_file_tell(File* file); +/** Expand the file (allocate space for it) + * @param file pointer to file object. + * @param size how many bytes to allocate + * @return success flag + */ +bool storage_file_expand(File* file, uint64_t size); + /** Truncates the file size to the current position of the r/w pointer * @param file pointer to file object. * @return bool success flag diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index 1cfe06a52..a5fc8cd6e 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -203,6 +203,21 @@ uint64_t storage_file_tell(File* file) { return S_RETURN_UINT64; } +bool storage_file_expand(File* file, uint64_t size) { + S_FILE_API_PROLOGUE; + S_API_PROLOGUE; + + SAData data = { + .fexpand = { + .file = file, + .size = size, + }}; + + S_API_MESSAGE(StorageCommandFileExpand); + S_API_EPILOGUE; + return S_RETURN_BOOL; +} + bool storage_file_truncate(File* file) { S_FILE_API_PROLOGUE; S_API_PROLOGUE; diff --git a/applications/services/storage/storage_message.h b/applications/services/storage/storage_message.h index 9511fcdd9..8be09f117 100644 --- a/applications/services/storage/storage_message.h +++ b/applications/services/storage/storage_message.h @@ -32,6 +32,11 @@ typedef struct { bool from_start; } SADataFSeek; +typedef struct { + File* file; + uint64_t size; +} SADataFExpand; + typedef struct { File* file; const char* path; @@ -97,6 +102,7 @@ typedef union { SADataFRead fread; SADataFWrite fwrite; SADataFSeek fseek; + SADataFExpand fexpand; SADataDOpen dopen; SADataDRead dread; @@ -149,6 +155,7 @@ typedef enum { StorageCommandSDStatus, StorageCommandCommonResolvePath, + StorageCommandFileExpand, StorageCommandCommonRename, } StorageCommand; diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index 87cb6b286..fef9a9891 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -206,6 +206,19 @@ static uint64_t storage_process_file_tell(Storage* app, File* file) { return ret; } +static bool storage_process_file_expand(Storage* app, File* file, const uint64_t size) { + bool ret = false; + StorageData* storage = get_storage_by_file(file, app->storage); + + if(storage == NULL) { + file->error_id = FSE_INVALID_PARAMETER; + } else { + FS_CALL(storage, file.expand(storage, file, size)); + } + + return ret; +} + static bool storage_process_file_truncate(Storage* app, File* file) { bool ret = false; StorageData* storage = get_storage_by_file(file, app->storage); @@ -575,6 +588,10 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) { message->return_data->uint64_value = storage_process_file_tell(app, message->data->file.file); break; + case StorageCommandFileExpand: + message->return_data->bool_value = storage_process_file_expand( + app, message->data->fexpand.file, message->data->fexpand.size); + break; case StorageCommandFileTruncate: message->return_data->bool_value = storage_process_file_truncate(app, message->data->file.file); diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index ca77b6843..7592b82fe 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -396,6 +396,22 @@ static uint64_t storage_ext_file_tell(void* ctx, File* file) { return position; } +static bool storage_ext_file_expand(void* ctx, File* file, const uint64_t size) { +#ifdef FURI_RAM_EXEC + UNUSED(ctx); + UNUSED(file); + UNUSED(size); + file->error_id = FSE_NOT_READY; +#else + StorageData* storage = ctx; + SDFile* file_data = storage_get_storage_file_data(file, storage); + + file->internal_error_id = f_expand(file_data, size, 1); + file->error_id = storage_ext_parse_error(file->internal_error_id); +#endif + return (file->error_id == FSE_OK); +} + static bool storage_ext_file_truncate(void* ctx, File* file) { #ifdef FURI_RAM_EXEC UNUSED(ctx); @@ -609,6 +625,7 @@ static const FS_Api fs_api = { .write = storage_ext_file_write, .seek = storage_ext_file_seek, .tell = storage_ext_file_tell, + .expand = storage_ext_file_expand, .truncate = storage_ext_file_truncate, .size = storage_ext_file_size, .sync = storage_ext_file_sync, diff --git a/applications/services/storage/storages/storage_int.c b/applications/services/storage/storages/storage_int.c index 50e3a7899..765bb8e93 100644 --- a/applications/services/storage/storages/storage_int.c +++ b/applications/services/storage/storages/storage_int.c @@ -455,6 +455,14 @@ static uint64_t storage_int_file_tell(void* ctx, File* file) { return position; } +static bool storage_int_file_expand(void* ctx, File* file, const uint64_t size) { + UNUSED(ctx); + UNUSED(file); + UNUSED(size); + file->error_id = FSE_NOT_IMPLEMENTED; + return (file->error_id == FSE_OK); +} + static bool storage_int_file_truncate(void* ctx, File* file) { StorageData* storage = ctx; lfs_t* lfs = lfs_get_from_storage(storage); @@ -703,6 +711,7 @@ static const FS_Api fs_api = { .write = storage_int_file_write, .seek = storage_int_file_seek, .tell = storage_int_file_tell, + .expand = storage_int_file_expand, .truncate = storage_int_file_truncate, .size = storage_int_file_size, .sync = storage_int_file_sync, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 9104206a8..4c5cf5da3 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2696,6 +2696,7 @@ Function,+,storage_file_close,_Bool,File* Function,+,storage_file_copy_to_file,_Bool,"File*, File*, uint32_t" Function,+,storage_file_eof,_Bool,File* Function,+,storage_file_exists,_Bool,"Storage*, const char*" +Function,+,storage_file_expand,_Bool,"File*, uint64_t" Function,+,storage_file_free,void,File* Function,+,storage_file_get_error,FS_Error,File* Function,+,storage_file_get_error_desc,const char*,File* diff --git a/firmware/targets/f7/fatfs/ffconf.h b/firmware/targets/f7/fatfs/ffconf.h index 8408a1ec1..3d9462fc5 100644 --- a/firmware/targets/f7/fatfs/ffconf.h +++ b/firmware/targets/f7/fatfs/ffconf.h @@ -68,7 +68,7 @@ #define _USE_FASTSEEK 1 /* This option switches fast seek feature. (0:Disable or 1:Enable) */ -#define _USE_EXPAND 0 +#define _USE_EXPAND 1 /* This option switches f_expand function. (0:Disable or 1:Enable) */ #define _USE_CHMOD 0