mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
conf-files: chase symlink files in conf directories
Previously, symlinks in paths to conf directories are chased, but symlink files in conf directories were not. This also makes symlink files in conf directories chased. And, any unresolvable symlinks are dropped, even if no verification is requested.
This commit is contained in:
@@ -23,6 +23,8 @@
|
||||
static int files_add(
|
||||
DIR *dir,
|
||||
const char *dirpath,
|
||||
int rfd,
|
||||
const char *root, /* for logging, can be NULL */
|
||||
Hashmap **files,
|
||||
Set **masked,
|
||||
const char *suffix,
|
||||
@@ -32,12 +34,14 @@ static int files_add(
|
||||
|
||||
assert(dir);
|
||||
assert(dirpath);
|
||||
assert(rfd >= 0 || rfd == AT_FDCWD);
|
||||
assert(files);
|
||||
assert(masked);
|
||||
|
||||
FOREACH_DIRENT(de, dir, return -errno) {
|
||||
_cleanup_free_ char *n = NULL, *p = NULL;
|
||||
struct stat st;
|
||||
root = strempty(root);
|
||||
|
||||
FOREACH_DIRENT(de, dir, return log_debug_errno(errno, "Failed to read directory '%s/%s': %m",
|
||||
root, skip_leading_slash(dirpath))) {
|
||||
|
||||
/* Does this match the suffix? */
|
||||
if (suffix && !endswith(de->d_name, suffix))
|
||||
@@ -45,31 +49,83 @@ static int files_add(
|
||||
|
||||
/* Has this file already been found in an earlier directory? */
|
||||
if (hashmap_contains(*files, de->d_name)) {
|
||||
log_debug("Skipping overridden file '%s/%s'.", dirpath, de->d_name);
|
||||
log_debug("Skipping overridden file '%s/%s/%s'.",
|
||||
root, skip_leading_slash(dirpath), de->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Has this been masked in an earlier directory? */
|
||||
if ((flags & CONF_FILES_FILTER_MASKED) && set_contains(*masked, de->d_name)) {
|
||||
log_debug("File '%s/%s' is masked by previous entry.", dirpath, de->d_name);
|
||||
if ((flags & CONF_FILES_FILTER_MASKED) != 0 && set_contains(*masked, de->d_name)) {
|
||||
log_debug("File '%s/%s/%s' is masked by previous entry.",
|
||||
root, skip_leading_slash(dirpath), de->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read file metadata if we shall validate the check for file masks, for node types or whether the node is marked executable. */
|
||||
if (flags & (CONF_FILES_FILTER_MASKED|CONF_FILES_REGULAR|CONF_FILES_DIRECTORY|CONF_FILES_EXECUTABLE))
|
||||
if (fstatat(dirfd(dir), de->d_name, &st, 0) < 0) {
|
||||
log_debug_errno(errno, "Failed to stat '%s/%s', ignoring: %m", dirpath, de->d_name);
|
||||
_cleanup_free_ char *p = path_join(dirpath, de->d_name);
|
||||
if (!p)
|
||||
return log_oom_debug();
|
||||
|
||||
_cleanup_free_ char *resolved_path = NULL;
|
||||
bool need_stat = (flags & (CONF_FILES_FILTER_MASKED | CONF_FILES_REGULAR | CONF_FILES_DIRECTORY | CONF_FILES_EXECUTABLE)) != 0;
|
||||
struct stat st;
|
||||
|
||||
if (!need_stat || FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK)) {
|
||||
|
||||
/* Even if no verification is requested, let's unconditionally call chaseat(),
|
||||
* to drop unsafe symlinks. */
|
||||
|
||||
r = chaseat(rfd, p, CHASE_AT_RESOLVE_IN_ROOT | CHASE_NONEXISTENT, &resolved_path, /* ret_fd = */ NULL);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to chase '%s/%s', ignoring: %m",
|
||||
root, skip_leading_slash(p));
|
||||
continue;
|
||||
}
|
||||
if (r == 0 && FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK)) {
|
||||
|
||||
/* If the path points to /dev/null in a image or so, then the device node may not exist. */
|
||||
if (path_equal(skip_leading_slash(resolved_path), "dev/null")) {
|
||||
/* Mark this one as masked */
|
||||
r = set_put_strdup(masked, de->d_name);
|
||||
if (r < 0)
|
||||
return log_oom_debug();
|
||||
|
||||
log_debug("File '%s/%s' is a mask (symlink to /dev/null).",
|
||||
root, skip_leading_slash(p));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the flag is set, we need to have stat, hence, skip the entry. */
|
||||
log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to chase '%s/%s', ignoring: %m",
|
||||
root, skip_leading_slash(p));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (need_stat) {
|
||||
r = fstatat(rfd, resolved_path, &st, AT_SYMLINK_NOFOLLOW);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to stat '%s/%s', ignoring: %m",
|
||||
root, skip_leading_slash(p));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
r = chase_and_statat(rfd, p, CHASE_AT_RESOLVE_IN_ROOT, &resolved_path, &st);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to chase and stat '%s/%s', ignoring: %m",
|
||||
root, skip_leading_slash(p));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Is this a masking entry? */
|
||||
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK) && stat_may_be_dev_null(&st)) {
|
||||
/* Mark this one as masked */
|
||||
r = set_put_strdup(masked, de->d_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_oom_debug();
|
||||
|
||||
log_debug("File '%s/%s' is a mask (symlink to /dev/null).", dirpath, de->d_name);
|
||||
log_debug("File '%s/%s' is a mask (symlink to /dev/null).", root, skip_leading_slash(p));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -77,46 +133,42 @@ static int files_add(
|
||||
/* Mark this one as masked */
|
||||
r = set_put_strdup(masked, de->d_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_oom_debug();
|
||||
|
||||
log_debug("File '%s/%s' is a mask (an empty file).", dirpath, de->d_name);
|
||||
log_debug("File '%s/%s' is a mask (an empty file).", root, skip_leading_slash(p));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Does this node have the right type? */
|
||||
if (flags & (CONF_FILES_REGULAR|CONF_FILES_DIRECTORY))
|
||||
if (!((flags & CONF_FILES_DIRECTORY) && S_ISDIR(st.st_mode)) &&
|
||||
!((flags & CONF_FILES_REGULAR) && S_ISREG(st.st_mode))) {
|
||||
log_debug("Ignoring '%s/%s', as it does not have the right type.", dirpath, de->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Does this node have the executable bit set? */
|
||||
if (flags & CONF_FILES_EXECUTABLE)
|
||||
/* As requested: check if the file is marked executable. Note that we don't check access(X_OK)
|
||||
* here, as we care about whether the file is marked executable at all, and not whether it is
|
||||
* executable for us, because if so, such errors are stuff we should log about. */
|
||||
|
||||
if ((st.st_mode & 0111) == 0) { /* not executable */
|
||||
log_debug("Ignoring '%s/%s', as it is not marked executable.", dirpath, de->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
n = strdup(de->d_name);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
if ((flags & CONF_FILES_BASENAME))
|
||||
r = hashmap_ensure_put(files, &string_hash_ops_free, n, n);
|
||||
else {
|
||||
p = path_join(dirpath, de->d_name);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = hashmap_ensure_put(files, &string_hash_ops_free_free, n, p);
|
||||
/* Is this node a regular file? */
|
||||
if (FLAGS_SET(flags, CONF_FILES_REGULAR) && !S_ISREG(st.st_mode)) {
|
||||
log_debug("Ignoring '%s/%s', as it is not a regular file.", root, skip_leading_slash(p));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Is this node a directory? */
|
||||
if (FLAGS_SET(flags, CONF_FILES_DIRECTORY) && !S_ISDIR(st.st_mode)) {
|
||||
log_debug("Ignoring '%s/%s', as it is not a directory.", root, skip_leading_slash(p));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Does this node have the executable bit set?
|
||||
* As requested: check if the file is marked executable. Note that we don't check access(X_OK)
|
||||
* here, as we care about whether the file is marked executable at all, and not whether it is
|
||||
* executable for us, because if so, such errors are stuff we should log about. */
|
||||
if (FLAGS_SET(flags, CONF_FILES_EXECUTABLE) && (st.st_mode & 0111) == 0) {
|
||||
log_debug("Ignoring '%s/%s', as it is not marked executable.", root, skip_leading_slash(p));
|
||||
continue;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *n = strdup(de->d_name);
|
||||
if (!n)
|
||||
return log_oom_debug();
|
||||
|
||||
r = hashmap_ensure_put(files, &string_hash_ops_free_free, n, p);
|
||||
if (r < 0) {
|
||||
assert(r == -ENOMEM);
|
||||
return log_oom_debug();
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(r > 0);
|
||||
|
||||
TAKE_PTR(n);
|
||||
@@ -126,66 +178,51 @@ static int files_add(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int copy_and_sort_files_from_hashmap(Hashmap *fh, char ***ret) {
|
||||
static int copy_and_sort_files_from_hashmap(Hashmap *fh, const char *root, ConfFilesFlags flags, char ***ret) {
|
||||
_cleanup_free_ char **sv = NULL;
|
||||
char **files;
|
||||
_cleanup_strv_free_ char **files = NULL;
|
||||
size_t n = 0;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
r = hashmap_dump_sorted(fh, (void***) &sv, /* ret_n = */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_oom_debug();
|
||||
|
||||
/* The entries in the array given by hashmap_dump_sorted() are still owned by the hashmap. */
|
||||
files = strv_copy(sv);
|
||||
if (!files)
|
||||
return -ENOMEM;
|
||||
STRV_FOREACH(s, sv) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
*ret = files;
|
||||
if (FLAGS_SET(flags, CONF_FILES_BASENAME)) {
|
||||
r = path_extract_filename(*s, &p);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to extract filename from '%s': %m", *s);
|
||||
} else if (root) {
|
||||
p = path_join(root, skip_leading_slash(*s));
|
||||
if (!p)
|
||||
return log_oom_debug();
|
||||
}
|
||||
|
||||
if (p)
|
||||
r = strv_consume_with_size(&files, &n, TAKE_PTR(p));
|
||||
else
|
||||
r = strv_extend_with_size(&files, &n, *s);
|
||||
if (r < 0)
|
||||
return log_oom_debug();
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(files);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_files_list_strv(
|
||||
char ***ret,
|
||||
const char *suffix,
|
||||
const char *root,
|
||||
ConfFilesFlags flags,
|
||||
const char * const *dirs) {
|
||||
|
||||
_cleanup_hashmap_free_ Hashmap *fh = NULL;
|
||||
_cleanup_set_free_ Set *masked = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
STRV_FOREACH(p, dirs) {
|
||||
_cleanup_closedir_ DIR *dir = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
|
||||
r = chase_and_opendir(*p, root, CHASE_PREFIX_ROOT, &path, &dir);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to chase and open directory '%s', ignoring: %m", *p);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = files_add(dir, path, &fh, &masked, suffix, flags);
|
||||
if (r == -ENOMEM)
|
||||
return r;
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to search for files in '%s', ignoring: %m", path);
|
||||
}
|
||||
|
||||
return copy_and_sort_files_from_hashmap(fh, ret);
|
||||
}
|
||||
|
||||
int conf_files_list_strv_at(
|
||||
char ***ret,
|
||||
static int conf_files_list_impl(
|
||||
const char *suffix,
|
||||
int rfd,
|
||||
const char *root, /* for logging, can be NULL */
|
||||
ConfFilesFlags flags,
|
||||
const char * const *dirs) {
|
||||
const char * const *dirs,
|
||||
Hashmap **ret) {
|
||||
|
||||
_cleanup_hashmap_free_ Hashmap *fh = NULL;
|
||||
_cleanup_set_free_ Set *masked = NULL;
|
||||
@@ -201,18 +238,64 @@ int conf_files_list_strv_at(
|
||||
r = chase_and_opendirat(rfd, *p, CHASE_AT_RESOLVE_IN_ROOT, &path, &dir);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to chase and open directory '%s', ignoring: %m", *p);
|
||||
log_debug_errno(r, "Failed to chase and open directory '%s%s', ignoring: %m", strempty(root), *p);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = files_add(dir, path, &fh, &masked, suffix, flags);
|
||||
r = files_add(dir, path, rfd, root, &fh, &masked, suffix, flags);
|
||||
if (r == -ENOMEM)
|
||||
return r;
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to search for files in '%s', ignoring: %m", path);
|
||||
}
|
||||
|
||||
return copy_and_sort_files_from_hashmap(fh, ret);
|
||||
*ret = TAKE_PTR(fh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_files_list_strv(
|
||||
char ***ret,
|
||||
const char *suffix,
|
||||
const char *root,
|
||||
ConfFilesFlags flags,
|
||||
const char * const *dirs) {
|
||||
|
||||
_cleanup_hashmap_free_ Hashmap *fh = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
_cleanup_close_ int rfd = open(empty_to_root(root), O_CLOEXEC|O_DIRECTORY|O_PATH);
|
||||
if (rfd < 0)
|
||||
return log_debug_errno(errno, "Failed to open '%s': %m", root);
|
||||
|
||||
r = conf_files_list_impl(suffix, rfd, root, flags, dirs, &fh);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return copy_and_sort_files_from_hashmap(fh, empty_to_root(root), flags, ret);
|
||||
}
|
||||
|
||||
int conf_files_list_strv_at(
|
||||
char ***ret,
|
||||
const char *suffix,
|
||||
int rfd,
|
||||
ConfFilesFlags flags,
|
||||
const char * const *dirs) {
|
||||
|
||||
_cleanup_hashmap_free_ Hashmap *fh = NULL;
|
||||
_cleanup_free_ char *root = NULL;
|
||||
int r;
|
||||
|
||||
assert(rfd >= 0 || rfd == AT_FDCWD);
|
||||
assert(ret);
|
||||
|
||||
if (rfd >= 0 && DEBUG_LOGGING)
|
||||
(void) fd_get_path(rfd, &root); /* for logging */
|
||||
|
||||
r = conf_files_list_impl(suffix, rfd, root, flags, dirs, &fh);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return copy_and_sort_files_from_hashmap(fh, /* root = */ NULL, flags, ret);
|
||||
}
|
||||
|
||||
int conf_files_insert(char ***strv, const char *root, char **dirs, const char *path) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "conf-files.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "path-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "string-util.h"
|
||||
@@ -17,19 +18,21 @@
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
TEST(conf_files_list) {
|
||||
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
|
||||
_cleanup_close_ int tfd = -EBADF;
|
||||
_cleanup_(rm_rf_physical_and_freep) char *t = NULL, *t2 = NULL;
|
||||
_cleanup_close_ int tfd = -EBADF, tfd2 = -EBADF;
|
||||
_cleanup_strv_free_ char **result = NULL;
|
||||
const char *search1, *search2, *search1_a, *search1_b, *search1_c, *search2_aa;
|
||||
const char *search1, *search2, *search3, *search1_a, *search1_b, *search1_c, *search2_aa, *search2_mm;
|
||||
|
||||
tfd = mkdtemp_open("/tmp/test-conf-files-XXXXXX", O_PATH, &t);
|
||||
assert(tfd >= 0);
|
||||
ASSERT_OK(tfd = mkdtemp_open("/tmp/test-conf-files-XXXXXX", O_PATH, &t));
|
||||
ASSERT_OK(tfd2 = mkdtemp_open("/tmp/test-conf-files-XXXXXX", O_PATH, &t2));
|
||||
|
||||
assert_se(mkdirat(tfd, "dir1", 0755) >= 0);
|
||||
assert_se(mkdirat(tfd, "dir2", 0755) >= 0);
|
||||
ASSERT_OK_ERRNO(mkdirat(tfd, "dir1", 0755));
|
||||
ASSERT_OK_ERRNO(mkdirat(tfd, "dir2", 0755));
|
||||
ASSERT_OK_ERRNO(mkdirat(tfd, "dir3", 0755));
|
||||
|
||||
search1 = strjoina(t, "/dir1/");
|
||||
search2 = strjoina(t, "/dir2/");
|
||||
search3 = strjoina(t, "/dir3/");
|
||||
|
||||
FOREACH_STRING(p, "a.conf", "b.conf", "c.foo") {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
@@ -38,19 +41,45 @@ TEST(conf_files_list) {
|
||||
assert_se(write_string_file(path, "foobar", WRITE_STRING_FILE_CREATE) >= 0);
|
||||
}
|
||||
|
||||
assert_se(symlinkat("/dev/null", tfd, "dir1/m.conf") >= 0);
|
||||
ASSERT_OK_ERRNO(symlinkat("/dev/null", tfd, "dir1/m.conf"));
|
||||
ASSERT_OK_ERRNO(symlinkat("../dev/null", tfd, "dir1/mm.conf"));
|
||||
|
||||
FOREACH_STRING(p, "a.conf", "aa.conf", "m.conf") {
|
||||
FOREACH_STRING(p, "a.conf", "aa.conf", "m.conf", "mm.conf") {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
|
||||
assert_se(path = path_join(search2, p));
|
||||
assert_se(write_string_file(path, "hogehoge", WRITE_STRING_FILE_CREATE) >= 0);
|
||||
}
|
||||
|
||||
ASSERT_OK(touch(strjoina(t2, "/absolute-empty.real")));
|
||||
ASSERT_OK(symlinkat_atomic_full(strjoina(t2, "/absolute-empty.real"), AT_FDCWD, strjoina(search3, "absolute-empty.conf"), /* flags = */ 0));
|
||||
|
||||
ASSERT_OK(write_string_file_at(tfd2, "absolute-non-empty.real", "absolute-non-empty", WRITE_STRING_FILE_CREATE));
|
||||
ASSERT_OK(symlinkat_atomic_full(strjoina(t2, "/absolute-non-empty.real"), AT_FDCWD, strjoina(search3, "absolute-non-empty.conf"), /* flags = */ 0));
|
||||
|
||||
ASSERT_OK(touch(strjoina(t2, "/relative-empty.real")));
|
||||
ASSERT_OK(symlinkat_atomic_full(strjoina(t2, "/relative-empty.real"), AT_FDCWD, strjoina(search3, "relative-empty.conf"), SYMLINK_MAKE_RELATIVE));
|
||||
|
||||
ASSERT_OK(write_string_file_at(tfd2, "relative-non-empty.real", "relative-non-empty", WRITE_STRING_FILE_CREATE));
|
||||
ASSERT_OK(symlinkat_atomic_full(strjoina(t2, "/relative-non-empty.real"), AT_FDCWD, strjoina(search3, "relative-non-empty.conf"), SYMLINK_MAKE_RELATIVE));
|
||||
|
||||
ASSERT_OK(touch(strjoina(t, "/absolute-empty-for-root.real")));
|
||||
ASSERT_OK(symlinkat_atomic_full("/absolute-empty-for-root.real", AT_FDCWD, strjoina(search3, "absolute-empty-for-root.conf"), /* flags = */ 0));
|
||||
|
||||
ASSERT_OK(write_string_file_at(tfd, "absolute-non-empty-for-root.real", "absolute-non-empty", WRITE_STRING_FILE_CREATE));
|
||||
ASSERT_OK(symlinkat_atomic_full("/absolute-non-empty-for-root.real", AT_FDCWD, strjoina(search3, "absolute-non-empty-for-root.conf"), /* flags = */ 0));
|
||||
|
||||
ASSERT_OK(touch(strjoina(t, "/relative-empty-for-root.real")));
|
||||
ASSERT_OK(symlinkat_atomic_full("../../../../relative-empty-for-root.real", AT_FDCWD, strjoina(search3, "relative-empty-for-root.conf"), /* flags = */ 0));
|
||||
|
||||
ASSERT_OK(write_string_file_at(tfd, "relative-non-empty-for-root.real", "relative-non-empty", WRITE_STRING_FILE_CREATE));
|
||||
ASSERT_OK(symlinkat_atomic_full("../../../../relative-non-empty-for-root.real", AT_FDCWD, strjoina(search3, "relative-non-empty-for-root.conf"), /* flags = */ 0));
|
||||
|
||||
search1_a = strjoina(search1, "a.conf");
|
||||
search1_b = strjoina(search1, "b.conf");
|
||||
search1_c = strjoina(search1, "c.foo");
|
||||
search2_aa = strjoina(search2, "aa.conf");
|
||||
search2_mm = strjoina(search2, "mm.conf");
|
||||
|
||||
/* search dir1 without suffix */
|
||||
assert_se(conf_files_list(&result, NULL, NULL, CONF_FILES_FILTER_MASKED, search1) >= 0);
|
||||
@@ -105,7 +134,7 @@ TEST(conf_files_list) {
|
||||
/* search two dirs */
|
||||
assert_se(conf_files_list_strv(&result, ".conf", NULL, CONF_FILES_FILTER_MASKED, STRV_MAKE_CONST(search1, search2)) >= 0);
|
||||
strv_print(result);
|
||||
assert_se(strv_equal(result, STRV_MAKE(search1_a, search2_aa, search1_b)));
|
||||
assert_se(strv_equal(result, STRV_MAKE(search1_a, search2_aa, search1_b, search2_mm)));
|
||||
|
||||
result = strv_free(result);
|
||||
|
||||
@@ -117,7 +146,7 @@ TEST(conf_files_list) {
|
||||
|
||||
assert_se(conf_files_list_strv_at(&result, ".conf", AT_FDCWD, CONF_FILES_FILTER_MASKED, STRV_MAKE_CONST(search1, search2)) >= 0);
|
||||
strv_print(result);
|
||||
assert_se(strv_equal(result, STRV_MAKE(search1_a, search2_aa, search1_b)));
|
||||
assert_se(strv_equal(result, STRV_MAKE(search1_a, search2_aa, search1_b, search2_mm)));
|
||||
|
||||
result = strv_free(result);
|
||||
|
||||
@@ -127,10 +156,123 @@ TEST(conf_files_list) {
|
||||
|
||||
result = strv_free(result);
|
||||
|
||||
/* search dir3 */
|
||||
ASSERT_OK(conf_files_list(&result, /* suffix = */ NULL, /* root = */ NULL, CONF_FILES_FILTER_MASKED, search3));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-non-empty.conf"),
|
||||
strjoina(search3, "relative-non-empty.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list(&result, /* suffix = */ NULL, /* root = */ NULL, CONF_FILES_FILTER_MASKED_BY_EMPTY, search3));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-non-empty.conf"),
|
||||
strjoina(search3, "relative-non-empty.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list(&result, /* suffix = */ NULL, /* root = */ NULL, CONF_FILES_FILTER_MASKED_BY_SYMLINK, search3));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-empty.conf"),
|
||||
strjoina(search3, "absolute-non-empty.conf"),
|
||||
strjoina(search3, "relative-empty.conf"),
|
||||
strjoina(search3, "relative-non-empty.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list(&result, /* suffix = */ NULL, /* root = */ NULL, CONF_FILES_REGULAR, search3));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-empty.conf"),
|
||||
strjoina(search3, "absolute-non-empty.conf"),
|
||||
strjoina(search3, "relative-empty.conf"),
|
||||
strjoina(search3, "relative-non-empty.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list(&result, /* suffix = */ NULL, t, CONF_FILES_FILTER_MASKED, "/dir3/"));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-non-empty-for-root.conf"),
|
||||
strjoina(search3, "relative-non-empty-for-root.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list(&result, /* suffix = */ NULL, t, CONF_FILES_FILTER_MASKED_BY_EMPTY, "/dir3/"));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-non-empty-for-root.conf"),
|
||||
strjoina(search3, "relative-non-empty-for-root.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list(&result, /* suffix = */ NULL, t, CONF_FILES_FILTER_MASKED_BY_SYMLINK, "/dir3/"));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-empty-for-root.conf"),
|
||||
strjoina(search3, "absolute-non-empty-for-root.conf"),
|
||||
strjoina(search3, "relative-empty-for-root.conf"),
|
||||
strjoina(search3, "relative-non-empty-for-root.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list(&result, /* suffix = */ NULL, t, CONF_FILES_REGULAR, "/dir3/"));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-empty-for-root.conf"),
|
||||
strjoina(search3, "absolute-non-empty-for-root.conf"),
|
||||
strjoina(search3, "relative-empty-for-root.conf"),
|
||||
strjoina(search3, "relative-non-empty-for-root.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list_at(&result, /* suffix = */ NULL, AT_FDCWD, CONF_FILES_FILTER_MASKED, search3));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-non-empty.conf"),
|
||||
strjoina(search3, "relative-non-empty.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list_at(&result, /* suffix = */ NULL, AT_FDCWD, CONF_FILES_FILTER_MASKED_BY_EMPTY, search3));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-non-empty.conf"),
|
||||
strjoina(search3, "relative-non-empty.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list_at(&result, /* suffix = */ NULL, AT_FDCWD, CONF_FILES_FILTER_MASKED_BY_SYMLINK, search3));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-empty.conf"),
|
||||
strjoina(search3, "absolute-non-empty.conf"),
|
||||
strjoina(search3, "relative-empty.conf"),
|
||||
strjoina(search3, "relative-non-empty.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list_at(&result, /* suffix = */ NULL, AT_FDCWD, CONF_FILES_REGULAR, search3));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE(strjoina(search3, "absolute-empty.conf"),
|
||||
strjoina(search3, "absolute-non-empty.conf"),
|
||||
strjoina(search3, "relative-empty.conf"),
|
||||
strjoina(search3, "relative-non-empty.conf"))));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list_at(&result, /* suffix = */ NULL, tfd, CONF_FILES_FILTER_MASKED, "/dir3/"));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE("dir3/absolute-non-empty-for-root.conf",
|
||||
"dir3/relative-non-empty-for-root.conf")));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list_at(&result, /* suffix = */ NULL, tfd, CONF_FILES_FILTER_MASKED_BY_EMPTY, "/dir3/"));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE("dir3/absolute-non-empty-for-root.conf",
|
||||
"dir3/relative-non-empty-for-root.conf")));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list_at(&result, /* suffix = */ NULL, tfd, CONF_FILES_FILTER_MASKED_BY_SYMLINK, "/dir3/"));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE("dir3/absolute-empty-for-root.conf",
|
||||
"dir3/absolute-non-empty-for-root.conf",
|
||||
"dir3/relative-empty-for-root.conf",
|
||||
"dir3/relative-non-empty-for-root.conf")));
|
||||
result = strv_free(result);
|
||||
|
||||
ASSERT_OK(conf_files_list_at(&result, /* suffix = */ NULL, tfd, CONF_FILES_REGULAR, "/dir3/"));
|
||||
strv_print(result);
|
||||
ASSERT_TRUE(strv_equal(result, STRV_MAKE("dir3/absolute-empty-for-root.conf",
|
||||
"dir3/absolute-non-empty-for-root.conf",
|
||||
"dir3/relative-empty-for-root.conf",
|
||||
"dir3/relative-non-empty-for-root.conf")));
|
||||
result = strv_free(result);
|
||||
|
||||
/* filename only */
|
||||
assert_se(conf_files_list_strv(&result, ".conf", NULL, CONF_FILES_FILTER_MASKED | CONF_FILES_BASENAME, STRV_MAKE_CONST(search1, search2)) >= 0);
|
||||
strv_print(result);
|
||||
assert_se(strv_equal(result, STRV_MAKE("a.conf", "aa.conf", "b.conf")));
|
||||
assert_se(strv_equal(result, STRV_MAKE("a.conf", "aa.conf", "b.conf", "mm.conf")));
|
||||
|
||||
result = strv_free(result);
|
||||
|
||||
@@ -142,7 +284,7 @@ TEST(conf_files_list) {
|
||||
|
||||
assert_se(conf_files_list_strv_at(&result, ".conf", AT_FDCWD, CONF_FILES_FILTER_MASKED | CONF_FILES_BASENAME, STRV_MAKE_CONST(search1, search2)) >= 0);
|
||||
strv_print(result);
|
||||
assert_se(strv_equal(result, STRV_MAKE("a.conf", "aa.conf", "b.conf")));
|
||||
assert_se(strv_equal(result, STRV_MAKE("a.conf", "aa.conf", "b.conf", "mm.conf")));
|
||||
|
||||
result = strv_free(result);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user