Fix BLI_path_parent_dir failing on paths ending with ".."
The check for BLI_path_normalize having succeeded only checked for a trailing "../" which isn't correct. This caused going up a directory in the file selector to do nothing on directories ending with "..". This also caused an empty path to expand into "../" because BLI_path_extension_check didn't account for this case. Resolve using BLI_path_name_at_index which extracts the last component of the path without having to match the the surrounding slashes.
This commit is contained in:
parent
12f4ac1706
commit
cc6f41f8a5
@ -364,6 +364,8 @@ bool BLI_path_make_safe(char *path) ATTR_NONNULL(1);
|
||||
*
|
||||
* Replaces path with the path of its parent directory, returning true if
|
||||
* it was able to find a parent directory within the path.
|
||||
*
|
||||
* On success, the resulting path will always have a trailing slash.
|
||||
*/
|
||||
bool BLI_path_parent_dir(char *path) ATTR_NONNULL();
|
||||
/**
|
||||
|
@ -630,14 +630,28 @@ bool BLI_path_parent_dir(char *path)
|
||||
char tmp[FILE_MAX + 4];
|
||||
|
||||
BLI_path_join(tmp, sizeof(tmp), path, parent_dir);
|
||||
BLI_path_normalize(NULL, tmp); /* does all the work of normalizing the path for us */
|
||||
/* Does all the work of normalizing the path for us.
|
||||
*
|
||||
* NOTE(@campbellbarton): While it's possible strip text after the second last slash,
|
||||
* this would have to be clever and skip cases like "/./" & multiple slashes.
|
||||
* Since this ends up solving some of the same problems as #BLI_path_normalize,
|
||||
* call this function instead of attempting to handle them separately. */
|
||||
BLI_path_normalize(NULL, tmp);
|
||||
|
||||
if (!BLI_path_extension_check(tmp, parent_dir)) {
|
||||
strcpy(path, tmp); /* We assume the parent directory is always shorter. */
|
||||
return true;
|
||||
/* Use #BLI_path_name_at_index instead of checking if the strings ends with `parent_dir`
|
||||
* to ensure the logic isn't confused by:
|
||||
* - Directory names that happen to end with `..`.
|
||||
* - When `path` is empty, the contents will be `../`
|
||||
* which would cause checking for a tailing `/../` fail.
|
||||
* Extracting the span of the final directory avoids both these issues. */
|
||||
int tail_ofs = 0, tail_len = 0;
|
||||
if (BLI_path_name_at_index(tmp, -1, &tail_ofs, &tail_len) && (tail_len == 2) &&
|
||||
(memcmp(&tmp[tail_ofs], "..", 2) == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
strcpy(path, tmp); /* We assume the parent directory is always shorter. */
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BLI_path_parent_dir_until_exists(char *dir)
|
||||
|
@ -75,6 +75,17 @@ TEST(path_util, ParentDir)
|
||||
PARENT_DIR("/a/b", "/a/");
|
||||
PARENT_DIR("/a", "/");
|
||||
PARENT_DIR("/", "/");
|
||||
PARENT_DIR("", "");
|
||||
|
||||
/* Ensure trailing dots aren't confused with parent path. */
|
||||
PARENT_DIR("/.../.../.../", "/.../.../");
|
||||
PARENT_DIR("/.../.../...", "/.../.../");
|
||||
|
||||
PARENT_DIR("/a../b../c../", "/a../b../");
|
||||
PARENT_DIR("/a../b../c..", "/a../b../");
|
||||
|
||||
PARENT_DIR("/a./b./c./", "/a./b./");
|
||||
PARENT_DIR("/a./b./c.", "/a./b./");
|
||||
|
||||
# undef PARENT_DIR
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user