chiark / gitweb /
util: add generic calls for prefixing a root directory to a path
authorLennart Poettering <lennart@poettering.net>
Wed, 13 May 2015 15:42:10 +0000 (17:42 +0200)
committerSven Eden <yamakuzure@gmx.net>
Tue, 14 Mar 2017 08:56:08 +0000 (09:56 +0100)
So far a number of utilities implemented their own calls for this, unify
them in prefix_root() and prefix_roota(). The former uses heap memory,
the latter allocates from the stack via alloca().

Port over most users of a --root= logic.

src/shared/conf-files.c
src/shared/path-util.c
src/shared/path-util.h

index 9ab08355e35cff0819462d4b2494d995643ff5d5..da8745b284d7462d9a3a03297b0784aff9bf09ce 100644 (file)
 
 static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
         _cleanup_closedir_ DIR *dir = NULL;
-        char *dirpath;
+        const char *dirpath;
+        int r;
 
         assert(path);
         assert(suffix);
 
-        dirpath = strjoina(root ? root : "", path);
+        dirpath = prefix_roota(root, path);
 
         dir = opendir(dirpath);
         if (!dir) {
@@ -53,7 +54,6 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
         for (;;) {
                 struct dirent *de;
                 char *p;
-                int r;
 
                 errno = 0;
                 de = readdir(dir);
index 635ce33b234a55a54d3ca4f5f10a9d3b08198669..7090989fcba21015b4638e49eeac894702a4b338 100644 (file)
@@ -793,3 +793,37 @@ int fsck_exists(const char *fstype) {
 
         return 0;
 }
+
+char *prefix_root(const char *root, const char *path) {
+        char *n, *p;
+        size_t l;
+
+        /* If root is passed, prefixes path with it. Otherwise returns
+         * it as is. */
+
+        assert(path);
+
+        /* First, drop duplicate prefixing slashes from the path */
+        while (path[0] == '/' && path[1] == '/')
+                path++;
+
+        if (isempty(root) || path_equal(root, "/"))
+                return strdup(path);
+
+        l = strlen(root) + 1 + strlen(path) + 1;
+
+        n = new(char, l);
+        if (!n)
+                return NULL;
+
+        p = stpcpy(n, root);
+
+        while (p > n && p[-1] == '/')
+                p--;
+
+        if (path[0] != '/')
+                *(p++) = '/';
+
+        strcpy(p, path);
+        return n;
+}
index 5548ce4a9410b33be21316e8c74071cd05141ec2..4f45cfd2b7ddf34778e4b8772c63cb517d205b02 100644 (file)
@@ -73,3 +73,30 @@ int fsck_exists(const char *fstype);
 /* 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), '/'))
+
+char *prefix_root(const char *root, const char *path);
+
+/* Similar to prefix_root(), but returns an alloca() buffer, or
+ * possibly a const pointer into the path parameter */
+#define prefix_roota(root, path)                                        \
+        ({                                                              \
+                const char* _path = (path), *_root = (root), *_ret;     \
+                char *_p, *_n;                                          \
+                size_t _l;                                              \
+                while (_path[0] == '/' && _path[1] == '/')              \
+                        _path ++;                                       \
+                if (isempty(_root) || path_equal(_root, "/"))           \
+                        _ret = _path;                                   \
+                else {                                                  \
+                        _l = strlen(_root) + 1 + strlen(_path) + 1;     \
+                        _n = alloca(_l);                                \
+                        _p = stpcpy(_n, _root);                         \
+                        while (_p > _n && _p[-1] == '/')                \
+                                _p--;                                   \
+                        if (_path[0] != '/')                            \
+                                *(_p++) = '/';                          \
+                        strcpy(_p, _path);                              \
+                        _ret = _n;                                      \
+                }                                                       \
+                _ret;                                                   \
+        })