}
char* path_simplify_full(char *path, PathSimplifyFlags flags) {
- bool add_slash = false, keep_trailing_slash;
+ bool add_slash = false, keep_trailing_slash, absolute, beginning = true;
char *f = ASSERT_PTR(path);
int r;
*
* ///foo//./bar/. becomes /foo/bar
* .//./foo//./bar/. becomes foo/bar
+ * /../foo/bar becomes /foo/bar
+ * /../foo/bar/.. becomes /foo/bar/..
*/
if (isempty(path))
keep_trailing_slash = FLAGS_SET(flags, PATH_SIMPLIFY_KEEP_TRAILING_SLASH) && endswith(path, "/");
- if (path_is_absolute(path))
- f++;
+ absolute = path_is_absolute(path);
+ f += absolute; /* Keep leading /, if present. */
for (const char *p = f;;) {
const char *e;
if (r == 0)
break;
+ if (r > 0 && absolute && beginning && path_startswith(e, ".."))
+ /* If we're at the beginning of an absolute path, we can safely skip ".." */
+ continue;
+
+ beginning = false;
+
if (add_slash)
*f++ = '/';
if (r < 0) {
- /* if path is invalid, then refuse to simplify remaining part. */
+ /* if path is invalid, then refuse to simplify the remaining part. */
memmove(f, p, strlen(p) + 1);
return path;
}
test_path_simplify_one("///", "/", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
test_path_simplify_one("///.//", "/", 0);
test_path_simplify_one("///.//.///", "/", 0);
- test_path_simplify_one("////.././///../.", "/../..", 0);
+ test_path_simplify_one("////.././///../.", "/", 0);
test_path_simplify_one(".", ".", 0);
test_path_simplify_one("./", ".", 0);
test_path_simplify_one("./", "./", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
"../aaa/.bbb/../c./d.dd/..eeee/..", 0);
test_path_simplify_one("abc///", "abc/", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../abc", "/abc", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../abc///", "/abc/", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../abc///", "/abc", 0);
+ test_path_simplify_one("/../abc", "/abc", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../abc///..", "/abc/..", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../abc///../", "/abc/../", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../abc///../", "/abc/..", 0);
+
+ test_path_simplify_one("/../../abc", "/abc", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../../abc///", "/abc/", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../../abc///", "/abc", 0);
+ test_path_simplify_one("/../../abc", "/abc", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../../abc///../..", "/abc/../..", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../../abc///../../", "/abc/../../", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/../../abc///../../", "/abc/../..", 0);
+
+ test_path_simplify_one("/.././../abc", "/abc", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/.././../abc///", "/abc/", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/.././../abc///", "/abc", 0);
+ test_path_simplify_one("/.././../abc", "/abc", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/.././../abc///../..", "/abc/../..", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/.././../abc///../../", "/abc/../../", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/.././../abc///../../", "/abc/../..", 0);
+
+ test_path_simplify_one("/./.././../abc", "/abc", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/./.././../abc///", "/abc/", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/./.././../abc///", "/abc", 0);
+ test_path_simplify_one("/./.././../abc", "/abc", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/./.././../abc///../..", "/abc/../..", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/./.././../abc///../../", "/abc/../../", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/./.././../abc///../../", "/abc/../..", 0);
+
+ test_path_simplify_one("/.../abc", "/.../abc", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/.../abc///", "/.../abc/", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/.../abc///", "/.../abc", 0);
+ test_path_simplify_one("/.../abc", "/.../abc", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/.../abc///...", "/.../abc/...", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/.../abc///.../", "/.../abc/.../", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
+ test_path_simplify_one("/.../abc///.../", "/.../abc/...", 0);
+
memset(foo, 'a', sizeof(foo) -1);
char_array_0(foo);