1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-25 10:04:04 +03:00

fs-util: readlinkat() supports an empty string

From readlinkat(2):
Since Linux 2.6.39, pathname can be an empty string, in which case the
call operates on the symbolic link referred to by dirfd (which should
have been obtained using open(2) with the O_PATH and O_NOFOLLOW flags).
This commit is contained in:
Yu Watanabe 2024-02-15 07:01:17 +09:00
parent d0aef638ac
commit e4c094c055
2 changed files with 41 additions and 2 deletions

View File

@ -116,7 +116,11 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
int readlinkat_malloc(int fd, const char *p, char **ret) {
size_t l = PATH_MAX;
assert(p);
assert(fd >= 0 || fd == AT_FDCWD);
if (fd < 0 && isempty(p))
return -EISDIR; /* In this case, the fd points to the current working directory, and is
* definitely not a symlink. Let's return earlier. */
for (;;) {
_cleanup_free_ char *c = NULL;
@ -126,7 +130,7 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
if (!c)
return -ENOMEM;
n = readlinkat(fd, p, c, l);
n = readlinkat(fd, strempty(p), c, l);
if (n < 0)
return -errno;

View File

@ -758,4 +758,39 @@ static int intro(void) {
return EXIT_SUCCESS;
}
TEST(readlinkat_malloc) {
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
_cleanup_close_ int tfd = -EBADF, fd = -EBADF;
_cleanup_free_ char *p = NULL, *q = NULL;
const char *expect = "hgoehogefoobar";
tfd = mkdtemp_open(NULL, O_PATH, &t);
assert_se(tfd >= 0);
assert_se(symlinkat(expect, tfd, "linkname") >= 0);
assert_se(readlinkat_malloc(tfd, "linkname", &p) >= 0);
assert_se(streq(p, expect));
p = mfree(p);
fd = openat(tfd, "linkname", O_PATH | O_NOFOLLOW | O_CLOEXEC);
assert_se(fd >= 0);
assert_se(readlinkat_malloc(fd, NULL, &p) >= 0);
assert_se(streq(p, expect));
p = mfree(p);
assert_se(readlinkat_malloc(fd, "", &p) >= 0);
assert_se(streq(p, expect));
p = mfree(p);
fd = safe_close(fd);
assert_se(q = path_join(t, "linkname"));
assert_se(readlinkat_malloc(AT_FDCWD, q, &p) >= 0);
assert_se(streq(p, expect));
p = mfree(p);
assert_se(readlinkat_malloc(INT_MAX, q, &p) >= 0);
assert_se(streq(p, expect));
p = mfree(p);
q = mfree(q);
}
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);