Merge remote-tracking branch 'ofw/dev' into mntm-dev --nobuild

This commit is contained in:
Willy-JL
2024-09-17 21:51:54 +01:00
9 changed files with 126 additions and 47 deletions

View File

@@ -428,21 +428,26 @@ bool storage_common_exists(Storage* storage, const char* path);
* - /int/Test and /int/test -> false (Case-sensitive storage),
* - /ext/Test and /ext/test -> true (Case-insensitive storage).
*
* If the truncate parameter is set to true, the second path will be
* truncated to be no longer than the first one. It is useful to determine
* whether path2 is a subdirectory of path1.
*
* @param storage pointer to a storage API instance.
* @param path1 pointer to a zero-terminated string containing the first path.
* @param path2 pointer to a zero-terminated string containing the second path.
* @param truncate whether to truncate path2 to be no longer than path1.
* @return true if paths are equivalent, false otherwise.
*/
bool storage_common_equivalent_path(
Storage* storage,
const char* path1,
const char* path2,
bool truncate);
bool storage_common_equivalent_path(Storage* storage, const char* path1, const char* path2);
/**
* @brief Check whether a path is a subpath of another path.
*
* This function respects storage-defined equivalence rules
* (see `storage_common_equivalent_path`).
*
* @param storage pointer to a storage API instance.
* @param parent pointer to a zero-terminated string containing the parent path.
* @param child pointer to a zero-terminated string containing the child path.
* @return true if `child` is a subpath of `parent`, or if `child` is equivalent
* to `parent`; false otherwise.
*/
bool storage_common_is_subdir(Storage* storage, const char* parent, const char* child);
/******************* Error Functions *******************/

View File

@@ -507,13 +507,13 @@ FS_Error storage_common_rename(Storage* storage, const char* old_path, const cha
}
// Cannot rename a directory to itself or to a nested directory
if(storage_common_equivalent_path(storage, old_path, new_path, true)) {
if(storage_common_is_subdir(storage, old_path, new_path)) {
error = FSE_INVALID_NAME;
break;
}
// Renaming a regular file to itself does nothing and always succeeds
} else if(storage_common_equivalent_path(storage, old_path, new_path, false)) {
} else if(storage_common_equivalent_path(storage, old_path, new_path)) {
error = FSE_OK;
break;
}
@@ -567,13 +567,13 @@ FS_Error storage_common_rename_safe(Storage* storage, const char* old_path, cons
if(storage_dir_exists(storage, old_path)) {
// Cannot rename a directory to itself or to a nested directory
if(storage_common_equivalent_path(storage, old_path, new_path, true)) {
if(storage_common_is_subdir(storage, old_path, new_path)) {
error = FSE_INVALID_NAME;
break;
}
// Renaming a regular file to itself does nothing and always succeeds
} else if(storage_common_equivalent_path(storage, old_path, new_path, false)) {
} else if(storage_common_equivalent_path(storage, old_path, new_path)) {
error = FSE_OK;
break;
}
@@ -608,7 +608,7 @@ FS_Error storage_common_rename_safe(Storage* storage, const char* old_path, cons
static FS_Error
storage_copy_recursive(Storage* storage, const char* old_path, const char* new_path) {
if(storage_common_equivalent_path(storage, old_path, new_path, true)) {
if(storage_common_is_subdir(storage, old_path, new_path)) {
return FSE_INVALID_NAME;
}
@@ -927,11 +927,11 @@ bool storage_common_exists(Storage* storage, const char* path) {
return storage_common_stat(storage, path, &file_info) == FSE_OK;
}
bool storage_common_equivalent_path(
static bool storage_internal_equivalent_path(
Storage* storage,
const char* path1,
const char* path2,
bool truncate) {
bool check_subdir) {
furi_check(storage);
S_API_PROLOGUE;
@@ -940,7 +940,7 @@ bool storage_common_equivalent_path(
.cequivpath = {
.path1 = path1,
.path2 = path2,
.truncate = truncate,
.check_subdir = check_subdir,
.thread_id = furi_thread_get_current_id(),
}};
@@ -950,6 +950,14 @@ bool storage_common_equivalent_path(
return S_RETURN_BOOL;
}
bool storage_common_equivalent_path(Storage* storage, const char* path1, const char* path2) {
return storage_internal_equivalent_path(storage, path1, path2, false);
}
bool storage_common_is_subdir(Storage* storage, const char* parent, const char* child) {
return storage_internal_equivalent_path(storage, parent, child, true);
}
/****************** ERROR ******************/
const char* storage_error_get_desc(FS_Error error_id) {

View File

@@ -77,7 +77,7 @@ typedef struct {
typedef struct {
const char* path1;
const char* path2;
bool truncate;
bool check_subdir;
FuriThreadId thread_id;
} SADataCEquivPath;

View File

@@ -757,11 +757,23 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) {
storage_path_trim_trailing_slashes(path2);
storage_process_alias(app, path1, message->data->cequivpath.thread_id, false);
storage_process_alias(app, path2, message->data->cequivpath.thread_id, false);
// Comparison is done on path name, same beginning of name != same file/folder
// Check with a / suffixed to ensure same file/folder name
furi_string_cat(path1, "/");
furi_string_cat(path2, "/");
if(message->data->cequivpath.truncate) {
if(message->data->cequivpath.check_subdir) {
// by appending slashes at the end and then truncating the second path, we can
// effectively check for shared path components:
// example 1:
// path1: "/ext/blah" -> "/ext/blah/" -> "/ext/blah/"
// path2: "/ext/blah-blah" -> "/ect/blah-blah/" -> "/ext/blah-"
// results unequal, conclusion: path2 is not a subpath of path1
// example 2:
// path1: "/ext/blah" -> "/ext/blah/" -> "/ext/blah/"
// path2: "/ext/blah/blah" -> "/ect/blah/blah/" -> "/ext/blah/"
// results equal, conclusion: path2 is a subpath of path1
// example 3:
// path1: "/ext/blah/blah" -> "/ect/blah/blah/" -> "/ext/blah/blah/"
// path2: "/ext/blah" -> "/ext/blah/" -> "/ext/blah/"
// results unequal, conclusion: path2 is not a subpath of path1
furi_string_push_back(path1, '/');
furi_string_push_back(path2, '/');
furi_string_left(path2, furi_string_size(path1));
}
message->return_data->bool_value =