[FL-3055] Getter for application data path (#2181)
* Threads: application id * Unit tests: appsdata getter test * Unit tests: moar test cases for appsdata getter * Unit tests: remove folders after test * Storage: dir_is_exist, migrate, + unit_tests * Plugins: migration * Storage: common_exists, moar unit_tests 4 "common_migrate", "common_migrate" and "common_merge" bugfixes * Storage: use FuriString for path handling * Storage API: send caller thread id with path * Storage: remove StorageType field in storage file list * Storage: simplify processing * Storage API: send caller thread id with path everywhere * Storage: /app alias, unit tests and path creation * Storage, path helper: remove unused * Examples: app data example * App plugins: use new VFS path * Storage: file_info_is_dir * Services: handle alias if the service accepts a path. * App plugins: fixes * Make PVS happy * Storage: fix storage_merge_recursive * Storage: rename process_aliases to resolve_path. Rename APPS_DATA to APP_DATA. * Apps: use predefined macro instead of raw paths. Example Apps Data: README fixes. * Storage: rename storage_common_resolve_path to storage_common_resolve_path_and_ensure_app_directory * Api: fix version * Storage: rename alias message * Storage: do not create app folders in path resolving process in certain cases. --------- Co-authored-by: Astra <93453568+Astrrra@users.noreply.github.com> Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
@@ -39,12 +39,6 @@
|
||||
.file = file, \
|
||||
}};
|
||||
|
||||
#define S_API_DATA_PATH \
|
||||
SAData data = { \
|
||||
.path = { \
|
||||
.path = path, \
|
||||
}};
|
||||
|
||||
#define S_RETURN_BOOL (return_data.bool_value);
|
||||
#define S_RETURN_UINT16 (return_data.uint16_value);
|
||||
#define S_RETURN_UINT64 (return_data.uint64_value);
|
||||
@@ -70,6 +64,7 @@ static bool storage_file_open_internal(
|
||||
.path = path,
|
||||
.access_mode = access_mode,
|
||||
.open_mode = open_mode,
|
||||
.thread_id = furi_thread_get_current_id(),
|
||||
}};
|
||||
|
||||
file->type = FileTypeOpenFile;
|
||||
@@ -249,7 +244,7 @@ bool storage_file_exists(Storage* storage, const char* path) {
|
||||
FileInfo fileinfo;
|
||||
FS_Error error = storage_common_stat(storage, path, &fileinfo);
|
||||
|
||||
if(error == FSE_OK && !(fileinfo.flags & FSF_DIRECTORY)) {
|
||||
if(error == FSE_OK && !file_info_is_dir(&fileinfo)) {
|
||||
exist = true;
|
||||
}
|
||||
|
||||
@@ -266,6 +261,7 @@ static bool storage_dir_open_internal(File* file, const char* path) {
|
||||
.dopen = {
|
||||
.file = file,
|
||||
.path = path,
|
||||
.thread_id = furi_thread_get_current_id(),
|
||||
}};
|
||||
|
||||
file->type = FileTypeOpenDir;
|
||||
@@ -349,12 +345,28 @@ bool storage_dir_rewind(File* file) {
|
||||
return S_RETURN_BOOL;
|
||||
}
|
||||
|
||||
bool storage_dir_exists(Storage* storage, const char* path) {
|
||||
bool exist = false;
|
||||
FileInfo fileinfo;
|
||||
FS_Error error = storage_common_stat(storage, path, &fileinfo);
|
||||
|
||||
if(error == FSE_OK && file_info_is_dir(&fileinfo)) {
|
||||
exist = true;
|
||||
}
|
||||
|
||||
return exist;
|
||||
}
|
||||
/****************** COMMON ******************/
|
||||
|
||||
FS_Error storage_common_timestamp(Storage* storage, const char* path, uint32_t* timestamp) {
|
||||
S_API_PROLOGUE;
|
||||
|
||||
SAData data = {.ctimestamp = {.path = path, .timestamp = timestamp}};
|
||||
SAData data = {
|
||||
.ctimestamp = {
|
||||
.path = path,
|
||||
.timestamp = timestamp,
|
||||
.thread_id = furi_thread_get_current_id(),
|
||||
}};
|
||||
|
||||
S_API_MESSAGE(StorageCommandCommonTimestamp);
|
||||
S_API_EPILOGUE;
|
||||
@@ -363,8 +375,12 @@ FS_Error storage_common_timestamp(Storage* storage, const char* path, uint32_t*
|
||||
|
||||
FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* fileinfo) {
|
||||
S_API_PROLOGUE;
|
||||
|
||||
SAData data = {.cstat = {.path = path, .fileinfo = fileinfo}};
|
||||
SAData data = {
|
||||
.cstat = {
|
||||
.path = path,
|
||||
.fileinfo = fileinfo,
|
||||
.thread_id = furi_thread_get_current_id(),
|
||||
}};
|
||||
|
||||
S_API_MESSAGE(StorageCommandCommonStat);
|
||||
S_API_EPILOGUE;
|
||||
@@ -373,7 +389,12 @@ FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* filei
|
||||
|
||||
FS_Error storage_common_remove(Storage* storage, const char* path) {
|
||||
S_API_PROLOGUE;
|
||||
S_API_DATA_PATH;
|
||||
SAData data = {
|
||||
.path = {
|
||||
.path = path,
|
||||
.thread_id = furi_thread_get_current_id(),
|
||||
}};
|
||||
|
||||
S_API_MESSAGE(StorageCommandCommonRemove);
|
||||
S_API_EPILOGUE;
|
||||
return S_RETURN_ERROR;
|
||||
@@ -423,7 +444,7 @@ static FS_Error
|
||||
furi_string_right(path, strlen(old_path));
|
||||
furi_string_printf(tmp_new_path, "%s%s", new_path, furi_string_get_cstr(path));
|
||||
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
if(file_info_is_dir(&fileinfo)) {
|
||||
error = storage_common_mkdir(storage, furi_string_get_cstr(tmp_new_path));
|
||||
} else {
|
||||
error = storage_common_copy(
|
||||
@@ -452,7 +473,7 @@ FS_Error storage_common_copy(Storage* storage, const char* old_path, const char*
|
||||
error = storage_common_stat(storage, old_path, &fileinfo);
|
||||
|
||||
if(error == FSE_OK) {
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
if(file_info_is_dir(&fileinfo)) {
|
||||
error = storage_copy_recursive(storage, old_path, new_path);
|
||||
} else {
|
||||
Stream* stream_from = file_stream_alloc(storage);
|
||||
@@ -479,7 +500,7 @@ FS_Error storage_common_copy(Storage* storage, const char* old_path, const char*
|
||||
|
||||
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);
|
||||
FS_Error error = FSE_OK;
|
||||
DirWalk* dir_walk = dir_walk_alloc(storage);
|
||||
FuriString *path, *file_basename, *tmp_new_path;
|
||||
FileInfo fileinfo;
|
||||
@@ -488,7 +509,7 @@ static FS_Error
|
||||
tmp_new_path = furi_string_alloc();
|
||||
|
||||
do {
|
||||
if((error != FSE_OK) && (error != FSE_EXIST)) break;
|
||||
if(!storage_simply_mkdir(storage, new_path)) break;
|
||||
|
||||
dir_walk_set_recursive(dir_walk, false);
|
||||
if(!dir_walk_open(dir_walk, old_path)) {
|
||||
@@ -508,13 +529,13 @@ static FS_Error
|
||||
path_extract_basename(furi_string_get_cstr(path), file_basename);
|
||||
path_concat(new_path, furi_string_get_cstr(file_basename), tmp_new_path);
|
||||
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
if(file_info_is_dir(&fileinfo)) {
|
||||
if(storage_common_stat(
|
||||
storage, furi_string_get_cstr(tmp_new_path), &fileinfo) == FSE_OK) {
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
if(file_info_is_dir(&fileinfo)) {
|
||||
error =
|
||||
storage_common_mkdir(storage, furi_string_get_cstr(tmp_new_path));
|
||||
if(error != FSE_OK) {
|
||||
if(error != FSE_OK && error != FSE_EXIST) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -548,7 +569,7 @@ FS_Error storage_common_merge(Storage* storage, const char* old_path, const char
|
||||
error = storage_common_stat(storage, old_path, &fileinfo);
|
||||
|
||||
if(error == FSE_OK) {
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
if(file_info_is_dir(&fileinfo)) {
|
||||
error = storage_merge_recursive(storage, old_path, new_path);
|
||||
} else {
|
||||
error = storage_common_stat(storage, new_path, &fileinfo);
|
||||
@@ -556,7 +577,7 @@ FS_Error storage_common_merge(Storage* storage, const char* old_path, const char
|
||||
furi_string_set(new_path_next, new_path);
|
||||
FuriString* dir_path;
|
||||
FuriString* filename;
|
||||
char extension[MAX_EXT_LEN];
|
||||
char extension[MAX_EXT_LEN] = {0};
|
||||
|
||||
dir_path = furi_string_alloc();
|
||||
filename = furi_string_alloc();
|
||||
@@ -608,7 +629,12 @@ FS_Error storage_common_merge(Storage* storage, const char* old_path, const char
|
||||
|
||||
FS_Error storage_common_mkdir(Storage* storage, const char* path) {
|
||||
S_API_PROLOGUE;
|
||||
S_API_DATA_PATH;
|
||||
SAData data = {
|
||||
.path = {
|
||||
.path = path,
|
||||
.thread_id = furi_thread_get_current_id(),
|
||||
}};
|
||||
|
||||
S_API_MESSAGE(StorageCommandCommonMkDir);
|
||||
S_API_EPILOGUE;
|
||||
return S_RETURN_ERROR;
|
||||
@@ -626,6 +652,7 @@ FS_Error storage_common_fs_info(
|
||||
.fs_path = fs_path,
|
||||
.total_space = total_space,
|
||||
.free_space = free_space,
|
||||
.thread_id = furi_thread_get_current_id(),
|
||||
}};
|
||||
|
||||
S_API_MESSAGE(StorageCommandCommonFSInfo);
|
||||
@@ -633,6 +660,38 @@ FS_Error storage_common_fs_info(
|
||||
return S_RETURN_ERROR;
|
||||
}
|
||||
|
||||
void storage_common_resolve_path_and_ensure_app_directory(Storage* storage, FuriString* path) {
|
||||
S_API_PROLOGUE;
|
||||
|
||||
SAData data = {
|
||||
.cresolvepath = {
|
||||
.path = path,
|
||||
.thread_id = furi_thread_get_current_id(),
|
||||
}};
|
||||
|
||||
S_API_MESSAGE(StorageCommandCommonResolvePath);
|
||||
S_API_EPILOGUE;
|
||||
}
|
||||
|
||||
FS_Error storage_common_migrate(Storage* storage, const char* source, const char* dest) {
|
||||
if(!storage_common_exists(storage, source)) {
|
||||
return FSE_OK;
|
||||
}
|
||||
|
||||
FS_Error error = storage_common_merge(storage, source, dest);
|
||||
|
||||
if(error == FSE_OK) {
|
||||
storage_simply_remove_recursive(storage, source);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
bool storage_common_exists(Storage* storage, const char* path) {
|
||||
FileInfo file_info;
|
||||
return storage_common_stat(storage, path, &file_info) == FSE_OK;
|
||||
}
|
||||
|
||||
/****************** ERROR ******************/
|
||||
|
||||
const char* storage_error_get_desc(FS_Error error_id) {
|
||||
@@ -750,7 +809,7 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path) {
|
||||
}
|
||||
|
||||
while(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) {
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
if(file_info_is_dir(&fileinfo)) {
|
||||
furi_string_cat_printf(cur_dir, "/%s", name);
|
||||
go_deeper = true;
|
||||
break;
|
||||
|
Reference in New Issue
Block a user