summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/basic/cgroup-util.c10
-rw-r--r--src/basic/fileio.c6
-rw-r--r--src/basic/mount-util.c2
-rw-r--r--src/basic/path-util.c55
-rw-r--r--src/basic/path-util.h6
-rw-r--r--src/basic/unit-name.c2
-rw-r--r--src/core/cgroup.c2
-rw-r--r--src/shared/conf-parser.c3
-rw-r--r--src/test/test-path-util.c41
9 files changed, 84 insertions, 43 deletions
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 0570e9abf..63117afb1 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -634,7 +634,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
if (!t)
return -ENOMEM;
- *fs = path_kill_slashes(t);
+ *fs = path_simplify(t, false);
return 0;
}
@@ -651,7 +651,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
if (r < 0)
return r;
- path_kill_slashes(*fs);
+ path_simplify(*fs, false);
return 0;
}
@@ -1267,7 +1267,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
if (!t)
return -ENOMEM;
- *path = path_kill_slashes(t);
+ *path = path_simplify(t, false);
}
if (controller)
@@ -1319,7 +1319,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
return -EINVAL;
}
- path_kill_slashes(u);
+ path_simplify(u, false);
}
if (controller)
@@ -1350,7 +1350,7 @@ int cg_mangle_path(const char *path, char **result) {
if (!t)
return -ENOMEM;
- *result = path_kill_slashes(t);
+ *result = path_simplify(t, false);
return 0;
}
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 859298ff0..245402f6d 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -1240,7 +1240,7 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
- *ret = path_kill_slashes(t);
+ *ret = path_simplify(t, false);
return 0;
}
@@ -1281,7 +1281,7 @@ int tempfn_random(const char *p, const char *extra, char **ret) {
*x = 0;
- *ret = path_kill_slashes(t);
+ *ret = path_simplify(t, false);
return 0;
}
@@ -1322,7 +1322,7 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
*x = 0;
- *ret = path_kill_slashes(t);
+ *ret = path_simplify(t, false);
return 0;
}
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index 9d1f34e08..76c0969d4 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -414,7 +414,7 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl
if (!cleaned)
return -ENOMEM;
- path_kill_slashes(cleaned);
+ path_simplify(cleaned, false);
done = set_new(&path_hash_ops);
if (!done)
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 957c13bb3..eb91adf5b 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -162,7 +162,7 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
if (!r)
return -ENOMEM;
- path_kill_slashes(r);
+ path_simplify(r, false);
*_r = r;
return 0;
@@ -217,7 +217,7 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
p = mempcpy(p, "../", 3);
strcpy(p, to_path);
- path_kill_slashes(r);
+ path_simplify(r, false);
*_r = r;
return 0;
@@ -238,7 +238,7 @@ int path_strv_make_absolute_cwd(char **l) {
if (r < 0)
return r;
- path_kill_slashes(t);
+ path_simplify(t, false);
free_and_replace(*s, t);
}
@@ -339,17 +339,30 @@ char **path_strv_resolve_uniq(char **l, const char *root) {
return strv_uniq(l);
}
-char *path_kill_slashes(char *path) {
+char *path_simplify(char *path, bool kill_dots) {
char *f, *t;
- bool slash = false;
+ bool slash = false, ignore_slash = false, absolute;
- /* Removes redundant inner and trailing slashes. Modifies the
- * passed string in-place.
+ assert(path);
+
+ /* Removes redundant inner and trailing slashes. Also removes unnecessary dots
+ * if kill_dots is true. Modifies the passed string in-place.
*
- * ///foo///bar/ becomes /foo/bar
+ * ///foo//./bar/. becomes /foo/./bar/. (if kill_dots is false)
+ * ///foo//./bar/. becomes /foo/bar (if kill_dots is true)
+ * .//./foo//./bar/. becomes ./foo/bar (if kill_dots is false)
+ * .//./foo//./bar/. becomes foo/bar (if kill_dots is true)
*/
- for (f = path, t = path; *f; f++) {
+ absolute = path_is_absolute(path);
+
+ f = path;
+ if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/')) {
+ ignore_slash = true;
+ f++;
+ }
+
+ for (t = path; *f; f++) {
if (*f == '/') {
slash = true;
@@ -357,17 +370,21 @@ char *path_kill_slashes(char *path) {
}
if (slash) {
+ if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/'))
+ continue;
+
slash = false;
- *(t++) = '/';
+ if (ignore_slash)
+ ignore_slash = false;
+ else
+ *(t++) = '/';
}
*(t++) = *f;
}
- /* Special rule, if we are talking of the root directory, a
- trailing slash is good */
-
- if (t == path && slash)
+ /* Special rule, if we are talking of the root directory, a trailing slash is good */
+ if (absolute && t == path)
*(t++) = '/';
*t = 0;
@@ -534,7 +551,7 @@ int find_binary(const char *name, char **ret) {
/* Found it! */
if (ret) {
- *ret = path_kill_slashes(j);
+ *ret = path_simplify(j, false);
j = NULL;
}
@@ -691,12 +708,12 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar
if (r < 0)
return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
- path_kill_slashes(p);
- if (suppress_root && path_equal(p, "/"))
+ path_simplify(p, false);
+ if (suppress_root && empty_or_root(p))
p = mfree(p);
- free(*arg);
- *arg = p;
+ free_and_replace(*arg, p);
+
return 0;
}
#endif // 0
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index e1f22ed97..4fabe06e6 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -56,12 +56,12 @@ int path_make_absolute_cwd(const char *p, char **ret);
#if 0 /// UNNEEDED by elogind
int path_make_relative(const char *from_dir, const char *to_path, char **_r);
#endif // 0
-char* path_kill_slashes(char *path);
char* path_startswith(const char *path, const char *prefix) _pure_;
int path_compare(const char *a, const char *b) _pure_;
bool path_equal(const char *a, const char *b) _pure_;
bool path_equal_or_files_same(const char *a, const char *b, int flags);
char* path_join(const char *root, const char *path, const char *rest);
+char* path_simplify(char *path, bool kill_dots);
static inline bool path_equal_ptr(const char *a, const char *b) {
return !!a == !!b && (!a || path_equal(a, b));
@@ -111,11 +111,11 @@ int mkfs_exists(const char *fstype);
* the tree, to root. Also returns "" (and not "/"!) for the root
* directory. Excludes the specified directory itself */
#define PATH_FOREACH_PREFIX(prefix, path) \
- for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
+ for (char *_slash = ({ path_simplify(strcpy(prefix, path), false); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
/* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */
#define PATH_FOREACH_PREFIX_MORE(prefix, path) \
- for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
+ for (char *_slash = ({ path_simplify(strcpy(prefix, path), false); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
char *prefix_root(const char *root, const char *path);
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
index 113d9bb10..12323fb4d 100644
--- a/src/basic/unit-name.c
+++ b/src/basic/unit-name.c
@@ -388,7 +388,7 @@ int unit_name_path_escape(const char *f, char **ret) {
if (!p)
return -ENOMEM;
- path_kill_slashes(p);
+ path_simplify(p, false);
if (empty_or_root(p))
s = strdup("-");
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index a1e66864b..1c8245e0b 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -1520,7 +1520,7 @@ static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suf
return -EINVAL;
pp = strjoina("/", pp, suffix_path);
- path_kill_slashes(pp);
+ path_simplify(pp, false);
r = sd_bus_call_method(u->manager->system_bus,
"org.freedesktop.systemd1",
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index eeb93e284..899711e54 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -41,6 +41,7 @@
//#include "rlimit-util.h"
//#include "rlimit-util.h"
//#include "rlimit-util.h"
+//#include "rlimit-util.h"
int config_item_table_lookup(
const void *table,
@@ -757,7 +758,7 @@ int config_parse_path(
if (!n)
return log_oom();
- path_kill_slashes(n);
+ path_simplify(n, false);
finalize:
free(*s);
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index e7a247027..80bca48e0 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -26,6 +26,16 @@
assert_se(path_equal(b, a) == !result); \
}
+static void test_path_simplify(const char *in, const char *out, const char *out_dot) {
+ char *p;
+
+ p = strdupa(in);
+ assert_se(streq(path_simplify(p, false), out));
+
+ p = strdupa(in);
+ assert_se(streq(path_simplify(p, true), out_dot));
+}
+
static void test_path(void) {
_cleanup_close_ int fd = -1;
@@ -69,15 +79,28 @@ static void test_path(void) {
assert_se(fd >= 0);
assert_se(fd_is_mount_point(fd, "/", 0) > 0);
- {
- char p1[] = "aaa/bbb////ccc";
- char p2[] = "//aaa/.////ccc";
- char p3[] = "/./";
-
- assert_se(path_equal(path_kill_slashes(p1), "aaa/bbb/ccc"));
- assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc"));
- assert_se(path_equal(path_kill_slashes(p3), "/./"));
- }
+ test_path_simplify("aaa/bbb////ccc", "aaa/bbb/ccc", "aaa/bbb/ccc");
+ test_path_simplify("//aaa/.////ccc", "/aaa/./ccc", "/aaa/ccc");
+ test_path_simplify("///", "/", "/");
+ test_path_simplify("///.//", "/.", "/");
+ test_path_simplify("///.//.///", "/./.", "/");
+ test_path_simplify("////.././///../.", "/.././../.", "/../..");
+ test_path_simplify(".", ".", "");
+ test_path_simplify("./", ".", "");
+ test_path_simplify(".///.//./.", "./././.", "");
+ test_path_simplify(".///.//././/", "./././.", "");
+ test_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.",
+ "/./aaa/././.bbb/../c./d.dd/..eeee/.",
+ "/aaa/.bbb/../c./d.dd/..eeee");
+ test_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
+ "/./aaa/././.bbb/../c./d.dd/..eeee/..",
+ "/aaa/.bbb/../c./d.dd/..eeee/..");
+ test_path_simplify(".//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
+ "././aaa/././.bbb/../c./d.dd/..eeee/..",
+ "aaa/.bbb/../c./d.dd/..eeee/..");
+ test_path_simplify("..//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
+ ".././aaa/././.bbb/../c./d.dd/..eeee/..",
+ "../aaa/.bbb/../c./d.dd/..eeee/..");
assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo"));
assert_se(PATH_IN_SET("/bin", "/bin"));