diff --git a/src/basic/chase.c b/src/basic/chase.c index eb4bda07a6..a6a37978e8 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -190,8 +190,9 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int return -ENOMEM; /* If we receive an absolute path together with AT_FDCWD, we need to return an absolute path, because - * a relative path would be interpreted relative to the current working directory. */ - bool need_absolute = dir_fd == AT_FDCWD && path_is_absolute(path); + * a relative path would be interpreted relative to the current working directory. Also, let's make + * the result absolute when the file descriptor of the root directory is specified. */ + bool need_absolute = (dir_fd == AT_FDCWD && path_is_absolute(path)) || dir_fd_is_root(dir_fd) > 0; if (need_absolute) { done = strdup("/"); if (!done) diff --git a/src/test/test-chase.c b/src/test/test-chase.c index 1e98f5c6ed..52ea21a54c 100644 --- a/src/test/test-chase.c +++ b/src/test/test-chase.c @@ -442,6 +442,34 @@ TEST(chaseat) { assert_se(streq(result, "/usr")); result = mfree(result); + /* If the file descriptor points to the root directory, the result will be absolute. */ + + fd = open("/", O_CLOEXEC | O_DIRECTORY | O_PATH); + assert_se(fd >= 0); + + assert_se(chaseat(fd, p, 0, &result, NULL) >= 0); + assert_se(streq(result, "/usr")); + result = mfree(result); + + assert_se(chaseat(fd, p, CHASE_AT_RESOLVE_IN_ROOT, &result, NULL) >= 0); + assert_se(streq(result, "/usr")); + result = mfree(result); + + fd = safe_close(fd); + + /* If the file descriptor does not point to the root directory, the result will be relative. */ + + assert_se(chaseat(tfd, "abc", CHASE_AT_RESOLVE_IN_ROOT, NULL, NULL) == -ENOENT); + assert_se(chaseat(tfd, "/abc", CHASE_AT_RESOLVE_IN_ROOT, NULL, NULL) == -ENOENT); + + assert_se(chaseat(tfd, "abc", CHASE_AT_RESOLVE_IN_ROOT | CHASE_NONEXISTENT, &result, NULL) >= 0); + assert_se(streq(result, "usr")); + result = mfree(result); + + assert_se(chaseat(tfd, "/abc", CHASE_AT_RESOLVE_IN_ROOT | CHASE_NONEXISTENT, &result, NULL) >= 0); + assert_se(streq(result, "usr")); + result = mfree(result); + /* Test that absolute path or not are the same when resolving relative to a directory file * descriptor and that we always get a relative path back. */