From: Yu Watanabe Date: Sun, 10 Apr 2022 22:01:59 +0000 (+0900) Subject: path-util: introduce path_make_relative_parent() X-Git-Tag: v252-rc1~207^2~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d4f60bdc11d8e6275922ca5c7f80b130ebbb3d5f;p=thirdparty%2Fsystemd.git path-util: introduce path_make_relative_parent() --- diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 338377d9183..41e0d4d753a 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -193,6 +193,24 @@ int path_make_relative(const char *from, const char *to, char **ret) { return 0; } +int path_make_relative_parent(const char *from_child, const char *to, char **ret) { + _cleanup_free_ char *from = NULL; + int r; + + assert(from_child); + assert(to); + assert(ret); + + /* Similar to path_make_relative(), but provides the relative path from the parent directory of + * 'from_child'. This may be useful when creating relative symlink. */ + + r = path_extract_directory(from_child, &from); + if (r < 0) + return r; + + return path_make_relative(from, to, ret); +} + char* path_startswith_strv(const char *p, char **set) { STRV_FOREACH(s, set) { char *t; diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 41bbc7bb86f..8cd7f512a65 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -61,6 +61,7 @@ char* path_make_absolute(const char *p, const char *prefix); int safe_getcwd(char **ret); int path_make_absolute_cwd(const char *p, char **ret); int path_make_relative(const char *from, const char *to, char **ret); +int path_make_relative_parent(const char *from_child, const char *to, char **ret); char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_; static inline char* path_startswith(const char *path, const char *prefix) { return path_startswith_full(path, prefix, true); diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index e0583cfbaba..a26e3512337 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -477,6 +477,33 @@ TEST(path_make_relative) { test_path_make_relative_one("//extra.//.//./.slashes//./won't////fo.ol///anybody//", "/././/extra././/.slashes////ar.e/.just/././.fine///", "../../../ar.e/.just/.fine"); } +static void test_path_make_relative_parent_one(const char *from, const char *to, const char *expected) { + _cleanup_free_ char *z = NULL; + int r; + + log_info("/* %s(%s, %s) */", __func__, from, to); + + r = path_make_relative_parent(from, to, &z); + assert_se((r >= 0) == !!expected); + assert_se(streq_ptr(z, expected)); +} + +TEST(path_make_relative_parent) { + test_path_make_relative_parent_one("some/relative/path/hoge", "/some/path", NULL); + test_path_make_relative_parent_one("/some/path/hoge", "some/relative/path", NULL); + test_path_make_relative_parent_one("/some/dotdot/../path/hoge", "/some/path", NULL); + test_path_make_relative_parent_one("/", "/aaa", NULL); + + test_path_make_relative_parent_one("/hoge", "/", "."); + test_path_make_relative_parent_one("/hoge", "/some/path", "some/path"); + test_path_make_relative_parent_one("/some/path/hoge", "/some/path", "."); + test_path_make_relative_parent_one("/some/path/hoge", "/some/path/in/subdir", "in/subdir"); + test_path_make_relative_parent_one("/some/path/hoge", "/", "../.."); + test_path_make_relative_parent_one("/some/path/hoge", "/some/other/path", "../other/path"); + test_path_make_relative_parent_one("/some/path/./dot/hoge", "/some/further/path", "../../further/path"); + test_path_make_relative_parent_one("//extra.//.//./.slashes//./won't////fo.ol///anybody//hoge", "/././/extra././/.slashes////ar.e/.just/././.fine///", "../../../ar.e/.just/.fine"); +} + TEST(path_strv_resolve) { char tmp_dir[] = "/tmp/test-path-util-XXXXXX"; _cleanup_strv_free_ char **search_dirs = NULL;