}
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,
_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,
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;
}
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,
_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;
}
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,
/* 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;
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,
}
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,
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);
/* 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,
}
return make_choice(
- toplevel_path,
- toplevel_fd,
+ root_path,
+ root_fd,
+ dir_fd,
enumeration_path,
/* inode_fd= */ -EBADF,
&(const PickFilter) {
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,
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,
_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);
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)
/* 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,
};
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);
}
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);
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);
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) {
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);
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);
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");
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());
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);
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);
_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"));
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"));
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"));
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"));
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) {
_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"));
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"));