mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-10 05:59:08 -07:00
Merge remote-tracking branch 'ofw/dev' into mntm-dev --nobuild
This commit is contained in:
@@ -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 *******************/
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -77,7 +77,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
const char* path1;
|
||||
const char* path2;
|
||||
bool truncate;
|
||||
bool check_subdir;
|
||||
FuriThreadId thread_id;
|
||||
} SADataCEquivPath;
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user