vpick: take separate root_fd and dir_fd arguments

Mirror how chaseat() works these days: instead of a single toplevel_fd that
serves as both the root (chroot) boundary and the directory that resolution
starts from, path_pick() now takes a separate root_fd and dir_fd. This lets
callers resolve a path relative to a specific directory fd while confining
symlink and absolute-path resolution to a root directory fd.

All existing callers are updated to pass the same fd for both, preserving
their current behaviour.
This commit is contained in:
Lennart Poettering
2026-06-24 12:59:55 +02:00
parent 8168aca9fb
commit 95a372a514
9 changed files with 109 additions and 83 deletions
+9 -6
View File
@@ -3719,8 +3719,9 @@ static int pin_rootfs(
if (context->root_image) {
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
r = path_pick(/* toplevel_path= */ NULL,
/* toplevel_fd= */ AT_FDCWD,
r = path_pick(/* root_path= */ NULL,
/* root_fd= */ AT_FDCWD,
/* dir_fd= */ AT_FDCWD,
context->root_image,
pick_filter_image_raw,
ELEMENTSOF(pick_filter_image_raw),
@@ -3760,8 +3761,9 @@ static int pin_rootfs(
if (context->root_directory) {
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
r = path_pick(/* toplevel_path= */ NULL,
/* toplevel_fd= */ AT_FDCWD,
r = path_pick(/* root_path= */ NULL,
/* root_fd= */ AT_FDCWD,
/* dir_fd= */ AT_FDCWD,
context->root_directory,
pick_filter_image_dir,
ELEMENTSOF(pick_filter_image_dir),
@@ -3789,8 +3791,9 @@ static int pin_rootfs(
if (context->root_mstack) {
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
r = path_pick(/* toplevel_path= */ NULL,
/* toplevel_fd= */ AT_FDCWD,
r = path_pick(/* root_path= */ NULL,
/* root_fd= */ AT_FDCWD,
/* dir_fd= */ AT_FDCWD,
context->root_mstack,
pick_filter_image_mstack,
/* n_filters= */ 1,
+6 -4
View File
@@ -564,8 +564,9 @@ static int append_extensions(
_cleanup_free_ char *mount_point = NULL;
const MountImage *m = mount_images + i;
r = path_pick(/* toplevel_path= */ NULL,
/* toplevel_fd= */ AT_FDCWD,
r = path_pick(/* root_path= */ NULL,
/* root_fd= */ AT_FDCWD,
/* dir_fd= */ AT_FDCWD,
m->source,
pick_filter_image_raw,
ELEMENTSOF(pick_filter_image_raw),
@@ -636,8 +637,9 @@ static int append_extensions(
if (startswith(e, "+"))
e++;
r = path_pick(/* toplevel_path= */ NULL,
/* toplevel_fd= */ AT_FDCWD,
r = path_pick(/* root_path= */ NULL,
/* root_fd= */ AT_FDCWD,
/* dir_fd= */ AT_FDCWD,
e,
pick_filter_image_dir,
ELEMENTSOF(pick_filter_image_dir),
+9 -6
View File
@@ -821,8 +821,9 @@ static int extract_image_and_extensions(
/* If we get a path, then check if it can be resolved with vpick. We need this as we might just
* get a simple image name, which would make vpick error out. */
if (path_is_absolute(name_or_path)) {
r = path_pick(/* toplevel_path= */ NULL,
/* toplevel_fd= */ AT_FDCWD,
r = path_pick(/* root_path= */ NULL,
/* root_fd= */ AT_FDCWD,
/* dir_fd= */ AT_FDCWD,
name_or_path,
pick_filter_image_any,
ELEMENTSOF(pick_filter_image_any),
@@ -860,8 +861,9 @@ static int extract_image_and_extensions(
const char *path = *p;
if (path_is_absolute(*p)) {
r = path_pick(/* toplevel_path= */ NULL,
/* toplevel_fd= */ AT_FDCWD,
r = path_pick(/* root_path= */ NULL,
/* root_fd= */ AT_FDCWD,
/* dir_fd= */ AT_FDCWD,
*p,
pick_filter_image_any,
ELEMENTSOF(pick_filter_image_any),
@@ -2201,8 +2203,9 @@ static bool marker_matches_images(const char *marker, const char *name_or_path,
if (r < 0)
return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", image);
r = path_pick(/* toplevel_path= */ NULL,
/* toplevel_fd= */ AT_FDCWD,
r = path_pick(/* root_path= */ NULL,
/* root_fd= */ AT_FDCWD,
/* dir_fd= */ AT_FDCWD,
*image_name_or_path,
pick_filter_image_any,
ELEMENTSOF(pick_filter_image_any),
+2
View File
@@ -956,6 +956,7 @@ int image_find(RuntimeScope scope,
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
r = path_pick(root,
rfd,
rfd,
fname_path, /* This has to be the unresolved entry with the .v suffix */
&filter,
@@ -1177,6 +1178,7 @@ int image_discover(
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
r = path_pick(root,
rfd,
rfd,
fname_path, /* This has to be the unresolved entry with the .v suffix */
&filter,
+1 -1
View File
@@ -139,7 +139,7 @@ static int mstack_load_one(MStack *mstack, const char *dir, int dir_fd, const ch
};
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
r = path_pick(dir, dir_fd, fname, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE, &result);
r = path_pick(dir, dir_fd, dir_fd, fname, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE, &result);
if (r < 0)
return log_debug_errno(r, "Failed to resolve '%s' directory: %m", fname);
if (r == 0)
+52 -38
View File
@@ -176,8 +176,9 @@ static int errno_from_mode(uint32_t type_mask, mode_t found) {
}
static int pin_choice(
const char *toplevel_path,
int toplevel_fd,
const char *root_path,
int root_fd,
int dir_fd,
const char *inode_path,
int _inode_fd, /* we always take ownership of the fd, even on failure */
unsigned tries_left,
@@ -190,14 +191,15 @@ static int pin_choice(
_cleanup_free_ char *resolved_path = NULL;
int r;
assert(wildcard_fd_is_valid(toplevel_fd));
assert(wildcard_fd_is_valid(root_fd));
assert(wildcard_fd_is_valid(dir_fd));
assert(inode_path);
assert(filter);
assert(ret);
if (inode_fd < 0 || FLAGS_SET(flags, PICK_RESOLVE)) {
r = chaseat(toplevel_fd,
toplevel_fd,
r = chaseat(root_fd,
dir_fd,
inode_path,
/* flags= */ 0,
FLAGS_SET(flags, PICK_RESOLVE) ? &resolved_path : NULL,
@@ -212,11 +214,11 @@ static int pin_choice(
struct stat st;
if (fstat(inode_fd, &st) < 0)
return log_debug_errno(errno, "Failed to stat discovered inode '%s%s': %m",
empty_to_root(toplevel_path), skip_leading_slash(inode_path));
empty_to_root(root_path), skip_leading_slash(inode_path));
if (filter->type_mask != 0 && !BIT_SET(filter->type_mask, IFTODT(st.st_mode))) {
log_debug("Inode '%s/%s' has wrong type, found '%s'.",
empty_to_root(toplevel_path), skip_leading_slash(inode_path),
empty_to_root(root_path), skip_leading_slash(inode_path),
inode_type_to_string(st.st_mode));
*ret = PICK_RESULT_NULL;
return 0;
@@ -311,8 +313,9 @@ static bool architecture_matches(const PickFilter *filter, Architecture a) {
}
static int make_choice(
const char *toplevel_path,
int toplevel_fd,
const char *root_path,
int root_fd,
int dir_fd,
const char *inode_path,
int _inode_fd, /* we always take ownership of the fd, even on failure */
const PickFilter *filter,
@@ -322,13 +325,14 @@ static int make_choice(
_cleanup_close_ int inode_fd = TAKE_FD(_inode_fd);
int r;
assert(wildcard_fd_is_valid(toplevel_fd));
assert(wildcard_fd_is_valid(root_fd));
assert(wildcard_fd_is_valid(dir_fd));
assert(inode_path);
assert(filter);
assert(ret);
if (inode_fd < 0) {
r = chaseat(toplevel_fd, toplevel_fd, inode_path, /* flags= */ 0, NULL, &inode_fd);
r = chaseat(root_fd, dir_fd, inode_path, /* flags= */ 0, NULL, &inode_fd);
if (r < 0)
return r;
}
@@ -345,18 +349,19 @@ static int make_choice(
return log_oom_debug();
_cleanup_close_ int object_fd = -EBADF;
r = chaseat(toplevel_fd, toplevel_fd, p, /* flags= */ 0, &object_path, &object_fd);
r = chaseat(root_fd, dir_fd, p, /* flags= */ 0, &object_path, &object_fd);
if (r == -ENOENT) {
*ret = PICK_RESULT_NULL;
return 0;
}
if (r < 0)
return log_debug_errno(r, "Failed to open '%s/%s': %m",
empty_to_root(toplevel_path), skip_leading_slash(p));
empty_to_root(root_path), skip_leading_slash(p));
return pin_choice(
toplevel_path,
toplevel_fd,
root_path,
root_fd,
dir_fd,
FLAGS_SET(flags, PICK_RESOLVE) ? object_path : p,
TAKE_FD(object_fd), /* unconditionally pass ownership of the fd */
/* tries_left= */ UINT_MAX,
@@ -371,16 +376,16 @@ static int make_choice(
/* Underspecified, so we do our enumeration dance */
/* Convert O_PATH to a regular directory fd */
_cleanup_close_ int dir_fd = fd_reopen(inode_fd, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
if (dir_fd < 0)
return log_debug_errno(dir_fd, "Failed to reopen '%s/%s' as directory: %m",
empty_to_root(toplevel_path), skip_leading_slash(inode_path));
_cleanup_close_ int enumerate_fd = fd_reopen(inode_fd, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
if (enumerate_fd < 0)
return log_debug_errno(enumerate_fd, "Failed to reopen '%s/%s' as directory: %m",
empty_to_root(root_path), skip_leading_slash(inode_path));
_cleanup_free_ DirectoryEntries *de = NULL;
r = readdir_all(dir_fd, 0, &de);
r = readdir_all(enumerate_fd, 0, &de);
if (r < 0)
return log_debug_errno(r, "Failed to read directory '%s/%s': %m",
empty_to_root(toplevel_path), skip_leading_slash(inode_path));
empty_to_root(root_path), skip_leading_slash(inode_path));
_cleanup_(pick_result_done) PickResult best = PICK_RESULT_NULL;
@@ -457,8 +462,9 @@ static int make_choice(
return log_oom_debug();
_cleanup_(pick_result_done) PickResult found = PICK_RESULT_NULL;
r = pin_choice(toplevel_path,
toplevel_fd,
r = pin_choice(root_path,
root_fd,
dir_fd,
p,
/* _inode_fd= */ -EBADF,
found_tries_left,
@@ -501,8 +507,9 @@ static int make_choice(
}
static int path_pick_one(
const char *toplevel_path,
int toplevel_fd,
const char *root_path,
int root_fd,
int dir_fd,
const char *path,
const PickFilter *filter,
PickFlags flags,
@@ -513,7 +520,8 @@ static int path_pick_one(
uint32_t filter_type_mask;
int r;
assert(wildcard_fd_is_valid(toplevel_fd));
assert(wildcard_fd_is_valid(root_fd));
assert(wildcard_fd_is_valid(dir_fd));
assert(path);
assert(filter);
assert(ret);
@@ -537,8 +545,9 @@ static int path_pick_one(
/* Explicit basename specified, then shortcut things and do .v mode regardless of the path name. */
if (filter->basename)
return make_choice(
toplevel_path,
toplevel_fd,
root_path,
root_fd,
dir_fd,
path,
/* inode_fd= */ -EBADF,
filter,
@@ -623,8 +632,9 @@ static int path_pick_one(
}
return make_choice(
toplevel_path,
toplevel_fd,
root_path,
root_fd,
dir_fd,
enumeration_path,
/* inode_fd= */ -EBADF,
&(const PickFilter) {
@@ -640,8 +650,9 @@ static int path_pick_one(
bypass:
/* Don't make any choice, but just use the passed path literally */
return pin_choice(
toplevel_path,
toplevel_fd,
root_path,
root_fd,
dir_fd,
path,
/* inode_fd= */ -EBADF,
/* tries_left= */ UINT_MAX,
@@ -651,8 +662,9 @@ bypass:
ret);
}
int path_pick(const char *toplevel_path,
int toplevel_fd,
int path_pick(const char *root_path,
int root_fd,
int dir_fd,
const char *path,
const PickFilter filters[],
size_t n_filters,
@@ -662,7 +674,8 @@ int path_pick(const char *toplevel_path,
_cleanup_(pick_result_done) PickResult best = PICK_RESULT_NULL;
int r;
assert(wildcard_fd_is_valid(toplevel_fd));
assert(wildcard_fd_is_valid(root_fd));
assert(wildcard_fd_is_valid(dir_fd));
assert(path);
assert(filters || n_filters == 0);
assert(ret);
@@ -671,7 +684,7 @@ int path_pick(const char *toplevel_path,
for (size_t i = 0; i < n_filters; i++) {
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
r = path_pick_one(toplevel_path, toplevel_fd, path, &filters[i], flags, &result);
r = path_pick_one(root_path, root_fd, dir_fd, path, &filters[i], flags, &result);
if (r < 0)
return r;
if (r == 0)
@@ -717,8 +730,9 @@ int path_pick_update_warn(
/* This updates the first argument if needed! */
r = path_pick(/* toplevel_path= */ NULL,
/* toplevel_fd= */ AT_FDCWD,
r = path_pick(/* root_path= */ NULL,
/* root_fd= */ AT_FDCWD,
/* dir_fd= */ AT_FDCWD,
*path,
filters,
n_filters,
+3 -2
View File
@@ -45,8 +45,9 @@ void pick_result_done(PickResult *p);
int pick_result_compare(const PickResult *a, const PickResult *b, PickFlags flags);
int path_pick(const char *toplevel_path,
int toplevel_fd,
int path_pick(const char *root_path,
int root_fd,
int dir_fd,
const char *path,
const PickFilter filters[],
size_t n_filters,
+24 -24
View File
@@ -48,7 +48,7 @@ TEST(path_pick) {
};
if (IN_SET(native_architecture(), ARCHITECTURE_X86, ARCHITECTURE_X86_64)) {
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_STREQ(result.version, "99");
ASSERT_EQ(result.architecture, ARCHITECTURE_X86);
@@ -58,7 +58,7 @@ TEST(path_pick) {
}
filter.architecture = ARCHITECTURE_X86_64;
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_STREQ(result.version, "55");
ASSERT_EQ(result.architecture, ARCHITECTURE_X86_64);
@@ -66,7 +66,7 @@ TEST(path_pick) {
pick_result_done(&result);
filter.architecture = ARCHITECTURE_IA64;
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_STREQ(result.version, "5");
ASSERT_EQ(result.architecture, ARCHITECTURE_IA64);
@@ -75,7 +75,7 @@ TEST(path_pick) {
filter.architecture = _ARCHITECTURE_INVALID;
filter.version = "5";
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_STREQ(result.version, "5");
if (native_architecture() != ARCHITECTURE_IA64) {
@@ -85,7 +85,7 @@ TEST(path_pick) {
pick_result_done(&result);
filter.architecture = ARCHITECTURE_IA64;
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_STREQ(result.version, "5");
ASSERT_EQ(result.architecture, ARCHITECTURE_IA64);
@@ -93,7 +93,7 @@ TEST(path_pick) {
pick_result_done(&result);
filter.architecture = ARCHITECTURE_CRIS;
ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_EQ(result.st.st_mode, MODE_INVALID);
ASSERT_NULL(result.version);
ASSERT_LT(result.architecture, 0);
@@ -104,7 +104,7 @@ TEST(path_pick) {
filter.architecture = _ARCHITECTURE_INVALID;
filter.version = NULL;
if (IN_SET(native_architecture(), ARCHITECTURE_X86_64, ARCHITECTURE_X86)) {
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_STREQ(result.version, "55");
@@ -123,7 +123,7 @@ TEST(path_pick) {
pp = ASSERT_NOT_NULL(path_join(p, "foo.v/foo___.raw"));
if (IN_SET(native_architecture(), ARCHITECTURE_X86, ARCHITECTURE_X86_64)) {
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_STREQ(result.version, "55");
ASSERT_EQ(result.architecture, native_architecture());
@@ -137,10 +137,10 @@ TEST(path_pick) {
pp = ASSERT_NOT_NULL(path_join(p, "foo.v/foo_5.raw"));
filter.type_mask = UINT32_C(1) << DT_DIR;
ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
filter.type_mask = UINT32_C(1) << DT_REG;
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_NULL(result.version);
ASSERT_EQ(result.architecture, _ARCHITECTURE_INVALID);
@@ -153,7 +153,7 @@ TEST(path_pick) {
filter.architecture = ARCHITECTURE_S390;
filter.basename = "quux";
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_STREQ(result.version, "2");
ASSERT_EQ(result.tries_left, 4U);
@@ -209,7 +209,7 @@ TEST(pick_filter_image_any) {
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
/* Test pick_filter_image_any: should pick the highest version, which is the directory test_5 */
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result));
ASSERT_TRUE(S_ISDIR(result.st.st_mode));
ASSERT_STREQ(result.version, "5");
ASSERT_TRUE(endswith(result.path, "/test_5"));
@@ -219,14 +219,14 @@ TEST(pick_filter_image_any) {
ASSERT_OK(unlinkat(sub_dfd, "test_4", AT_REMOVEDIR));
ASSERT_OK(unlinkat(sub_dfd, "test_5", AT_REMOVEDIR));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_STREQ(result.version, "3");
ASSERT_TRUE(endswith(result.path, "/test_3.raw"));
pick_result_done(&result);
/* Verify that pick_filter_image_raw only matches .raw files */
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE, &result));
ASSERT_TRUE(S_ISREG(result.st.st_mode));
ASSERT_STREQ(result.version, "3");
ASSERT_TRUE(endswith(result.path, "/test_3.raw"));
@@ -239,12 +239,12 @@ TEST(pick_filter_image_any) {
ASSERT_OK(unlinkat(sub_dfd, "test_3.raw", 0));
/* Now only test_10.txt, test_11.img, and test_12 remain - none should match */
ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result));
ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result));
/* But if we add a directory, it should be picked */
ASSERT_OK(mkdirat(sub_dfd, "test_6", 0755));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result));
ASSERT_TRUE(S_ISDIR(result.st.st_mode));
ASSERT_STREQ(result.version, "6");
ASSERT_TRUE(endswith(result.path, "/test_6"));
@@ -263,7 +263,7 @@ TEST(pick_filter_image_any) {
pick_result_done(&result);
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result));
ASSERT_TRUE(S_ISDIR(result.st.st_mode));
ASSERT_STREQ(result.version, "2");
ASSERT_TRUE(endswith(result.path, "/myimage_2"));
@@ -273,7 +273,7 @@ TEST(pick_filter_image_any) {
ASSERT_OK(unlinkat(sub_dfd, "myimage_1", AT_REMOVEDIR));
ASSERT_OK(unlinkat(sub_dfd, "myimage_2", AT_REMOVEDIR));
ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result));
ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result));
}
TEST(path_pick_resolve) {
@@ -294,26 +294,26 @@ TEST(path_pick_resolve) {
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
/* Test without PICK_RESOLVE - should return the symlink path */
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result));
ASSERT_STREQ(result.version, "2");
ASSERT_TRUE(endswith(result.path, "/resolve_2.raw"));
pick_result_done(&result);
/* Test with PICK_RESOLVE - should return the resolved (target) path */
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE|PICK_RESOLVE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE|PICK_RESOLVE, &result));
ASSERT_STREQ(result.version, "2");
ASSERT_TRUE(endswith(result.path, "/target_file.raw"));
pick_result_done(&result);
/* Test pick_filter_image_dir without PICK_RESOLVE */
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result));
ASSERT_TRUE(S_ISDIR(result.st.st_mode));
ASSERT_STREQ(result.version, "1");
ASSERT_TRUE(endswith(result.path, "/resolve_1"));
pick_result_done(&result);
/* Test pick_filter_image_dir with PICK_RESOLVE */
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE|PICK_RESOLVE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE|PICK_RESOLVE, &result));
ASSERT_TRUE(S_ISDIR(result.st.st_mode));
ASSERT_STREQ(result.version, "1");
ASSERT_TRUE(endswith(result.path, "/target_dir"));
@@ -323,12 +323,12 @@ TEST(path_pick_resolve) {
ASSERT_OK(symlinkat("target_file.raw", dfd, "intermediate_link.raw"));
ASSERT_OK(symlinkat("../intermediate_link.raw", sub_dfd, "resolve_3.raw"));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE, &result));
ASSERT_STREQ(result.version, "3");
ASSERT_TRUE(endswith(result.path, "/resolve_3.raw"));
pick_result_done(&result);
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE|PICK_RESOLVE, &result));
ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE|PICK_RESOLVE, &result));
ASSERT_STREQ(result.version, "3");
/* The chain should be fully resolved to target_file.raw */
ASSERT_TRUE(endswith(result.path, "/target_file.raw"));
+3 -2
View File
@@ -237,8 +237,9 @@ static int run(int argc, char *argv[]) {
return log_error_errno(r, "Failed to make path '%s' absolute: %m", *i);
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
r = path_pick(/* toplevel_path= */ NULL,
/* toplevel_fd= */ AT_FDCWD,
r = path_pick(/* root_path= */ NULL,
/* root_fd= */ AT_FDCWD,
/* dir_fd= */ AT_FDCWD,
p,
&(PickFilter) {
.basename = arg_filter_basename,