]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
path-util: introduce path_make_relative_parent()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 10 Apr 2022 22:01:59 +0000 (07:01 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 2 Sep 2022 20:01:51 +0000 (05:01 +0900)
src/basic/path-util.c
src/basic/path-util.h
src/test/test-path-util.c

index 338377d9183094a66267094a4cd42da3875ae00c..41e0d4d753a025a544e069acf320637c8eaf964a 100644 (file)
@@ -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;
index 41bbc7bb86f0a6c0175579f91f55ea81e52cf04a..8cd7f512a6588b9f1b058556152ef328f0bc5d4e 100644 (file)
@@ -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);
index e0583cfbaba762ce1ff375691a16053ea72521e0..a26e3512337123ae578f4a8e6856ba6f610216c9 100644 (file)
@@ -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;