summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-05-13 17:42:10 +0200
committerSven Eden <yamakuzure@gmx.net>2017-03-14 09:56:08 +0100
commit6785155e4ec3e478918481cd6321d96ec30c83b7 (patch)
treea0e7d6ed157706967a5842eb5de1834ebe9567c5
parentf0b159f2e7b4ac8a75997834d240459f5436d36e (diff)
util: add generic calls for prefixing a root directory to a path
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.
-rw-r--r--src/shared/conf-files.c6
-rw-r--r--src/shared/path-util.c34
-rw-r--r--src/shared/path-util.h27
3 files changed, 64 insertions, 3 deletions
diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c
index 9ab08355e..da8745b28 100644
--- a/src/shared/conf-files.c
+++ b/src/shared/conf-files.c
@@ -36,12 +36,13 @@
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);
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 635ce33b2..7090989fc 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -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;
+}
diff --git a/src/shared/path-util.h b/src/shared/path-util.h
index 5548ce4a9..4f45cfd2b 100644
--- a/src/shared/path-util.h
+++ b/src/shared/path-util.h
@@ -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; \
+ })