mirror of
https://github.com/systemd/systemd.git
synced 2025-01-12 13:18:14 +03:00
fs-util: add new CHASE_NOFOLLOW flag to chase_symlinks()
This flag mimics what "O_NOFOLLOW|O_PATH" does for open(2) that is chase_symlinks() will not resolve the final pathname component if it's a symlink and instead will return a file descriptor referring to the symlink itself. Note: if CHASE_SAFE is also passed, no safety checking is performed on the transition done if the symlink would have been followed.
This commit is contained in:
parent
7ea5a87f92
commit
1f56e4ce77
@ -695,7 +695,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
||||
if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN|CHASE_STEP)) == CHASE_OPEN) {
|
||||
/* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set
|
||||
* and doesn't care about any of the other special features we provide either. */
|
||||
r = open(path, O_PATH|O_CLOEXEC);
|
||||
r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
@ -850,7 +850,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
||||
fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
|
||||
return -EREMOTE;
|
||||
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
|
||||
char *joined;
|
||||
|
||||
_cleanup_free_ char *destination = NULL;
|
||||
|
@ -73,6 +73,7 @@ enum {
|
||||
CHASE_OPEN = 1 << 4, /* If set, return an O_PATH object to the final component */
|
||||
CHASE_TRAIL_SLASH = 1 << 5, /* If set, any trailing slash will be preserved */
|
||||
CHASE_STEP = 1 << 6, /* If set, just execute a single step of the normalization */
|
||||
CHASE_NOFOLLOW = 1 << 7, /* Only valid with CHASE_OPEN: when the path's right-most component refers to symlink return O_PATH fd of the symlink, rather than following it. */
|
||||
};
|
||||
|
||||
/* How many iterations to execute before returning -ELOOP */
|
||||
|
@ -22,6 +22,7 @@ static void test_chase_symlinks(void) {
|
||||
_cleanup_free_ char *result = NULL;
|
||||
char temp[] = "/tmp/test-chase.XXXXXX";
|
||||
const char *top, *p, *pslash, *q, *qslash;
|
||||
struct stat st;
|
||||
int r, pfd;
|
||||
|
||||
assert_se(mkdtemp(temp));
|
||||
@ -266,6 +267,30 @@ static void test_chase_symlinks(void) {
|
||||
assert_se(sd_id128_equal(a, b));
|
||||
}
|
||||
|
||||
/* Test CHASE_NOFOLLOW */
|
||||
|
||||
p = strjoina(temp, "/target");
|
||||
q = strjoina(temp, "/symlink");
|
||||
assert_se(symlink(p, q) >= 0);
|
||||
pfd = chase_symlinks(q, NULL, CHASE_OPEN|CHASE_NOFOLLOW, &result);
|
||||
assert_se(pfd > 0);
|
||||
assert_se(path_equal(result, q));
|
||||
assert_se(fstat(pfd, &st) >= 0);
|
||||
assert_se(S_ISLNK(st.st_mode));
|
||||
result = mfree(result);
|
||||
|
||||
/* s1 -> s2 -> nonexistent */
|
||||
q = strjoina(temp, "/s1");
|
||||
assert_se(symlink("s2", q) >= 0);
|
||||
p = strjoina(temp, "/s2");
|
||||
assert_se(symlink("nonexistent", p) >= 0);
|
||||
pfd = chase_symlinks(q, NULL, CHASE_OPEN|CHASE_NOFOLLOW, &result);
|
||||
assert_se(pfd > 0);
|
||||
assert_se(path_equal(result, q));
|
||||
assert_se(fstat(pfd, &st) >= 0);
|
||||
assert_se(S_ISLNK(st.st_mode));
|
||||
result = mfree(result);
|
||||
|
||||
/* Test CHASE_ONE */
|
||||
|
||||
p = strjoina(temp, "/start");
|
||||
|
Loading…
Reference in New Issue
Block a user