Merge pull request #26784 from DaanDeMeyer/chase-fix
Allow creating files and directories with chase_symlinks_open() and further improvements
This commit is contained in:
+77
-76
@@ -92,26 +92,15 @@ int chase_symlinks_at(
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
/* Either the file may be missing, or we return an fd to the final object, but both make no sense */
|
||||
if ((flags & CHASE_NONEXISTENT) && ret_fd)
|
||||
return -EINVAL;
|
||||
if ((flags & CHASE_NONEXISTENT))
|
||||
assert(!ret_fd);
|
||||
|
||||
if ((flags & CHASE_STEP) && ret_fd)
|
||||
return -EINVAL;
|
||||
|
||||
if (FLAGS_SET(flags, CHASE_MKDIR_0755|CHASE_NONEXISTENT))
|
||||
return -EINVAL;
|
||||
if ((flags & CHASE_STEP))
|
||||
assert(!ret_fd);
|
||||
|
||||
if (isempty(path))
|
||||
path = ".";
|
||||
|
||||
if (flags & CHASE_PARENT) {
|
||||
r = path_extract_directory(path, &buffer);
|
||||
if (r == -EDESTADDRREQ)
|
||||
path = "."; /* If we don't have a parent directory, fall back to the dir_fd directory. */
|
||||
else if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* This function resolves symlinks of the path relative to the given directory file descriptor. If
|
||||
* CHASE_SYMLINKS_RESOLVE_IN_ROOT is specified and a directory file descriptor is provided, symlinks
|
||||
* are resolved relative to the given directory file descriptor. Otherwise, they are resolved
|
||||
@@ -292,6 +281,9 @@ int chase_symlinks_at(
|
||||
previous_stat = st;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(flags, CHASE_PARENT) && isempty(todo))
|
||||
break;
|
||||
|
||||
close_and_replace(fd, fd_parent);
|
||||
|
||||
continue;
|
||||
@@ -306,20 +298,23 @@ int chase_symlinks_at(
|
||||
if (!isempty(todo) && !path_is_safe(todo))
|
||||
return r;
|
||||
|
||||
if (flags & CHASE_NONEXISTENT) {
|
||||
if (FLAGS_SET(flags, CHASE_MKDIR_0755) && !isempty(todo)) {
|
||||
child = open_mkdir_at(fd, first, O_CLOEXEC|O_PATH|O_EXCL, 0755);
|
||||
if (child < 0)
|
||||
return child;
|
||||
} else if (FLAGS_SET(flags, CHASE_PARENT) && isempty(todo)) {
|
||||
if (!path_extend(&done, first))
|
||||
return -ENOMEM;
|
||||
|
||||
break;
|
||||
} else if (flags & CHASE_NONEXISTENT) {
|
||||
if (!path_extend(&done, first, todo))
|
||||
return -ENOMEM;
|
||||
|
||||
exists = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(flags & CHASE_MKDIR_0755))
|
||||
} else
|
||||
return r;
|
||||
|
||||
child = open_mkdir_at(fd, first, O_CLOEXEC|O_PATH|O_EXCL, 0755);
|
||||
if (child < 0)
|
||||
return child;
|
||||
}
|
||||
|
||||
if (fstat(child, &st) < 0)
|
||||
@@ -394,11 +389,14 @@ int chase_symlinks_at(
|
||||
if (!path_extend(&done, first))
|
||||
return -ENOMEM;
|
||||
|
||||
if (FLAGS_SET(flags, CHASE_PARENT) && isempty(todo))
|
||||
break;
|
||||
|
||||
/* And iterate again, but go one directory further down. */
|
||||
close_and_replace(fd, child);
|
||||
}
|
||||
|
||||
if (flags & (CHASE_PARENT|CHASE_MKDIR_0755)) {
|
||||
if (flags & CHASE_PARENT) {
|
||||
r = fd_verify_directory(fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -522,7 +520,9 @@ int chase_symlinks(
|
||||
return r;
|
||||
|
||||
if (ret_path) {
|
||||
char *q = path_join(empty_to_root(root), p);
|
||||
_cleanup_free_ char *q = NULL;
|
||||
|
||||
q = path_join(empty_to_root(root), p);
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -549,28 +549,37 @@ int chase_symlinks_and_open(
|
||||
char **ret_path) {
|
||||
|
||||
_cleanup_close_ int path_fd = -EBADF;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
_cleanup_free_ char *p = NULL, *fname = NULL;
|
||||
mode_t mode = open_flags & O_DIRECTORY ? 0755 : 0644;
|
||||
const char *q;
|
||||
int r;
|
||||
|
||||
if (chase_flags & (CHASE_NONEXISTENT|CHASE_STEP))
|
||||
return -EINVAL;
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
|
||||
|
||||
if (empty_or_root(root) && !ret_path &&
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
|
||||
/* Shortcut this call if none of the special features of this call are requested */
|
||||
r = open(path, open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
return RET_NERRNO(xopenat(AT_FDCWD, path,
|
||||
open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0),
|
||||
mode));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
|
||||
r = chase_symlinks(path, root, CHASE_PARENT|chase_flags, &p, &path_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(path_fd >= 0);
|
||||
|
||||
r = fd_reopen(path_fd, open_flags);
|
||||
assert_se(q = path_startswith(p, empty_to_root(root)));
|
||||
if (isempty(q))
|
||||
q = ".";
|
||||
|
||||
r = path_extract_filename(q, &fname);
|
||||
if (r < 0 && r != -EADDRNOTAVAIL)
|
||||
return r;
|
||||
|
||||
if (FLAGS_SET(chase_flags, CHASE_PARENT) || r == -EADDRNOTAVAIL)
|
||||
r = fd_reopen(path_fd, open_flags);
|
||||
else
|
||||
r = xopenat(path_fd, fname, open_flags|O_NOFOLLOW, mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -592,10 +601,8 @@ int chase_symlinks_and_opendir(
|
||||
DIR *d;
|
||||
int r;
|
||||
|
||||
if (!ret_dir)
|
||||
return -EINVAL;
|
||||
if (chase_flags & (CHASE_NONEXISTENT|CHASE_STEP))
|
||||
return -EINVAL;
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
|
||||
assert(ret_dir);
|
||||
|
||||
if (empty_or_root(root) && !ret_path &&
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
|
||||
@@ -629,21 +636,18 @@ int chase_symlinks_and_stat(
|
||||
const char *root,
|
||||
ChaseSymlinksFlags chase_flags,
|
||||
char **ret_path,
|
||||
struct stat *ret_stat,
|
||||
int *ret_fd) {
|
||||
struct stat *ret_stat) {
|
||||
|
||||
_cleanup_close_ int path_fd = -EBADF;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
|
||||
assert(ret_stat);
|
||||
|
||||
if (chase_flags & (CHASE_NONEXISTENT|CHASE_STEP))
|
||||
return -EINVAL;
|
||||
|
||||
if (empty_or_root(root) && !ret_path &&
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0 && !ret_fd) {
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
|
||||
/* Shortcut this call if none of the special features of this call are requested */
|
||||
|
||||
if (fstatat(AT_FDCWD, path, ret_stat, FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0) < 0)
|
||||
@@ -662,8 +666,6 @@ int chase_symlinks_and_stat(
|
||||
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(p);
|
||||
if (ret_fd)
|
||||
*ret_fd = TAKE_FD(path_fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -673,20 +675,17 @@ int chase_symlinks_and_access(
|
||||
const char *root,
|
||||
ChaseSymlinksFlags chase_flags,
|
||||
int access_mode,
|
||||
char **ret_path,
|
||||
int *ret_fd) {
|
||||
char **ret_path) {
|
||||
|
||||
_cleanup_close_ int path_fd = -EBADF;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
if (chase_flags & (CHASE_NONEXISTENT|CHASE_STEP))
|
||||
return -EINVAL;
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
|
||||
|
||||
if (empty_or_root(root) && !ret_path &&
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0 && !ret_fd) {
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
|
||||
/* Shortcut this call if none of the special features of this call are requested */
|
||||
|
||||
if (faccessat(AT_FDCWD, path, access_mode, FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0) < 0)
|
||||
@@ -706,8 +705,6 @@ int chase_symlinks_and_access(
|
||||
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(p);
|
||||
if (ret_fd)
|
||||
*ret_fd = TAKE_FD(path_fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -725,6 +722,7 @@ int chase_symlinks_and_fopen_unlocked(
|
||||
int mode_flags, r;
|
||||
|
||||
assert(path);
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_PARENT)));
|
||||
assert(open_flags);
|
||||
assert(ret_file);
|
||||
|
||||
@@ -753,31 +751,26 @@ int chase_symlinks_and_unlink(
|
||||
int unlink_flags,
|
||||
char **ret_path) {
|
||||
|
||||
_cleanup_free_ char *p = NULL, *rp = NULL, *fname = NULL;
|
||||
_cleanup_free_ char *p = NULL, *fname = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_PARENT)));
|
||||
|
||||
r = path_extract_filename(path, &fname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fd = chase_symlinks_and_open(path, root, chase_flags|CHASE_PARENT, O_PATH|O_DIRECTORY|O_CLOEXEC, ret_path ? &p : NULL);
|
||||
fd = chase_symlinks_and_open(path, root, chase_flags|CHASE_PARENT|CHASE_NOFOLLOW, O_PATH|O_DIRECTORY|O_CLOEXEC, &p);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (p) {
|
||||
rp = path_join(p, fname);
|
||||
if (!rp)
|
||||
return -ENOMEM;
|
||||
}
|
||||
r = path_extract_filename(p, &fname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (unlinkat(fd, fname, unlink_flags) < 0)
|
||||
return -errno;
|
||||
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(rp);
|
||||
*ret_path = TAKE_PTR(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -790,23 +783,31 @@ int chase_symlinks_at_and_open(
|
||||
char **ret_path) {
|
||||
|
||||
_cleanup_close_ int path_fd = -EBADF;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
_cleanup_free_ char *p = NULL, *fname = NULL;
|
||||
mode_t mode = open_flags & O_DIRECTORY ? 0755 : 0644;
|
||||
int r;
|
||||
|
||||
if (chase_flags & (CHASE_NONEXISTENT|CHASE_STEP))
|
||||
return -EINVAL;
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
|
||||
|
||||
if (dir_fd == AT_FDCWD && !ret_path &&
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
|
||||
/* Shortcut this call if none of the special features of this call are requested */
|
||||
return RET_NERRNO(openat(dir_fd, path, open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0)));
|
||||
return RET_NERRNO(xopenat(dir_fd, path,
|
||||
open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0),
|
||||
mode));
|
||||
|
||||
r = chase_symlinks_at(dir_fd, path, chase_flags, ret_path ? &p : NULL, &path_fd);
|
||||
r = chase_symlinks_at(dir_fd, path, chase_flags|CHASE_PARENT, &p, &path_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(path_fd >= 0);
|
||||
|
||||
r = fd_reopen(path_fd, open_flags);
|
||||
r = path_extract_filename(p, &fname);
|
||||
if (r < 0 && r != -EDESTADDRREQ)
|
||||
return r;
|
||||
|
||||
if (FLAGS_SET(chase_flags, CHASE_PARENT) || r == -EDESTADDRREQ)
|
||||
r = fd_reopen(path_fd, open_flags);
|
||||
else
|
||||
r = xopenat(path_fd, fname, open_flags|O_NOFOLLOW, mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -20,8 +20,10 @@ typedef enum ChaseSymlinksFlags {
|
||||
CHASE_AT_RESOLVE_IN_ROOT = 1 << 8, /* Same as openat2()'s RESOLVE_IN_ROOT flag, symlinks are resolved
|
||||
* relative to the given directory fd instead of root. */
|
||||
CHASE_PROHIBIT_SYMLINKS = 1 << 9, /* Refuse all symlinks */
|
||||
CHASE_PARENT = 1 << 10, /* Chase the parent directory of the given path. */
|
||||
CHASE_MKDIR_0755 = 1 << 11, /* Create any missing directories in the given path. */
|
||||
CHASE_PARENT = 1 << 10, /* Chase the parent directory of the given path. Note that the
|
||||
* full path is still stored in ret_path and only the returned
|
||||
* file descriptor will point to the parent directory. */
|
||||
CHASE_MKDIR_0755 = 1 << 11, /* Create any missing parent directories in the given path. */
|
||||
} ChaseSymlinksFlags;
|
||||
|
||||
bool unsafe_transition(const struct stat *a, const struct stat *b);
|
||||
@@ -33,8 +35,8 @@ int chase_symlinks(const char *path_with_prefix, const char *root, ChaseSymlinks
|
||||
|
||||
int chase_symlinks_and_open(const char *path, const char *root, ChaseSymlinksFlags chase_flags, int open_flags, char **ret_path);
|
||||
int chase_symlinks_and_opendir(const char *path, const char *root, ChaseSymlinksFlags chase_flags, char **ret_path, DIR **ret_dir);
|
||||
int chase_symlinks_and_stat(const char *path, const char *root, ChaseSymlinksFlags chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd);
|
||||
int chase_symlinks_and_access(const char *path, const char *root, ChaseSymlinksFlags chase_flags, int access_mode, char **ret_path, int *ret_fd);
|
||||
int chase_symlinks_and_stat(const char *path, const char *root, ChaseSymlinksFlags chase_flags, char **ret_path, struct stat *ret_stat);
|
||||
int chase_symlinks_and_access(const char *path, const char *root, ChaseSymlinksFlags chase_flags, int access_mode, char **ret_path);
|
||||
int chase_symlinks_and_fopen_unlocked(const char *path, const char *root, ChaseSymlinksFlags chase_flags, const char *open_flags, char **ret_path, FILE **ret_file);
|
||||
int chase_symlinks_and_unlink(const char *path, const char *root, ChaseSymlinksFlags chase_flags, int unlink_flags, char **ret_path);
|
||||
|
||||
|
||||
+46
-27
@@ -988,7 +988,6 @@ int parse_cifs_service(
|
||||
int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
|
||||
_cleanup_close_ int fd = -EBADF, parent_fd = -EBADF;
|
||||
_cleanup_free_ char *fname = NULL;
|
||||
bool made;
|
||||
int r;
|
||||
|
||||
/* Creates a directory with mkdirat() and then opens it, in the "most atomic" fashion we can
|
||||
@@ -1028,33 +1027,11 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
|
||||
path = fname;
|
||||
}
|
||||
|
||||
r = RET_NERRNO(mkdirat(dirfd, path, mode));
|
||||
if (r == -EEXIST) {
|
||||
if (FLAGS_SET(flags, O_EXCL))
|
||||
return -EEXIST;
|
||||
|
||||
made = false;
|
||||
} else if (r < 0)
|
||||
return r;
|
||||
else
|
||||
made = true;
|
||||
|
||||
fd = RET_NERRNO(openat(dirfd, path, (flags & ~O_EXCL)|O_DIRECTORY|O_NOFOLLOW));
|
||||
if (fd < 0) {
|
||||
if (fd == -ENOENT) /* We got ENOENT? then someone else immediately removed it after we
|
||||
* created it. In that case let's return immediately without unlinking
|
||||
* anything, because there simply isn't anything to unlink anymore. */
|
||||
return -ENOENT;
|
||||
if (fd == -ELOOP) /* is a symlink? exists already → created by someone else, don't unlink */
|
||||
return -EEXIST;
|
||||
if (fd == -ENOTDIR) /* not a directory? exists already → created by someone else, don't unlink */
|
||||
return -EEXIST;
|
||||
|
||||
if (made)
|
||||
(void) unlinkat(dirfd, path, AT_REMOVEDIR);
|
||||
|
||||
fd = xopenat(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, mode);
|
||||
if (IN_SET(fd, -ELOOP, -ENOTDIR))
|
||||
return -EEXIST;
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
}
|
||||
|
||||
return TAKE_FD(fd);
|
||||
}
|
||||
@@ -1105,3 +1082,45 @@ int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, b
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
int xopenat(int dir_fd, const char *path, int flags, mode_t mode) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
bool made = false;
|
||||
int r;
|
||||
|
||||
if (FLAGS_SET(flags, O_DIRECTORY|O_CREAT)) {
|
||||
r = RET_NERRNO(mkdirat(dir_fd, path, mode));
|
||||
if (r == -EEXIST) {
|
||||
if (FLAGS_SET(flags, O_EXCL))
|
||||
return -EEXIST;
|
||||
|
||||
made = false;
|
||||
} else if (r < 0)
|
||||
return r;
|
||||
else
|
||||
made = true;
|
||||
|
||||
flags &= ~(O_EXCL|O_CREAT);
|
||||
}
|
||||
|
||||
fd = RET_NERRNO(openat(dir_fd, path, flags, mode));
|
||||
if (fd < 0) {
|
||||
if (IN_SET(fd,
|
||||
/* We got ENOENT? then someone else immediately removed it after we
|
||||
* created it. In that case let's return immediately without unlinking
|
||||
* anything, because there simply isn't anything to unlink anymore. */
|
||||
-ENOENT,
|
||||
/* is a symlink? exists already → created by someone else, don't unlink */
|
||||
-ELOOP,
|
||||
/* not a directory? exists already → created by someone else, don't unlink */
|
||||
-ENOTDIR))
|
||||
return fd;
|
||||
|
||||
if (made)
|
||||
(void) unlinkat(dir_fd, path, AT_REMOVEDIR);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
return TAKE_FD(fd);
|
||||
}
|
||||
|
||||
@@ -127,3 +127,5 @@ int parse_cifs_service(const char *s, char **ret_host, char **ret_service, char
|
||||
int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode);
|
||||
|
||||
int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created);
|
||||
|
||||
int xopenat(int dir_fd, const char *path, int flags, mode_t mode);
|
||||
|
||||
@@ -145,7 +145,7 @@ int null_or_empty_path_with_root(const char *fn, const char *root) {
|
||||
if (path_equal_ptr(path_startswith(fn, root ?: "/"), "dev/null"))
|
||||
return true;
|
||||
|
||||
r = chase_symlinks_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st, NULL);
|
||||
r = chase_symlinks_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -664,7 +664,7 @@ static int install_variables(
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = chase_symlinks_and_access(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL, NULL);
|
||||
r = chase_symlinks_and_access(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
|
||||
@@ -560,7 +560,7 @@ static void deref_unlink_file(Hashmap *known_files, const char *fn, const char *
|
||||
return;
|
||||
|
||||
if (arg_dry_run) {
|
||||
r = chase_symlinks_and_access(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, &path, NULL);
|
||||
r = chase_symlinks_and_access(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, &path);
|
||||
if (r < 0)
|
||||
log_info_errno(r, "Unable to determine whether \"%s\" exists, ignoring: %m", fn);
|
||||
else
|
||||
|
||||
@@ -1768,7 +1768,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Path to init binary '%s' not absolute.", init);
|
||||
|
||||
r = chase_symlinks_and_access(init, root, CHASE_PREFIX_ROOT, X_OK, NULL, NULL);
|
||||
r = chase_symlinks_and_access(init, root, CHASE_PREFIX_ROOT, X_OK, NULL);
|
||||
if (r == -EACCES)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Init binary %s is not executable.", init);
|
||||
|
||||
@@ -981,7 +981,7 @@ static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp)
|
||||
return r;
|
||||
assert(r > 0);
|
||||
|
||||
r = chase_symlinks_and_access(filename, arg_root, CHASE_PREFIX_ROOT, F_OK, &resolved, NULL);
|
||||
r = chase_symlinks_and_access(filename, arg_root, CHASE_PREFIX_ROOT, F_OK, &resolved);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Cannot access \"%s%s\": %m", strempty(arg_root), filename);
|
||||
|
||||
|
||||
@@ -926,7 +926,7 @@ static int mount_inaccessible(const char *dest, CustomMount *m) {
|
||||
assert(dest);
|
||||
assert(m);
|
||||
|
||||
r = chase_symlinks_and_stat(m->destination, dest, CHASE_PREFIX_ROOT, &where, &st, NULL);
|
||||
r = chase_symlinks_and_stat(m->destination, dest, CHASE_PREFIX_ROOT, &where, &st);
|
||||
if (r < 0) {
|
||||
log_full_errno(m->graceful ? LOG_DEBUG : LOG_ERR, r, "Failed to resolve %s/%s: %m", dest, m->destination);
|
||||
return m->graceful ? 0 : r;
|
||||
|
||||
@@ -4021,7 +4021,7 @@ static int add_exclude_path(const char *path, Hashmap **denylist, DenyType type)
|
||||
if (!st)
|
||||
return log_oom();
|
||||
|
||||
r = chase_symlinks_and_stat(path, arg_root, CHASE_PREFIX_ROOT, NULL, st, NULL);
|
||||
r = chase_symlinks_and_stat(path, arg_root, CHASE_PREFIX_ROOT, NULL, st);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
|
||||
@@ -1269,7 +1269,7 @@ static void boot_entry_file_list(
|
||||
assert(p);
|
||||
assert(ret_status);
|
||||
|
||||
int status = chase_symlinks_and_access(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL, NULL);
|
||||
int status = chase_symlinks_and_access(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL);
|
||||
|
||||
/* Note that this shows two '/' between the root and the file. This is intentional to highlight (in
|
||||
* the absence of color support) to the user that the boot loader is only interested in the second
|
||||
|
||||
@@ -21,11 +21,11 @@ static int same_file_in_root(
|
||||
struct stat sta, stb;
|
||||
int r;
|
||||
|
||||
r = chase_symlinks_and_stat(a, root, CHASE_PREFIX_ROOT, NULL, &sta, NULL);
|
||||
r = chase_symlinks_and_stat(a, root, CHASE_PREFIX_ROOT, NULL, &sta);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = chase_symlinks_and_stat(b, root, CHASE_PREFIX_ROOT, NULL, &stb, NULL);
|
||||
r = chase_symlinks_and_stat(b, root, CHASE_PREFIX_ROOT, NULL, &stb);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
+69
-22
@@ -331,10 +331,10 @@ TEST(chase_symlinks) {
|
||||
}
|
||||
|
||||
assert_se(lstat(p, &st) >= 0);
|
||||
r = chase_symlinks_and_unlink(p, NULL, 0, 0, &result);
|
||||
r = chase_symlinks_and_unlink(p, NULL, 0, 0, &result);
|
||||
assert_se(r == 0);
|
||||
assert_se(path_equal(result, p));
|
||||
result = mfree(result);
|
||||
assert_se(r == 0);
|
||||
assert_se(lstat(p, &st) == -1 && errno == ENOENT);
|
||||
|
||||
/* Test CHASE_NOFOLLOW */
|
||||
@@ -426,18 +426,6 @@ TEST(chase_symlinks) {
|
||||
assert_se(chase_symlinks("top/dot/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG);
|
||||
assert_se(chase_symlinks("top/dot/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG);
|
||||
|
||||
/* Test CHASE_PARENT */
|
||||
|
||||
assert_se(chase_symlinks("/chase/parent", temp, CHASE_PREFIX_ROOT|CHASE_PARENT|CHASE_NONEXISTENT, &result, NULL) >= 0);
|
||||
p = strjoina(temp, "/chase");
|
||||
assert_se(streq(p, result));
|
||||
result = mfree(result);
|
||||
assert_se(chase_symlinks("/chase", temp, CHASE_PREFIX_ROOT|CHASE_PARENT|CHASE_NONEXISTENT, &result, NULL) >= 0);
|
||||
assert_se(streq(temp, result));
|
||||
result = mfree(result);
|
||||
assert_se(chase_symlinks("/", temp, CHASE_PREFIX_ROOT|CHASE_PARENT|CHASE_NONEXISTENT, NULL, NULL) == -EADDRNOTAVAIL);
|
||||
assert_se(chase_symlinks(".", temp, CHASE_PREFIX_ROOT|CHASE_PARENT|CHASE_NONEXISTENT, NULL, NULL) == -EADDRNOTAVAIL);
|
||||
|
||||
cleanup:
|
||||
assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
|
||||
}
|
||||
@@ -479,23 +467,51 @@ TEST(chase_symlinks_at) {
|
||||
|
||||
/* Test CHASE_PARENT */
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, "chase/parent", CHASE_NONEXISTENT|CHASE_PARENT, &result, NULL) >= 0);
|
||||
assert_se(streq(result, "chase"));
|
||||
assert_se((fd = open_mkdir_at(tfd, "chase", O_CLOEXEC, 0755)) >= 0);
|
||||
assert_se(symlinkat("/def", fd, "parent") >= 0);
|
||||
fd = safe_close(fd);
|
||||
|
||||
/* Make sure that when we chase a symlink parent directory, that we chase the parent directory of the
|
||||
* symlink target and not the symlink itself. But if we add CHASE_NOFOLLOW, we get the parent
|
||||
* directory of the symlink itself. */
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, "chase/parent", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT, &result, &fd) >= 0);
|
||||
assert_se(faccessat(fd, "def", F_OK, 0) >= 0);
|
||||
assert_se(streq(result, "def"));
|
||||
fd = safe_close(fd);
|
||||
result = mfree(result);
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, "chase", CHASE_NONEXISTENT|CHASE_PARENT, &result, NULL) >= 0);
|
||||
assert_se(chase_symlinks_at(tfd, "chase/parent", CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_NOFOLLOW, &result, &fd) >= 0);
|
||||
assert_se(faccessat(fd, "parent", F_OK, AT_SYMLINK_NOFOLLOW) >= 0);
|
||||
assert_se(streq(result, "chase/parent"));
|
||||
fd = safe_close(fd);
|
||||
result = mfree(result);
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, "chase", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT, &result, &fd) >= 0);
|
||||
assert_se(faccessat(fd, "chase", F_OK, 0) >= 0);
|
||||
assert_se(streq(result, "chase"));
|
||||
fd = safe_close(fd);
|
||||
result = mfree(result);
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, "/", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT, &result, NULL) >= 0);
|
||||
assert_se(streq(result, "."));
|
||||
result = mfree(result);
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, ".", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT, &result, NULL) >= 0);
|
||||
assert_se(streq(result, "."));
|
||||
result = mfree(result);
|
||||
|
||||
/* Test CHASE_MKDIR_0755 */
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, "m/k/d/i/r", CHASE_MKDIR_0755, &result, NULL) >= 0);
|
||||
assert_se(faccessat(tfd, "m/k/d/i/r", F_OK, 0) >= 0);
|
||||
assert_se(chase_symlinks_at(tfd, "m/k/d/i/r", CHASE_MKDIR_0755|CHASE_NONEXISTENT, &result, NULL) >= 0);
|
||||
assert_se(faccessat(tfd, "m/k/d/i", F_OK, 0) >= 0);
|
||||
assert_se(RET_NERRNO(faccessat(tfd, "m/k/d/i/r", F_OK, 0)) == -ENOENT);
|
||||
assert_se(streq(result, "m/k/d/i/r"));
|
||||
result = mfree(result);
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, "m/../q", CHASE_MKDIR_0755, &result, NULL) >= 0);
|
||||
assert_se(faccessat(tfd, "q", F_OK, 0) >= 0);
|
||||
assert_se(chase_symlinks_at(tfd, "m/../q", CHASE_MKDIR_0755|CHASE_NONEXISTENT, &result, NULL) >= 0);
|
||||
assert_se(faccessat(tfd, "m", F_OK, 0) >= 0);
|
||||
assert_se(RET_NERRNO(faccessat(tfd, "q", F_OK, 0)) == -ENOENT);
|
||||
assert_se(streq(result, "q"));
|
||||
result = mfree(result);
|
||||
|
||||
@@ -503,8 +519,14 @@ TEST(chase_symlinks_at) {
|
||||
|
||||
/* Test chase_symlinks_at_and_open() */
|
||||
|
||||
fd = chase_symlinks_at_and_open(tfd, "o/p/e/n", CHASE_MKDIR_0755, O_CLOEXEC, NULL);
|
||||
fd = chase_symlinks_at_and_open(tfd, "o/p/e/n/f/i/l/e", CHASE_MKDIR_0755, O_CREAT|O_EXCL|O_CLOEXEC, NULL);
|
||||
assert_se(fd >= 0);
|
||||
assert_se(fd_verify_regular(fd) >= 0);
|
||||
fd = safe_close(fd);
|
||||
|
||||
fd = chase_symlinks_at_and_open(tfd, "o/p/e/n/d/i/r", CHASE_MKDIR_0755, O_DIRECTORY|O_CREAT|O_EXCL|O_CLOEXEC, NULL);
|
||||
assert_se(fd >= 0);
|
||||
assert_se(fd_verify_directory(fd) >= 0);
|
||||
fd = safe_close(fd);
|
||||
}
|
||||
|
||||
@@ -1136,6 +1158,31 @@ TEST(openat_report_new) {
|
||||
assert_se(b);
|
||||
}
|
||||
|
||||
TEST(xopenat) {
|
||||
_cleanup_close_ int tfd = -EBADF, fd = -EBADF;
|
||||
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
|
||||
|
||||
assert_se((tfd = mkdtemp_open(NULL, 0, &t)) >= 0);
|
||||
|
||||
/* Test that xopenat() creates directories if O_DIRECTORY is specified. */
|
||||
|
||||
assert_se((fd = xopenat(tfd, "abc", O_DIRECTORY|O_CREAT|O_EXCL|O_CLOEXEC, 0755)) >= 0);
|
||||
assert_se((fd_verify_directory(fd) >= 0));
|
||||
fd = safe_close(fd);
|
||||
|
||||
assert_se(xopenat(tfd, "abc", O_DIRECTORY|O_CREAT|O_EXCL|O_CLOEXEC, 0755) == -EEXIST);
|
||||
|
||||
assert_se((fd = xopenat(tfd, "abc", O_DIRECTORY|O_CREAT|O_CLOEXEC, 0755)) >= 0);
|
||||
assert_se((fd_verify_directory(fd) >= 0));
|
||||
fd = safe_close(fd);
|
||||
|
||||
/* Test that xopenat() creates regular files if O_DIRECTORY is not specified. */
|
||||
|
||||
assert_se((fd = xopenat(tfd, "def", O_CREAT|O_EXCL|O_CLOEXEC, 0644)) >= 0);
|
||||
assert_se(fd_verify_regular(fd) >= 0);
|
||||
fd = safe_close(fd);
|
||||
}
|
||||
|
||||
static int intro(void) {
|
||||
arg_test_dir = saved_argv[1];
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
Reference in New Issue
Block a user