path-util: allow NULLs in arguments to path_join()

This removes the need to remember to put strempty() in places, thus reducing
the likelihood of a stupid mistake.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2018-11-30 11:06:24 +01:00
parent 62a85ee0a9
commit 652ef29887
8 changed files with 29 additions and 26 deletions

View file

@ -216,7 +216,7 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p
p2 = path_startswith(path, *dir);
if (p2) {
/* Our new entry has higher priority */
t = path_join(strempty(root), path);
t = path_join(root, path);
if (!t)
return log_oom();
@ -232,7 +232,7 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p
/* … we are not there yet, let's continue */
}
t = path_join(strempty(root), path);
t = path_join(root, path);
if (!t)
return log_oom();
@ -318,7 +318,7 @@ int conf_files_list_with_replacement(
if (r < 0)
return log_error_errno(r, "Failed to extend config file list: %m");
p = path_join(strempty(root), replacement);
p = path_join(root, replacement);
if (!p)
return log_oom();
}

View file

@ -488,11 +488,10 @@ char* path_join_internal(const char *first, ...) {
bool slash;
size_t sz;
assert(first);
/* Joins all listed strings until NULL and places an "/" between them unless the strings end/begin already with
* one so that it is unnecessary. Note that "/" which are already duplicate won't be removed. The string
* returned is hence always equal or longer than the sum of the lengths of each individual string.
/* Joins all listed strings until the sentinel and places a "/" between them unless the strings end/begin
* already with one so that it is unnecessary. Note that slashes which are already duplicate won't be
* removed. The string returned is hence always equal to or longer than the sum of the lengths of each
* individual string.
*
* Note: any listed empty string is simply skipped. This can be useful for concatenating strings of which some
* are optional.
@ -503,22 +502,18 @@ char* path_join_internal(const char *first, ...) {
* path_join("foo/", "bar") "foo/bar"
* path_join("", "foo", "", "bar", "") "foo/bar" */
sz = strlen(first);
sz = strlen_ptr(first);
va_start(ap, first);
while ((p = va_arg(ap, char*))) {
if (*p == 0) /* Skip empty items */
continue;
sz += 1 + strlen(p);
}
while ((p = va_arg(ap, char*)) != (const char*) -1)
if (!isempty(p))
sz += 1 + strlen(p);
va_end(ap);
joined = new(char, sz + 1);
if (!joined)
return NULL;
if (first[0] != 0) {
if (!isempty(first)) {
q = stpcpy(joined, first);
slash = endswith(first, "/");
} else {
@ -529,9 +524,8 @@ char* path_join_internal(const char *first, ...) {
}
va_start(ap, first);
while ((p = va_arg(ap, char*))) {
if (*p == 0) /* Skip empty items */
while ((p = va_arg(ap, char*)) != (const char*) -1) {
if (isempty(p))
continue;
if (!slash && p[0] != '/')

View file

@ -49,8 +49,8 @@ char* path_startswith(const char *path, const char *prefix) _pure_;
int path_compare(const char *a, const char *b) _pure_;
bool path_equal(const char *a, const char *b) _pure_;
bool path_equal_or_files_same(const char *a, const char *b, int flags);
char* path_join_internal(const char *first, ...) _sentinel_;
#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, NULL)
char* path_join_internal(const char *first, ...);
#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, (const char*) -1)
char* path_simplify(char *path, bool kill_dots);

View file

@ -2110,7 +2110,7 @@ int main(int argc, char *argv[]) {
case ACTION_UPDATE_CATALOG: {
_cleanup_free_ char *database;
database = path_join(strempty(arg_root), CATALOG_DATABASE);
database = path_join(arg_root, CATALOG_DATABASE);
if (!database) {
r = log_oom();
goto finish;

View file

@ -651,7 +651,7 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co
log_debug("strings dedup'ed: %8zu bytes (%8zu)",
trie->strings->dedup_len, trie->strings->dedup_count);
hwdb_bin = path_join(strempty(root), hwdb_bin_dir ?: default_hwdb_bin_dir, "hwdb.bin");
hwdb_bin = path_join(root, hwdb_bin_dir ?: default_hwdb_bin_dir, "hwdb.bin");
if (!hwdb_bin)
return -ENOMEM;

View file

@ -217,7 +217,7 @@ int conf_files_cat(const char *root, const char *name) {
if (r < 0)
return log_error_errno(r, "Failed to query file list: %m");
path = path_join(strempty(root), "/etc", name);
path = path_join(root, "/etc", name);
if (!path)
return log_oom();

View file

@ -5975,7 +5975,7 @@ static int enable_sysv_units(const char *verb, char **args) {
if (found_native && streq(verb, "is-enabled"))
continue;
p = path_join(strempty(arg_root), SYSTEM_SYSVINIT_PATH, name);
p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
if (!p)
return log_oom();

View file

@ -251,10 +251,19 @@ static void test_path_join(void) {
test_join("/c", "", "/", "c");
test_join("/", "", "/", NULL);
test_join("/a/b/c", NULL, "/a/b", "/c");
test_join("a/b/c", NULL, "a/b", "c");
test_join("/a/b/c", NULL, "/a/b", "c");
test_join("/c", NULL, "/", "c");
test_join("/", NULL, "/", NULL);
test_join("", "", NULL);
test_join("", NULL, "");
test_join("", NULL, NULL);
test_join("foo/bar", "foo", "bar");
test_join("foo/bar", "", "foo", "bar");
test_join("foo/bar", NULL, "foo", NULL, "bar");
test_join("foo/bar", "", "foo", "", "bar", "");
test_join("foo/bar", "", "", "", "", "foo", "", "", "", "bar", "", "", "");