[FL-2675] /int space reservation (#1448)

* storage: added global #defines for /int, /ext & /any
* storage: introduced PATH_EXT, PATH_INT& PATH_ANY macros
* core apps: moved hardcoded config files names to separate headers; prefixed them with "."; updater: added file name migration to new naming convention on backup extraction
* storage: fixed storage_merge_recursive handling of complex directory structures; storage_move_to_sd: changed data migration logic to all non-dot files & all folders
* core: added macro aliases for core record names
* Bumped protobuf commit pointer
* storage: reserved 5 pages in /int; denying write&creation of non-dot files when running out of free space

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
hedger
2022-07-26 15:21:51 +03:00
committed by GitHub
parent 52a83fc929
commit 056446dfed
171 changed files with 1111 additions and 910 deletions

View File

@@ -11,7 +11,7 @@
#define ICON_SD_MOUNTED &I_SDcardMounted_11x8
#define ICON_SD_ERROR &I_SDcardFail_11x8
#define TAG "Storage"
#define TAG RECORD_STORAGE
static void storage_app_sd_icon_draw_callback(Canvas* canvas, void* context) {
furi_assert(canvas);
@@ -52,9 +52,9 @@ Storage* storage_app_alloc() {
view_port_draw_callback_set(app->sd_gui.view_port, storage_app_sd_icon_draw_callback, app);
view_port_enabled_set(app->sd_gui.view_port, false);
Gui* gui = furi_record_open("gui");
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, app->sd_gui.view_port, GuiLayerStatusBarLeft);
furi_record_close("gui");
furi_record_close(RECORD_GUI);
return app;
}
@@ -102,7 +102,7 @@ void storage_tick(Storage* app) {
int32_t storage_srv(void* p) {
UNUSED(p);
Storage* app = storage_app_alloc();
furi_record_create("storage", app);
furi_record_create(RECORD_STORAGE, app);
StorageMessage message;
while(1) {

View File

@@ -8,6 +8,16 @@
extern "C" {
#endif
#define STORAGE_INT_PATH_PREFIX "/int"
#define STORAGE_EXT_PATH_PREFIX "/ext"
#define STORAGE_ANY_PATH_PREFIX "/any"
#define INT_PATH(path) STORAGE_INT_PATH_PREFIX "/" path
#define EXT_PATH(path) STORAGE_EXT_PATH_PREFIX "/" path
#define ANY_PATH(path) STORAGE_ANY_PATH_PREFIX "/" path
#define RECORD_STORAGE "storage"
typedef struct Storage Storage;
/** Allocates and initializes a file descriptor
@@ -273,6 +283,8 @@ FS_Error storage_sd_status(Storage* api);
/******************* Internal LFS Functions *******************/
typedef void (*Storage_name_converter)(string_t);
/** Backs up internal storage to a tar archive
* @param api pointer to the api
* @param dstmane destination archive path
@@ -283,9 +295,10 @@ FS_Error storage_int_backup(Storage* api, const char* dstname);
/** Restores internal storage from a tar archive
* @param api pointer to the api
* @param dstmane archive path
* @param converter pointer to filename conversion function, may be NULL
* @return FS_Error operation result
*/
FS_Error storage_int_restore(Storage* api, const char* dstname);
FS_Error storage_int_restore(Storage* api, const char* dstname, Storage_name_converter converter);
/***************** Simplified Functions ******************/

View File

@@ -40,12 +40,13 @@ static void storage_cli_print_error(FS_Error error) {
static void storage_cli_info(Cli* cli, string_t path) {
UNUSED(cli);
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
if(string_cmp_str(path, "/int") == 0) {
if(string_cmp_str(path, STORAGE_INT_PATH_PREFIX) == 0) {
uint64_t total_space;
uint64_t free_space;
FS_Error error = storage_common_fs_info(api, "/int", &total_space, &free_space);
FS_Error error =
storage_common_fs_info(api, STORAGE_INT_PATH_PREFIX, &total_space, &free_space);
if(error != FSE_OK) {
storage_cli_print_error(error);
@@ -56,7 +57,7 @@ static void storage_cli_info(Cli* cli, string_t path) {
(uint32_t)(total_space / 1024),
(uint32_t)(free_space / 1024));
}
} else if(string_cmp_str(path, "/ext") == 0) {
} else if(string_cmp_str(path, STORAGE_EXT_PATH_PREFIX) == 0) {
SDInfo sd_info;
FS_Error error = storage_sd_info(api, &sd_info);
@@ -74,17 +75,17 @@ static void storage_cli_info(Cli* cli, string_t path) {
storage_cli_print_usage();
}
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
};
static void storage_cli_format(Cli* cli, string_t path) {
if(string_cmp_str(path, "/int") == 0) {
if(string_cmp_str(path, STORAGE_INT_PATH_PREFIX) == 0) {
storage_cli_print_error(FSE_NOT_IMPLEMENTED);
} else if(string_cmp_str(path, "/ext") == 0) {
} else if(string_cmp_str(path, STORAGE_EXT_PATH_PREFIX) == 0) {
printf("Formatting SD card, all data will be lost. Are you sure (y/n)?\r\n");
char answer = cli_getc(cli);
if(answer == 'y' || answer == 'Y') {
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
printf("Formatting, please wait...\r\n");
FS_Error error = storage_sd_format(api);
@@ -94,7 +95,7 @@ static void storage_cli_format(Cli* cli, string_t path) {
} else {
printf("SD card was successfully formatted.\r\n");
}
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
} else {
printf("Cancelled.\r\n");
}
@@ -110,7 +111,7 @@ static void storage_cli_list(Cli* cli, string_t path) {
printf("\t[D] ext\r\n");
printf("\t[D] any\r\n");
} else {
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(api);
if(storage_dir_open(file, string_get_cstr(path))) {
@@ -136,18 +137,18 @@ static void storage_cli_list(Cli* cli, string_t path) {
storage_dir_close(file);
storage_file_free(file);
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
}
static void storage_cli_tree(Cli* cli, string_t path) {
if(string_cmp_str(path, "/") == 0) {
string_set(path, "/int");
string_set(path, STORAGE_INT_PATH_PREFIX);
storage_cli_tree(cli, path);
string_set(path, "/ext");
string_set(path, STORAGE_EXT_PATH_PREFIX);
storage_cli_tree(cli, path);
} else {
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
DirWalk* dir_walk = dir_walk_alloc(api);
string_t name;
string_init(name);
@@ -174,13 +175,13 @@ static void storage_cli_tree(Cli* cli, string_t path) {
string_clear(name);
dir_walk_free(dir_walk);
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
}
static void storage_cli_read(Cli* cli, string_t path) {
UNUSED(cli);
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(api);
if(storage_file_open(file, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
@@ -206,11 +207,11 @@ static void storage_cli_read(Cli* cli, string_t path) {
storage_file_close(file);
storage_file_free(file);
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
static void storage_cli_write(Cli* cli, string_t path) {
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(api);
const uint16_t buffer_size = 512;
@@ -260,11 +261,11 @@ static void storage_cli_write(Cli* cli, string_t path) {
free(buffer);
storage_file_free(file);
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
static void storage_cli_read_chunks(Cli* cli, string_t path, string_t args) {
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(api);
uint32_t buffer_size;
@@ -298,11 +299,11 @@ static void storage_cli_read_chunks(Cli* cli, string_t path, string_t args) {
storage_file_close(file);
storage_file_free(file);
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
static void storage_cli_write_chunk(Cli* cli, string_t path, string_t args) {
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(api);
uint32_t buffer_size;
@@ -334,18 +335,19 @@ static void storage_cli_write_chunk(Cli* cli, string_t path, string_t args) {
}
storage_file_free(file);
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
static void storage_cli_stat(Cli* cli, string_t path) {
UNUSED(cli);
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
if(string_cmp_str(path, "/") == 0) {
printf("Storage\r\n");
} else if(
string_cmp_str(path, "/ext") == 0 || string_cmp_str(path, "/int") == 0 ||
string_cmp_str(path, "/any") == 0) {
string_cmp_str(path, STORAGE_EXT_PATH_PREFIX) == 0 ||
string_cmp_str(path, STORAGE_INT_PATH_PREFIX) == 0 ||
string_cmp_str(path, STORAGE_ANY_PATH_PREFIX) == 0) {
uint64_t total_space;
uint64_t free_space;
FS_Error error =
@@ -374,12 +376,12 @@ static void storage_cli_stat(Cli* cli, string_t path) {
}
}
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
static void storage_cli_copy(Cli* cli, string_t old_path, string_t args) {
UNUSED(cli);
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
string_t new_path;
string_init(new_path);
@@ -395,24 +397,24 @@ static void storage_cli_copy(Cli* cli, string_t old_path, string_t args) {
}
string_clear(new_path);
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
static void storage_cli_remove(Cli* cli, string_t path) {
UNUSED(cli);
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
FS_Error error = storage_common_remove(api, string_get_cstr(path));
if(error != FSE_OK) {
storage_cli_print_error(error);
}
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
static void storage_cli_rename(Cli* cli, string_t old_path, string_t args) {
UNUSED(cli);
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
string_t new_path;
string_init(new_path);
@@ -428,24 +430,24 @@ static void storage_cli_rename(Cli* cli, string_t old_path, string_t args) {
}
string_clear(new_path);
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
static void storage_cli_mkdir(Cli* cli, string_t path) {
UNUSED(cli);
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
FS_Error error = storage_common_mkdir(api, string_get_cstr(path));
if(error != FSE_OK) {
storage_cli_print_error(error);
}
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
static void storage_cli_md5(Cli* cli, string_t path) {
UNUSED(cli);
Storage* api = furi_record_open("storage");
Storage* api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(api);
if(storage_file_open(file, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
@@ -478,7 +480,7 @@ static void storage_cli_md5(Cli* cli, string_t path) {
storage_file_close(file);
storage_file_free(file);
furi_record_close("storage");
furi_record_close(RECORD_STORAGE);
}
void storage_cli(Cli* cli, string_t args, void* context) {
@@ -592,11 +594,11 @@ static void storage_cli_factory_reset(Cli* cli, string_t args, void* context) {
void storage_on_system_start() {
#ifdef SRV_CLI
Cli* cli = furi_record_open("cli");
cli_add_command(cli, "storage", CliCommandFlagParallelSafe, storage_cli, NULL);
Cli* cli = furi_record_open(RECORD_CLI);
cli_add_command(cli, RECORD_STORAGE, CliCommandFlagParallelSafe, storage_cli, NULL);
cli_add_command(
cli, "factory_reset", CliCommandFlagParallelSafe, storage_cli_factory_reset, NULL);
furi_record_close("cli");
furi_record_close(RECORD_CLI);
#else
UNUSED(storage_cli_factory_reset);
#endif

View File

@@ -447,17 +447,16 @@ static FS_Error
storage_merge_recursive(Storage* storage, const char* old_path, const char* new_path) {
FS_Error error = storage_common_mkdir(storage, new_path);
DirWalk* dir_walk = dir_walk_alloc(storage);
string_t path;
string_t tmp_new_path;
string_t tmp_old_path;
string_t path, file_basename, tmp_new_path;
FileInfo fileinfo;
string_init(path);
string_init(file_basename);
string_init(tmp_new_path);
string_init(tmp_old_path);
do {
if((error != FSE_OK) && (error != FSE_EXIST)) break;
dir_walk_set_recursive(dir_walk, false);
if(!dir_walk_open(dir_walk, old_path)) {
error = dir_walk_get_error(dir_walk);
break;
@@ -472,30 +471,33 @@ static FS_Error
} else if(res == DirWalkLast) {
break;
} else {
string_set(tmp_old_path, path);
string_right(path, strlen(old_path));
string_printf(tmp_new_path, "%s%s", new_path, string_get_cstr(path));
path_extract_basename(string_get_cstr(path), file_basename);
path_concat(new_path, string_get_cstr(file_basename), tmp_new_path);
if(fileinfo.flags & FSF_DIRECTORY) {
if(storage_common_stat(storage, string_get_cstr(tmp_new_path), &fileinfo) ==
FSE_OK) {
if(fileinfo.flags & FSF_DIRECTORY) {
error = storage_common_mkdir(storage, string_get_cstr(tmp_new_path));
if(error != FSE_OK) {
break;
}
}
}
} else {
error = storage_common_merge(
storage, string_get_cstr(tmp_old_path), string_get_cstr(tmp_new_path));
}
error = storage_common_merge(
storage, string_get_cstr(path), string_get_cstr(tmp_new_path));
if(error != FSE_OK) break;
if(error != FSE_OK) {
break;
}
}
}
} while(false);
string_clear(tmp_new_path);
string_clear(tmp_old_path);
string_clear(file_basename);
string_clear(path);
dir_walk_free(dir_walk);
return error;

View File

@@ -3,20 +3,19 @@
#include "storage.h"
#include <toolbox/tar/tar_archive.h>
#define INT_PATH "/int"
FS_Error storage_int_backup(Storage* api, const char* dstname) {
TarArchive* archive = tar_archive_alloc(api);
bool success = tar_archive_open(archive, dstname, TAR_OPEN_MODE_WRITE) &&
tar_archive_add_dir(archive, INT_PATH, "") && tar_archive_finalize(archive);
tar_archive_add_dir(archive, STORAGE_INT_PATH_PREFIX, "") &&
tar_archive_finalize(archive);
tar_archive_free(archive);
return success ? FSE_OK : FSE_INTERNAL;
}
FS_Error storage_int_restore(Storage* api, const char* srcname) {
FS_Error storage_int_restore(Storage* api, const char* srcname, Storage_name_converter converter) {
TarArchive* archive = tar_archive_alloc(api);
bool success = tar_archive_open(archive, srcname, TAR_OPEN_MODE_READ) &&
tar_archive_unpack_to(archive, INT_PATH);
tar_archive_unpack_to(archive, STORAGE_INT_PATH_PREFIX, converter);
tar_archive_free(archive);
return success ? FSE_OK : FSE_INTERNAL;
}

View File

@@ -43,17 +43,18 @@ static const char* remove_vfs(const char* path) {
return path + MIN(4u, strlen(path));
}
static const char* ext_path = "/ext";
static const char* int_path = "/int";
static const char* any_path = "/any";
static StorageType storage_get_type_by_path(Storage* app, const char* path) {
StorageType type = ST_ERROR;
if(strlen(path) >= strlen(ext_path) && memcmp(path, ext_path, strlen(ext_path)) == 0) {
if(strlen(path) >= strlen(STORAGE_EXT_PATH_PREFIX) &&
memcmp(path, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) {
type = ST_EXT;
} else if(strlen(path) >= strlen(int_path) && memcmp(path, int_path, strlen(int_path)) == 0) {
} else if(
strlen(path) >= strlen(STORAGE_INT_PATH_PREFIX) &&
memcmp(path, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) {
type = ST_INT;
} else if(strlen(path) >= strlen(any_path) && memcmp(path, any_path, strlen(any_path)) == 0) {
} else if(
strlen(path) >= strlen(STORAGE_ANY_PATH_PREFIX) &&
memcmp(path, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) {
type = ST_ANY;
}
@@ -68,19 +69,20 @@ static StorageType storage_get_type_by_path(Storage* app, const char* path) {
}
static void storage_path_change_to_real_storage(string_t path, StorageType real_storage) {
if(memcmp(string_get_cstr(path), any_path, strlen(any_path)) == 0) {
if(memcmp(string_get_cstr(path), STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) ==
0) {
switch(real_storage) {
case ST_EXT:
string_set_char(path, 0, ext_path[0]);
string_set_char(path, 1, ext_path[1]);
string_set_char(path, 2, ext_path[2]);
string_set_char(path, 3, ext_path[3]);
string_set_char(path, 0, STORAGE_EXT_PATH_PREFIX[0]);
string_set_char(path, 1, STORAGE_EXT_PATH_PREFIX[1]);
string_set_char(path, 2, STORAGE_EXT_PATH_PREFIX[2]);
string_set_char(path, 3, STORAGE_EXT_PATH_PREFIX[3]);
break;
case ST_INT:
string_set_char(path, 0, int_path[0]);
string_set_char(path, 1, int_path[1]);
string_set_char(path, 2, int_path[2]);
string_set_char(path, 3, int_path[3]);
string_set_char(path, 0, STORAGE_INT_PATH_PREFIX[0]);
string_set_char(path, 1, STORAGE_INT_PATH_PREFIX[1]);
string_set_char(path, 2, STORAGE_INT_PATH_PREFIX[2]);
string_set_char(path, 3, STORAGE_INT_PATH_PREFIX[3]);
break;
default:
break;

View File

@@ -317,22 +317,22 @@ static void do_test_end(Storage* api, const char* path) {
int32_t storage_test_app(void* p) {
UNUSED(p);
Storage* api = furi_record_open("storage");
do_test_start(api, "/int");
do_test_start(api, "/any");
do_test_start(api, "/ext");
Storage* api = furi_record_open(RECORD_STORAGE);
do_test_start(api, STORAGE_INT_PATH_PREFIX);
do_test_start(api, STORAGE_ANY_PATH_PREFIX);
do_test_start(api, STORAGE_EXT_PATH_PREFIX);
do_file_test(api, "/int/test.txt");
do_file_test(api, "/any/test.txt");
do_file_test(api, "/ext/test.txt");
do_file_test(api, INT_PATH("test.txt"));
do_file_test(api, ANY_PATH("test.txt"));
do_file_test(api, EXT_PATH("test.txt"));
do_dir_test(api, "/int");
do_dir_test(api, "/any");
do_dir_test(api, "/ext");
do_dir_test(api, STORAGE_INT_PATH_PREFIX);
do_dir_test(api, STORAGE_ANY_PATH_PREFIX);
do_dir_test(api, STORAGE_EXT_PATH_PREFIX);
do_test_end(api, "/int");
do_test_end(api, "/any");
do_test_end(api, "/ext");
do_test_end(api, STORAGE_INT_PATH_PREFIX);
do_test_end(api, STORAGE_ANY_PATH_PREFIX);
do_test_end(api, STORAGE_EXT_PATH_PREFIX);
while(true) {
furi_delay_ms(1000);

View File

@@ -11,7 +11,7 @@ typedef FILINFO SDFileInfo;
typedef FRESULT SDError;
#define TAG "StorageExt"
#define STORAGE_PATH "/ext"
/********************* Definitions ********************/
typedef struct {
@@ -35,9 +35,9 @@ static bool sd_mount_card(StorageData* storage, bool notify) {
while(result == false && counter > 0 && hal_sd_detect()) {
if(notify) {
NotificationApp* notification = furi_record_open("notification");
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
sd_notify_wait(notification);
furi_record_close("notification");
furi_record_close(RECORD_NOTIFICATION);
}
if((counter % 2) == 0) {
@@ -78,9 +78,9 @@ static bool sd_mount_card(StorageData* storage, bool notify) {
}
if(notify) {
NotificationApp* notification = furi_record_open("notification");
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
sd_notify_wait_off(notification);
furi_record_close("notification");
furi_record_close(RECORD_NOTIFICATION);
}
if(!result) {
@@ -224,16 +224,16 @@ static void storage_ext_tick_internal(StorageData* storage, bool notify) {
if(storage->status != StorageStatusOK) {
FURI_LOG_E(TAG, "sd init error: %s", storage_data_status_text(storage));
if(notify) {
NotificationApp* notification = furi_record_open("notification");
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
sd_notify_error(notification);
furi_record_close("notification");
furi_record_close(RECORD_NOTIFICATION);
}
} else {
FURI_LOG_I(TAG, "card mounted");
if(notify) {
NotificationApp* notification = furi_record_open("notification");
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
sd_notify_success(notification);
furi_record_close("notification");
furi_record_close(RECORD_NOTIFICATION);
}
}
@@ -252,9 +252,9 @@ static void storage_ext_tick_internal(StorageData* storage, bool notify) {
sd_unmount_card(storage);
if(notify) {
NotificationApp* notification = furi_record_open("notification");
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
sd_notify_eject(notification);
furi_record_close("notification");
furi_record_close(RECORD_NOTIFICATION);
}
}
}

View File

@@ -1,11 +1,16 @@
#include "storage_int.h"
#include <lfs.h>
#include <furi_hal.h>
#include <toolbox/path.h>
#define TAG "StorageInt"
#define STORAGE_PATH "/int"
#define STORAGE_PATH STORAGE_INT_PATH_PREFIX
#define LFS_CLEAN_FINGERPRINT 0
/* When less than LFS_RESERVED_PAGES_COUNT are left free, creation &
* modification of non-dot files is restricted */
#define LFS_RESERVED_PAGES_COUNT 5
typedef struct {
const size_t start_address;
const size_t start_page;
@@ -297,6 +302,20 @@ static FS_Error storage_int_parse_error(int error) {
return result;
}
/* Returns false if less than reserved space is left free */
static bool storage_int_check_for_free_space(StorageData* storage) {
LFSData* lfs_data = lfs_data_get_from_storage(storage);
lfs_ssize_t result = lfs_fs_size(lfs_get_from_storage(storage));
if(result >= 0) {
lfs_size_t free_space =
(lfs_data->config.block_count - result) * lfs_data->config.block_size;
return (free_space > LFS_RESERVED_PAGES_COUNT * furi_hal_flash_get_page_size());
}
return false;
}
/******************* File Functions *******************/
static bool storage_int_file_open(
@@ -308,6 +327,8 @@ static bool storage_int_file_open(
StorageData* storage = ctx;
lfs_t* lfs = lfs_get_from_storage(storage);
bool enough_free_space = storage_int_check_for_free_space(storage);
int flags = 0;
if(access_mode & FSAM_READ) flags |= LFS_O_RDONLY;
@@ -321,6 +342,23 @@ static bool storage_int_file_open(
LFSHandle* handle = lfs_handle_alloc_file();
storage_set_storage_file_data(file, handle, storage);
if(!enough_free_space) {
string_t filename;
string_init(filename);
path_extract_basename(path, filename);
bool is_dot_file = (!string_empty_p(filename) && (string_get_char(filename, 0) == '.'));
string_clear(filename);
/* Restrict write & creation access to all non-dot files */
if(!is_dot_file && (flags & (LFS_O_CREAT | LFS_O_WRONLY))) {
file->internal_error_id = LFS_ERR_NOSPC;
file->error_id = FSE_DENIED;
FURI_LOG_W(TAG, "Denied access to '%s': no free space", path);
return false;
}
}
file->internal_error_id = lfs_file_open(lfs, lfs_handle_get_file(handle), path, flags);
if(file->internal_error_id >= LFS_ERR_OK) {
@@ -328,6 +366,7 @@ static bool storage_int_file_open(
}
file->error_id = storage_int_parse_error(file->internal_error_id);
return (file->error_id == FSE_OK);
}