diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2018-06-03 16:54:32 +0200 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2018-06-03 16:54:32 +0200 |
commit | 48054262798c0feb70b0044091105020bb5d1bfc (patch) | |
tree | d7fe02c6c608ee625a4a37b5f6142ecbe549c7ac /src/basic | |
parent | path-util: introduce path_simplify() (diff) | |
download | systemd-48054262798c0feb70b0044091105020bb5d1bfc.tar.xz systemd-48054262798c0feb70b0044091105020bb5d1bfc.zip |
path-util: make path_make_relative() support path including dots
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/path-util.c | 68 |
1 files changed, 32 insertions, 36 deletions
diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 769417c6a9..00c30f35f1 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -127,8 +127,8 @@ int path_make_absolute_cwd(const char *p, char **ret) { } int path_make_relative(const char *from_dir, const char *to_path, char **_r) { - char *r, *p; - unsigned n_parents; + char *f, *t, *r, *p; + unsigned n_parents = 0; assert(from_dir); assert(to_path); @@ -136,85 +136,81 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) { /* Strips the common part, and adds ".." elements as necessary. */ - if (!path_is_absolute(from_dir)) + if (!path_is_absolute(from_dir) || !path_is_absolute(to_path)) return -EINVAL; - if (!path_is_absolute(to_path)) - 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; - from_dir += strspn(from_dir, "/"); - to_path += strspn(to_path, "/"); + f += *f == '/'; + t += *t == '/'; - if (!*from_dir) { - if (!*to_path) + if (!*f) { + if (!*t) /* from_dir equals to_path. */ r = strdup("."); else /* from_dir is a parent directory of to_path. */ - r = strdup(to_path); + r = strdup(t); if (!r) return -ENOMEM; - path_simplify(r, false); - *_r = r; return 0; } - if (!*to_path) + if (!*t) break; - a = strcspn(from_dir, "/"); - b = strcspn(to_path, "/"); - - if (a != b) - break; + a = strcspn(f, "/"); + b = strcspn(t, "/"); - if (memcmp(from_dir, to_path, a) != 0) + if (a != b || memcmp(f, t, a) != 0) break; - from_dir += a; - to_path += b; + 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 (n_parents = 0;;) { + for (; *f;) { size_t w; - from_dir += strspn(from_dir, "/"); - - if (!*from_dir) - break; - - w = strcspn(from_dir, "/"); + w = strcspn(f, "/"); /* If this includes ".." we can't do a simple series of "..", refuse */ - if (w == 2 && from_dir[0] == '.' && from_dir[1] == '.') + if (w == 2 && f[0] == '.' && f[1] == '.') return -EINVAL; - /* Count number of elements, except if they are "." */ - if (w != 1 || from_dir[0] != '.') - n_parents++; + /* Count number of elements */ + n_parents++; - from_dir += w; + f += w; + f += *f == '/'; } - r = new(char, n_parents * 3 + strlen(to_path) + 1); + r = new(char, n_parents * 3 + strlen(t) + 1); if (!r) return -ENOMEM; for (p = r; n_parents > 0; n_parents--) p = mempcpy(p, "../", 3); - strcpy(p, to_path); - path_simplify(r, false); + if (*t) + strcpy(p, t); + else + /* Remove trailing slash */ + *(--p) = 0; *_r = r; return 0; |