diff --git a/applications/services/storage/filesystem_api_internal.h b/applications/services/storage/filesystem_api_internal.h index 47214f21a..407b37a71 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 @@ -94,6 +100,7 @@ typedef struct { uint16_t (*write)(void* context, File* file, const void* buff, uint16_t bytes_to_write); bool (*const seek)(void* context, File* file, uint32_t offset, bool from_start); uint64_t (*tell)(void* context, File* file); + bool (*const expand)(void* context, File* file, uint64_t size); bool (*const truncate)(void* context, File* file); uint64_t (*size)(void* context, File* file); bool (*const sync)(void* context, File* file); 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 e77bad6ee..8f0dc2879 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; @@ -130,6 +136,7 @@ typedef enum { StorageCommandFileWrite, StorageCommandFileSeek, StorageCommandFileTell, + StorageCommandFileExpand, StorageCommandFileTruncate, StorageCommandFileSize, StorageCommandFileSync, diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index 0eaf23b18..4cb9ffc61 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 4fd06df73..1b0542070 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); + return 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); + return (file->error_id == FSE_OK); +#endif +} + 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..5fab54e24 100644 --- a/applications/services/storage/storages/storage_int.c +++ b/applications/services/storage/storages/storage_int.c @@ -455,6 +455,13 @@ 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); + return false; +} + static bool storage_int_file_truncate(void* ctx, File* file) { StorageData* storage = ctx; lfs_t* lfs = lfs_get_from_storage(storage); @@ -703,6 +710,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 559823f9f..a9fdeece8 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2669,6 +2669,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