summaryrefslogtreecommitdiff
path: root/src/basic/path-util.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-05-02 05:53:14 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-05-28 13:41:23 +0900
commitfe69c41ee80920714b13c958cb180cce03f4098e (patch)
treed234fc6073e90dde4d282f2efbb2653e2790f8eb /src/basic/path-util.c
parent63f11e354a3e5d64ee4cabb7bb584307d237fee4 (diff)
downloadsystemd-fe69c41ee80920714b13c958cb180cce03f4098e.tar.gz
path-util: use path_find_first_component() in path_make_relative()
This also makes the function checks the result is a valid path or not.
Diffstat (limited to 'src/basic/path-util.c')
-rw-r--r--src/basic/path-util.c123
1 files changed, 63 insertions, 60 deletions
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index aa65e2950f..6cfad9efe6 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -107,93 +107,96 @@ int path_make_absolute_cwd(const char *p, char **ret) {
return 0;
}
-int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
- char *f, *t, *r, *p;
- unsigned n_parents = 0;
-
- assert(from_dir);
- assert(to_path);
- assert(_r);
+int path_make_relative(const char *from, const char *to, char **ret) {
+ _cleanup_free_ char *result = NULL;
+ unsigned n_parents;
+ const char *f, *t;
+ int r, k;
+ char *p;
+
+ assert(from);
+ assert(to);
+ assert(ret);
/* Strips the common part, and adds ".." elements as necessary. */
- if (!path_is_absolute(from_dir) || !path_is_absolute(to_path))
+ if (!path_is_absolute(from) || !path_is_absolute(to))
return -EINVAL;
- f = strdupa(from_dir);
- t = strdupa(to_path);
-
- path_simplify(f, true);
- path_simplify(t, true);
-
- /* Skip the common part. */
for (;;) {
- size_t a, b;
+ r = path_find_first_component(&from, true, &f);
+ if (r < 0)
+ return r;
+
+ k = path_find_first_component(&to, true, &t);
+ if (k < 0)
+ return k;
+
+ if (r == 0) {
+ /* end of 'from' */
+ if (k == 0) {
+ /* from and to are equivalent. */
+ result = strdup(".");
+ if (!result)
+ return -ENOMEM;
+ } else {
+ /* 'to' is inside of 'from'. */
+ result = strdup(t);
+ if (!result)
+ return -ENOMEM;
- f += *f == '/';
- t += *t == '/';
+ path_simplify(result, true);
- if (!*f) {
- if (!*t)
- /* from_dir equals to_path. */
- r = strdup(".");
- else
- /* from_dir is a parent directory of to_path. */
- r = strdup(t);
- if (!r)
- return -ENOMEM;
+ if (!path_is_valid(result))
+ return -EINVAL;
+ }
- *_r = r;
+ *ret = TAKE_PTR(result);
return 0;
}
- if (!*t)
- break;
-
- a = strcspn(f, "/");
- b = strcspn(t, "/");
-
- if (a != b || memcmp(f, t, a) != 0)
+ if (r != k || !strneq(f, t, r))
break;
-
- f += a;
- t += b;
}
/* If we're here, then "from_dir" has one or more elements that need to
* be replaced with "..". */
- /* Count the number of necessary ".." elements. */
- for (; *f;) {
- size_t w;
+ for (n_parents = 1;; n_parents++) {
+ /* If this includes ".." we can't do a simple series of "..". */
+ r = path_find_first_component(&from, false, &f);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+ }
- w = strcspn(f, "/");
+ if (isempty(t) && n_parents * 3 > PATH_MAX)
+ /* PATH_MAX is counted *with* the trailing NUL byte */
+ return -EINVAL;
- /* If this includes ".." we can't do a simple series of "..", refuse */
- if (w == 2 && f[0] == '.' && f[1] == '.')
- return -EINVAL;
+ result = new(char, n_parents * 3 + !isempty(t) + strlen_ptr(t));
+ if (!result)
+ return -ENOMEM;
- /* Count number of elements */
- n_parents++;
+ for (p = result; n_parents > 0; n_parents--)
+ p = mempcpy(p, "../", 3);
- f += w;
- f += *f == '/';
+ if (isempty(t)) {
+ /* Remove trailing slash and terminate string. */
+ *(--p) = '\0';
+ *ret = TAKE_PTR(result);
+ return 0;
}
- r = new(char, n_parents * 3 + strlen(t) + 1);
- if (!r)
- return -ENOMEM;
+ strcpy(p, t);
- for (p = r; n_parents > 0; n_parents--)
- p = mempcpy(p, "../", 3);
+ path_simplify(result, true);
- if (*t)
- strcpy(p, t);
- else
- /* Remove trailing slash */
- *(--p) = 0;
+ if (!path_is_valid(result))
+ return -EINVAL;
- *_r = r;
+ *ret = TAKE_PTR(result);
return 0;
}