From 6785155e4ec3e478918481cd6321d96ec30c83b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 May 2015 17:42:10 +0200 Subject: [PATCH] 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. --- src/shared/conf-files.c | 6 +++--- src/shared/path-util.c | 34 ++++++++++++++++++++++++++++++++++ src/shared/path-util.h | 27 +++++++++++++++++++++++++++ 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; \ + }) -- 2.30.2