Merge pull request #27885 from DaanDeMeyer/please-dont-make-me-write-more-openat-helpers

Add more openat like helper functions
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2023-06-07 13:25:33 +02:00
committed by GitHub
25 changed files with 208 additions and 246 deletions
-1
View File
@@ -81,7 +81,6 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
const char *todo;
int r;
assert(path);
assert(!FLAGS_SET(flags, CHASE_PREFIX_ROOT));
assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME));
assert(!FLAGS_SET(flags, CHASE_TRAIL_SLASH|CHASE_EXTRACT_FILENAME));
+14 -14
View File
@@ -9,29 +9,29 @@
#include "chattr-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "macro.h"
#include "string-util.h"
int chattr_full(const char *path,
int fd,
unsigned value,
unsigned mask,
unsigned *ret_previous,
unsigned *ret_final,
ChattrApplyFlags flags) {
int chattr_full(
int dir_fd,
const char *path,
unsigned value,
unsigned mask,
unsigned *ret_previous,
unsigned *ret_final,
ChattrApplyFlags flags) {
_cleanup_close_ int fd_will_close = -EBADF;
_cleanup_close_ int fd = -EBADF;
unsigned old_attr, new_attr;
int set_flags_errno = 0;
struct stat st;
assert(path || fd >= 0);
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
if (fd < 0) {
fd = fd_will_close = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd < 0)
return -errno;
}
fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, /* xopen_flags = */ 0, /* mode = */ 0);
if (fd < 0)
return -errno;
if (fstat(fd, &st) < 0)
return -errno;
+8 -5
View File
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <fcntl.h>
#include <linux/fs.h>
#include <stdbool.h>
#include <stddef.h>
@@ -39,13 +40,15 @@ typedef enum ChattrApplyFlags {
CHATTR_WARN_UNSUPPORTED_FLAGS = 1 << 1,
} ChattrApplyFlags;
int chattr_full(const char *path, int fd, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, ChattrApplyFlags flags);
int chattr_full(int dir_fd, const char *path, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, ChattrApplyFlags flags);
static inline int chattr_at(int dir_fd, const char *path, unsigned value, unsigned mask, unsigned *previous) {
return chattr_full(dir_fd, path, value, mask, previous, NULL, 0);
}
static inline int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) {
return chattr_full(NULL, fd, value, mask, previous, NULL, 0);
return chattr_full(fd, NULL, value, mask, previous, NULL, 0);
}
static inline int chattr_path(const char *path, unsigned value, unsigned mask, unsigned *previous) {
return chattr_full(path, -1, value, mask, previous, NULL, 0);
return chattr_full(AT_FDCWD, path, value, mask, previous, NULL, 0);
}
int read_attr_fd(int fd, unsigned *ret);
@@ -57,5 +60,5 @@ int read_attr_path(const char *p, unsigned *ret);
#define CHATTR_SECRET_FLAGS (FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL)
static inline int chattr_secret(int fd, ChattrApplyFlags flags) {
return chattr_full(NULL, fd, CHATTR_SECRET_FLAGS, CHATTR_SECRET_FLAGS, NULL, NULL, flags|CHATTR_FALLBACK_BITWISE);
return chattr_full(fd, NULL, CHATTR_SECRET_FLAGS, CHATTR_SECRET_FLAGS, NULL, NULL, flags|CHATTR_FALLBACK_BITWISE);
}
+11 -2
View File
@@ -891,12 +891,21 @@ int fd_get_diskseq(int fd, uint64_t *ret) {
return 0;
}
int dir_fd_is_root(int dir_fd) {
int path_is_root_at(int dir_fd, const char *path) {
STRUCT_NEW_STATX_DEFINE(st);
STRUCT_NEW_STATX_DEFINE(pst);
_cleanup_close_ int fd = -EBADF;
int r;
assert(dir_fd >= 0);
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
if (!isempty(path)) {
fd = openat(dir_fd, path, O_PATH|O_CLOEXEC);
if (fd < 0)
return -errno;
dir_fd = fd;
}
r = statx_fallback(dir_fd, ".", 0, STATX_TYPE|STATX_INO|STATX_MNT_ID, &st.sx);
if (r == -ENOTDIR)
+5 -2
View File
@@ -101,9 +101,12 @@ int fd_is_opath(int fd);
int read_nr_open(void);
int fd_get_diskseq(int fd, uint64_t *ret);
int dir_fd_is_root(int dir_fd);
int path_is_root_at(int dir_fd, const char *path);
static inline int dir_fd_is_root(int dir_fd) {
return path_is_root_at(dir_fd, NULL);
}
static inline int dir_fd_is_root_or_cwd(int dir_fd) {
return dir_fd == AT_FDCWD ? true : dir_fd_is_root(dir_fd);
return dir_fd == AT_FDCWD ? true : path_is_root_at(dir_fd, NULL);
}
/* The maximum length a buffer for a /proc/self/fd/<fd> path needs */
-1
View File
@@ -1097,7 +1097,6 @@ int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags
int r;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
if (isempty(path)) {
assert(!FLAGS_SET(open_flags, O_CREAT|O_EXCL));
+5 -13
View File
@@ -207,20 +207,13 @@ bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
return F_TYPE_EQUAL(s->f_type, magic_value);
}
int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
int is_fs_type_at(int dir_fd, const char *path, statfs_f_type_t magic_value) {
struct statfs s;
int r;
if (fstatfs(fd, &s) < 0)
return -errno;
return is_fs_type(&s, magic_value);
}
int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
struct statfs s;
if (statfs(path, &s) < 0)
return -errno;
r = xstatfsat(dir_fd, path, &s);
if (r < 0)
return r;
return is_fs_type(&s, magic_value);
}
@@ -461,7 +454,6 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
_cleanup_close_ int fd = -EBADF;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
assert(ret);
fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0);
+7 -2
View File
@@ -48,8 +48,13 @@ static inline int inode_same(const char *filea, const char *fileb, int flags) {
typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t;
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_;
int fd_is_fs_type(int fd, statfs_f_type_t magic_value);
int path_is_fs_type(const char *path, statfs_f_type_t magic_value);
int is_fs_type_at(int dir_fd, const char *path, statfs_f_type_t magic_value);
static inline int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
return is_fs_type_at(fd, NULL, magic_value);
}
static inline int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
return is_fs_type_at(AT_FDCWD, path, magic_value);
}
bool is_temporary_fs(const struct statfs *s) _pure_;
bool is_network_fs(const struct statfs *s) _pure_;
+1 -1
View File
@@ -1286,7 +1286,7 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) {
}
/* Try to copy as directory? */
r = copy_directory_fd(source_fd, arg_target, COPY_REFLINK|COPY_MERGE_EMPTY|COPY_SIGINT|COPY_HARDLINKS);
r = copy_directory_at(source_fd, NULL, AT_FDCWD, arg_target, COPY_REFLINK|COPY_MERGE_EMPTY|COPY_SIGINT|COPY_HARDLINKS);
if (r >= 0)
return 0;
if (r != -ENOTDIR)
+1 -1
View File
@@ -2281,7 +2281,7 @@ int home_create_luks(
setup->temporary_image_path = TAKE_PTR(t);
r = chattr_full(t, setup->image_fd, FS_NOCOW_FL|FS_NOCOMP_FL, FS_NOCOW_FL|FS_NOCOMP_FL, NULL, NULL, CHATTR_FALLBACK_BITWISE);
r = chattr_full(setup->image_fd, NULL, FS_NOCOW_FL|FS_NOCOMP_FL, FS_NOCOW_FL|FS_NOCOMP_FL, NULL, NULL, CHATTR_FALLBACK_BITWISE);
if (r < 0 && r != -ENOANO) /* ENOANO → some bits didn't work; which we skip logging about because chattr_full() already debug logs about those flags */
log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set file attributes on %s, ignoring: %m", setup->temporary_image_path);
+1 -1
View File
@@ -293,7 +293,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType
return r;
/* Let's try to make a snapshot, if we can, so that the export is atomic */
r = btrfs_subvol_snapshot_fd(sfd, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE);
r = btrfs_subvol_snapshot_at(sfd, NULL, AT_FDCWD, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE);
if (r < 0) {
log_debug_errno(r, "Couldn't create snapshot %s of %s, not exporting atomically: %m", e->temp_path, path);
e->temp_path = mfree(e->temp_path);
+6 -6
View File
@@ -194,9 +194,9 @@ static int import_fs(int argc, char *argv[], void *userdata) {
BLOCK_SIGNALS(SIGINT, SIGTERM);
if (arg_btrfs_subvol)
r = btrfs_subvol_snapshot_fd_full(
fd,
dest,
r = btrfs_subvol_snapshot_at_full(
fd, NULL,
AT_FDCWD, dest,
BTRFS_SNAPSHOT_FALLBACK_COPY|
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
BTRFS_SNAPSHOT_RECURSIVE|
@@ -206,9 +206,9 @@ static int import_fs(int argc, char *argv[], void *userdata) {
progress_bytes,
&progress);
else
r = copy_directory_fd_full(
fd,
dest,
r = copy_directory_at_full(
fd, NULL,
AT_FDCWD, dest,
COPY_REFLINK|
COPY_SAME_MOUNT|
COPY_HARDLINKS|
+3 -3
View File
@@ -237,9 +237,9 @@ static int tar_pull_make_local_copy(TarPull *i) {
return log_error_errno(r, "Failed to generate temporary filename for %s: %m", p);
if (i->flags & PULL_BTRFS_SUBVOL)
r = btrfs_subvol_snapshot(
i->final_path,
t,
r = btrfs_subvol_snapshot_at(
AT_FDCWD, i->final_path,
AT_FDCWD, t,
(i->flags & PULL_BTRFS_QUOTA ? BTRFS_SNAPSHOT_QUOTA : 0)|
BTRFS_SNAPSHOT_FALLBACK_COPY|
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
+15 -15
View File
@@ -5564,13 +5564,13 @@ static int run(int argc, char *argv[]) {
{
BLOCK_SIGNALS(SIGINT);
r = btrfs_subvol_snapshot(arg_directory, np,
(arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
BTRFS_SNAPSHOT_FALLBACK_COPY |
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
BTRFS_SNAPSHOT_RECURSIVE |
BTRFS_SNAPSHOT_QUOTA |
BTRFS_SNAPSHOT_SIGINT);
r = btrfs_subvol_snapshot_at(AT_FDCWD, arg_directory, AT_FDCWD, np,
(arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
BTRFS_SNAPSHOT_FALLBACK_COPY |
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
BTRFS_SNAPSHOT_RECURSIVE |
BTRFS_SNAPSHOT_QUOTA |
BTRFS_SNAPSHOT_SIGINT);
}
if (r == -EINTR) {
log_error_errno(r, "Interrupted while copying file system tree to %s, removed again.", np);
@@ -5605,14 +5605,14 @@ static int run(int argc, char *argv[]) {
{
BLOCK_SIGNALS(SIGINT);
r = btrfs_subvol_snapshot(arg_template, arg_directory,
(arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
BTRFS_SNAPSHOT_FALLBACK_COPY |
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
BTRFS_SNAPSHOT_RECURSIVE |
BTRFS_SNAPSHOT_QUOTA |
BTRFS_SNAPSHOT_SIGINT);
r = btrfs_subvol_snapshot_at(AT_FDCWD, arg_template, AT_FDCWD, arg_directory,
(arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
BTRFS_SNAPSHOT_FALLBACK_COPY |
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
BTRFS_SNAPSHOT_RECURSIVE |
BTRFS_SNAPSHOT_QUOTA |
BTRFS_SNAPSHOT_SIGINT);
}
if (r == -EEXIST)
log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
+47 -79
View File
@@ -17,6 +17,7 @@
#include "alloc-util.h"
#include "blockdev-util.h"
#include "btrfs-util.h"
#include "chase.h"
#include "chattr-util.h"
#include "copy.h"
#include "fd-util.h"
@@ -70,32 +71,20 @@ static int extract_subvolume_name(const char *path, char **ret) {
return 0;
}
int btrfs_is_subvol_fd(int fd) {
int btrfs_is_subvol_at(int dir_fd, const char *path) {
struct stat st;
assert(fd >= 0);
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
/* On btrfs subvolumes always have the inode 256 */
if (fstat(fd, &st) < 0)
if (fstatat(dir_fd, strempty(path), &st, (isempty(path) ? AT_EMPTY_PATH : 0)) < 0)
return -errno;
if (!btrfs_might_be_subvol(&st))
return 0;
return fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
}
int btrfs_is_subvol(const char *path) {
_cleanup_close_ int fd = -EBADF;
assert(path);
fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (fd < 0)
return -errno;
return btrfs_is_subvol_fd(fd);
return is_fs_type_at(dir_fd, path, BTRFS_SUPER_MAGIC);
}
int btrfs_subvol_make_fd(int fd, const char *subvolume) {
@@ -163,11 +152,16 @@ int btrfs_subvol_make_fallback(const char *path, mode_t mode) {
return 0; /* plain directory */
}
int btrfs_subvol_set_read_only_fd(int fd, bool b) {
int btrfs_subvol_set_read_only_at(int dir_fd, const char *path, bool b) {
_cleanup_close_ int fd = -EBADF;
uint64_t flags, nflags;
struct stat st;
assert(fd >= 0);
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
fd = xopenat(dir_fd, path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY, /* xopen_flags = */ 0, /* mode = */ 0);
if (fd < 0)
return fd;
if (fstat(fd, &st) < 0)
return -errno;
@@ -185,16 +179,6 @@ int btrfs_subvol_set_read_only_fd(int fd, bool b) {
return RET_NERRNO(ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags));
}
int btrfs_subvol_set_read_only(const char *path, bool b) {
_cleanup_close_ int fd = -EBADF;
fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (fd < 0)
return -errno;
return btrfs_subvol_set_read_only_fd(fd, b);
}
int btrfs_subvol_get_read_only_fd(int fd) {
uint64_t flags;
struct stat st;
@@ -1135,25 +1119,21 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
return 0;
}
int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
int btrfs_subvol_remove_at(int dir_fd, const char *path, BtrfsRemoveFlags flags) {
_cleanup_free_ char *subvolume = NULL;
_cleanup_close_ int fd = -EBADF;
int r;
assert(path);
r = extract_subvolume_name(path, &subvolume);
if (r < 0)
return r;
fd = open_parent(path, O_CLOEXEC, 0);
fd = chase_and_openat(dir_fd, path, CHASE_PARENT|CHASE_EXTRACT_FILENAME, O_CLOEXEC, &subvolume);
if (fd < 0)
return fd;
return subvol_remove_children(fd, subvolume, 0, flags);
}
r = validate_subvolume_name(subvolume);
if (r < 0)
return r;
int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags) {
return subvol_remove_children(fd, subvolume, 0, flags);
}
@@ -1526,22 +1506,37 @@ static int subvol_snapshot_children(
return 0;
}
int btrfs_subvol_snapshot_fd_full(
int old_fd,
const char *new_path,
int btrfs_subvol_snapshot_at_full(
int dir_fdf,
const char *from,
int dir_fdt,
const char *to,
BtrfsSnapshotFlags flags,
copy_progress_path_t progress_path,
copy_progress_bytes_t progress_bytes,
void *userdata) {
_cleanup_free_ char *subvolume = NULL;
_cleanup_close_ int new_fd = -EBADF;
_cleanup_close_ int old_fd = -EBADF, new_fd = -EBADF;
int r;
assert(old_fd >= 0);
assert(new_path);
assert(dir_fdf >= 0 || dir_fdf == AT_FDCWD);
assert(dir_fdt >= 0 || dir_fdt == AT_FDCWD);
assert(to);
r = btrfs_is_subvol_fd(old_fd);
old_fd = xopenat(dir_fdf, from, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY, /* xopen_flags = */ 0, /* mode = */ 0);
if (old_fd < 0)
return old_fd;
new_fd = chase_and_openat(dir_fdt, to, CHASE_PARENT|CHASE_EXTRACT_FILENAME, O_CLOEXEC, &subvolume);
if (new_fd < 0)
return new_fd;
r = validate_subvolume_name(subvolume);
if (r < 0)
return r;
r = btrfs_is_subvol_at(dir_fdf, from);
if (r < 0)
return r;
if (r == 0) {
@@ -1551,18 +1546,19 @@ int btrfs_subvol_snapshot_fd_full(
if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
return -EISDIR;
r = btrfs_subvol_make(new_path);
r = btrfs_subvol_make_fd(new_fd, subvolume);
if (ERRNO_IS_NOT_SUPPORTED(r) && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) {
/* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
if (mkdir(new_path, 0755) < 0)
if (mkdirat(new_fd, subvolume, 0755) < 0)
return -errno;
plain_directory = true;
} else if (r < 0)
return r;
r = copy_directory_fd_full(
old_fd, new_path,
r = copy_directory_at_full(
dir_fdf, from,
new_fd, subvolume,
COPY_MERGE_EMPTY|
COPY_REFLINK|
COPY_SAME_MOUNT|
@@ -1583,9 +1579,9 @@ int btrfs_subvol_snapshot_fd_full(
* it: the IMMUTABLE bit. Let's use this here, if this is requested. */
if (flags & BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE)
(void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL);
(void) chattr_at(new_fd, subvolume, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL);
} else {
r = btrfs_subvol_set_read_only(new_path, true);
r = btrfs_subvol_set_read_only_at(new_fd, subvolume, true);
if (r < 0)
goto fallback_fail;
}
@@ -1594,41 +1590,13 @@ int btrfs_subvol_snapshot_fd_full(
return 0;
fallback_fail:
(void) rm_rf(new_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
(void) rm_rf_at(new_fd, subvolume, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
return r;
}
r = extract_subvolume_name(new_path, &subvolume);
if (r < 0)
return r;
new_fd = open_parent(new_path, O_CLOEXEC, 0);
if (new_fd < 0)
return new_fd;
return subvol_snapshot_children(old_fd, new_fd, subvolume, 0, flags);
}
int btrfs_subvol_snapshot_full(
const char *old_path,
const char *new_path,
BtrfsSnapshotFlags flags,
copy_progress_path_t progress_path,
copy_progress_bytes_t progress_bytes,
void *userdata) {
_cleanup_close_ int old_fd = -EBADF;
assert(old_path);
assert(new_path);
old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (old_fd < 0)
return -errno;
return btrfs_subvol_snapshot_fd_full(old_fd, new_path, flags, progress_path, progress_bytes, userdata);
}
int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
struct btrfs_ioctl_search_args args = {
+20 -12
View File
@@ -43,8 +43,13 @@ typedef enum BtrfsRemoveFlags {
BTRFS_REMOVE_QUOTA = 1 << 1,
} BtrfsRemoveFlags;
int btrfs_is_subvol_fd(int fd);
int btrfs_is_subvol(const char *path);
int btrfs_is_subvol_at(int dir_fd, const char *path);
static inline int btrfs_is_subvol_fd(int fd) {
return btrfs_is_subvol_at(fd, NULL);
}
static inline int btrfs_is_subvol(const char *path) {
return btrfs_is_subvol_at(AT_FDCWD, path);
}
int btrfs_get_block_device_at(int dir_fd, const char *path, dev_t *ret);
static inline int btrfs_get_block_device(const char *path, dev_t *ret) {
@@ -69,21 +74,24 @@ int btrfs_subvol_make_fd(int fd, const char *subvolume);
int btrfs_subvol_make_fallback(const char *path, mode_t);
int btrfs_subvol_snapshot_fd_full(int old_fd, const char *new_path, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
static inline int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) {
return btrfs_subvol_snapshot_fd_full(old_fd, new_path, flags, NULL, NULL, NULL);
int btrfs_subvol_snapshot_at_full(int dir_fdf, const char *from, int dir_fdt, const char *to, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
static inline int btrfs_subvol_snapshot_at(int dir_fdf, const char *from, int dir_fdt, const char *to, BtrfsSnapshotFlags flags) {
return btrfs_subvol_snapshot_at_full(dir_fdf, from, dir_fdt, to, flags, NULL, NULL, NULL);
}
int btrfs_subvol_snapshot_full(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
static inline int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) {
return btrfs_subvol_snapshot_full(old_path, new_path, flags, NULL, NULL, NULL);
int btrfs_subvol_remove_at(int dir_fd, const char *path, BtrfsRemoveFlags flags);
static inline int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
return btrfs_subvol_remove_at(AT_FDCWD, path, flags);
}
int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags);
int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags);
int btrfs_subvol_set_read_only_at(int dir_fd, const char *path, bool b);
static inline int btrfs_subvol_set_read_only_fd(int fd, bool b) {
return btrfs_subvol_set_read_only_at(fd, NULL, b);
}
static inline int btrfs_subvol_set_read_only(const char *path, bool b) {
return btrfs_subvol_set_read_only_at(AT_FDCWD, path, b);
}
int btrfs_subvol_set_read_only_fd(int fd, bool b);
int btrfs_subvol_set_read_only(const char *path, bool b);
int btrfs_subvol_get_read_only_fd(int fd);
int btrfs_subvol_get_id(int fd, const char *subvolume, uint64_t *ret);
+14 -52
View File
@@ -1208,61 +1208,22 @@ int copy_tree_at_full(
return 0;
}
static int sync_dir_by_flags(const char *path, CopyFlags copy_flags) {
static int sync_dir_by_flags(int dir_fd, const char *path, CopyFlags copy_flags) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
if (copy_flags & COPY_SYNCFS)
return syncfs_path(AT_FDCWD, path);
return syncfs_path(dir_fd, path);
if (copy_flags & COPY_FSYNC_FULL)
return fsync_parent_at(AT_FDCWD, path);
return fsync_parent_at(dir_fd, path);
return 0;
}
int copy_directory_fd_full(
int dirfd,
const char *to,
CopyFlags copy_flags,
copy_progress_path_t progress_path,
copy_progress_bytes_t progress_bytes,
void *userdata) {
struct stat st;
int r;
assert(dirfd >= 0);
assert(to);
if (fstat(dirfd, &st) < 0)
return -errno;
r = stat_verify_directory(&st);
if (r < 0)
return r;
r = fd_copy_directory(
dirfd, NULL,
&st,
AT_FDCWD, to,
st.st_dev,
COPY_DEPTH_MAX,
UID_INVALID, GID_INVALID,
copy_flags,
NULL, NULL, NULL,
progress_path,
progress_bytes,
userdata);
if (r < 0)
return r;
r = sync_dir_by_flags(to, copy_flags);
if (r < 0)
return r;
return 0;
}
int copy_directory_full(
int copy_directory_at_full(
int dir_fdf,
const char *from,
int dir_fdt,
const char *to,
CopyFlags copy_flags,
copy_progress_path_t progress_path,
@@ -1272,10 +1233,11 @@ int copy_directory_full(
struct stat st;
int r;
assert(from);
assert(dir_fdf >= 0 || dir_fdf == AT_FDCWD);
assert(dir_fdt >= 0 || dir_fdt == AT_FDCWD);
assert(to);
if (lstat(from, &st) < 0)
if (fstatat(dir_fdf, strempty(from), &st, AT_SYMLINK_NOFOLLOW|(isempty(from) ? AT_EMPTY_PATH : 0)) < 0)
return -errno;
r = stat_verify_directory(&st);
@@ -1283,9 +1245,9 @@ int copy_directory_full(
return r;
r = fd_copy_directory(
AT_FDCWD, from,
dir_fdf, from,
&st,
AT_FDCWD, to,
dir_fdt, to,
st.st_dev,
COPY_DEPTH_MAX,
UID_INVALID, GID_INVALID,
@@ -1297,7 +1259,7 @@ int copy_directory_full(
if (r < 0)
return r;
r = sync_dir_by_flags(to, copy_flags);
r = sync_dir_by_flags(dir_fdt, to, copy_flags);
if (r < 0)
return r;
+3 -8
View File
@@ -82,14 +82,9 @@ static inline int copy_tree(const char *from, const char *to, uid_t override_uid
return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, denylist, NULL, NULL, NULL);
}
int copy_directory_fd_full(int dirfd, const char *to, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
static inline int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
return copy_directory_fd_full(dirfd, to, copy_flags, NULL, NULL, NULL);
}
int copy_directory_full(const char *from, const char *to, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
static inline int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
return copy_directory_full(from, to, copy_flags, NULL, NULL, NULL);
int copy_directory_at_full(int dir_fdf, const char *from, int dir_fdt, const char *to, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
static inline int copy_directory_at(int dir_fdf, const char *from, int dir_fdt, const char *to, CopyFlags copy_flags) {
return copy_directory_at_full(dir_fdf, from, dir_fdt, to, copy_flags, NULL, NULL, NULL);
}
int copy_bytes_full(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags, void **ret_remains, size_t *ret_remains_size, copy_progress_bytes_t progress, void *userdata);
+7 -7
View File
@@ -923,13 +923,13 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
new_path = strjoina("/var/lib/machines/", new_name);
r = btrfs_subvol_snapshot(i->path, new_path,
(read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
BTRFS_SNAPSHOT_FALLBACK_COPY |
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
BTRFS_SNAPSHOT_RECURSIVE |
BTRFS_SNAPSHOT_QUOTA);
r = btrfs_subvol_snapshot_at(AT_FDCWD, i->path, AT_FDCWD, new_path,
(read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
BTRFS_SNAPSHOT_FALLBACK_COPY |
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
BTRFS_SNAPSHOT_RECURSIVE |
BTRFS_SNAPSHOT_QUOTA);
if (r >= 0)
/* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
(void) btrfs_subvol_auto_qgroup(new_path, 0, true);
+15 -12
View File
@@ -228,7 +228,7 @@ static int rm_rf_inner_child(
if ((flags & REMOVE_SUBVOLUME) && btrfs_might_be_subvol(&st)) {
/* This could be a subvolume, try to remove it */
r = btrfs_subvol_remove_fd(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
r = btrfs_subvol_remove_at(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r < 0) {
if (!IN_SET(r, -ENOTTY, -EINVAL))
return r;
@@ -425,11 +425,14 @@ static int rm_rf_children_impl(
return ret;
}
int rm_rf(const char *path, RemoveFlags flags) {
int rm_rf_at(int dir_fd, const char *path, RemoveFlags flags) {
mode_t old_mode;
int fd, r, q = 0;
assert(path);
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
if (FLAGS_SET(flags, REMOVE_ROOT))
assert(path && !dot_or_dot_dot(path)); /* unlinkat() does not support AT_EMPTY_PATH or "." so a path must be provided here. */
/* For now, don't support dropping subvols when also only dropping directories, since we can't do
* this race-freely. */
@@ -438,14 +441,13 @@ int rm_rf(const char *path, RemoveFlags flags) {
/* We refuse to clean the root file system with this call. This is extra paranoia to never cause a
* really seriously broken system. */
if (path_equal_or_inode_same(path, "/", AT_SYMLINK_NOFOLLOW))
if (path_is_root_at(dir_fd, path) > 0)
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
"Attempted to remove entire root file system (\"%s\"), and we can't allow that.",
path);
"Attempted to remove entire root file system, and we can't allow that.");
if (FLAGS_SET(flags, REMOVE_SUBVOLUME | REMOVE_ROOT | REMOVE_PHYSICAL)) {
/* Try to remove as subvolume first */
r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
r = btrfs_subvol_remove_at(dir_fd, path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r >= 0)
return r;
@@ -458,13 +460,13 @@ int rm_rf(const char *path, RemoveFlags flags) {
/* Not btrfs or not a subvolume */
}
fd = openat_harder(AT_FDCWD, path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME, flags, &old_mode);
fd = openat_harder(dir_fd, path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME, flags, &old_mode);
if (fd >= 0) {
/* We have a dir */
r = rm_rf_children_impl(fd, flags, NULL, old_mode);
if (FLAGS_SET(flags, REMOVE_ROOT))
q = RET_NERRNO(rmdir(path));
q = RET_NERRNO(unlinkat(dir_fd, path, AT_REMOVEDIR));
} else {
r = fd;
if (FLAGS_SET(flags, REMOVE_MISSING_OK) && r == -ENOENT)
@@ -479,8 +481,9 @@ int rm_rf(const char *path, RemoveFlags flags) {
if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) {
struct statfs s;
if (statfs(path, &s) < 0)
return -errno;
r = xstatfsat(dir_fd, path, &s);
if (r < 0)
return r;
if (is_physical_fs(&s))
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
"Attempted to remove files from a disk file system under \"%s\", refusing.",
@@ -488,7 +491,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
}
r = 0;
q = RET_NERRNO(unlink(path));
q = RET_NERRNO(unlinkat(dir_fd, path, 0));
}
if (r < 0)
+5 -1
View File
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <fcntl.h>
#include <sys/stat.h>
#include "alloc-util.h"
@@ -26,7 +27,10 @@ int fstatat_harder(int dfd,
int rm_rf_children(int fd, RemoveFlags flags, const struct stat *root_dev);
int rm_rf_child(int fd, const char *name, RemoveFlags flags);
int rm_rf(const char *path, RemoveFlags flags);
int rm_rf_at(int dir_fd, const char *path, RemoveFlags flags);
static inline int rm_rf(const char *path, RemoveFlags flags) {
return rm_rf_at(AT_FDCWD, path, flags);
}
/* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */
static inline char *rm_rf_physical_and_free(char *p) {
+7 -5
View File
@@ -54,11 +54,11 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to write file: %m");
r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest2", 0);
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest2", 0);
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest3", BTRFS_SNAPSHOT_READ_ONLY);
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest3", BTRFS_SNAPSHOT_READ_ONLY);
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
@@ -74,7 +74,8 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
r = btrfs_subvol_snapshot("/etc", "/etc2", BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY);
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/etc", AT_FDCWD, "/etc2",
BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY);
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
@@ -115,7 +116,7 @@ int main(int argc, char *argv[]) {
if (mkdir("/xxxrectest/mnt", 0755) < 0)
log_error_errno(errno, "Failed to make directory: %m");
r = btrfs_subvol_snapshot("/xxxrectest", "/xxxrectest2", BTRFS_SNAPSHOT_RECURSIVE);
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxrectest", AT_FDCWD, "/xxxrectest2", BTRFS_SNAPSHOT_RECURSIVE);
if (r < 0)
log_error_errno(r, "Failed to snapshot subvolume: %m");
@@ -151,7 +152,8 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to set up quota limit: %m");
r = btrfs_subvol_snapshot("/xxxquotatest", "/xxxquotatest2", BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxquotatest", AT_FDCWD, "/xxxquotatest2",
BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to set up snapshot: %m");
+11 -1
View File
@@ -574,7 +574,7 @@ TEST(chaseat) {
assert_se(chaseat(tfd, "i/../p", CHASE_MKDIR_0755|CHASE_NONEXISTENT, NULL, NULL) == -ENOENT);
/* Test CHASE_FILENAME */
/* Test CHASE_EXTRACT_FILENAME */
assert_se(chaseat(tfd, "chase/parent", CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_NOFOLLOW|CHASE_EXTRACT_FILENAME, &result, &fd) >= 0);
assert_se(faccessat(fd, result, F_OK, AT_SYMLINK_NOFOLLOW) >= 0);
@@ -596,6 +596,10 @@ TEST(chaseat) {
assert_se(streq(result, "."));
result = mfree(result);
assert_se(chaseat(tfd, NULL, CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT|CHASE_EXTRACT_FILENAME, &result, NULL) >= 0);
assert_se(streq(result, "."));
result = mfree(result);
/* Test chase_and_openat() */
fd = chase_and_openat(tfd, "o/p/e/n/f/i/l/e", CHASE_MKDIR_0755, O_CREAT|O_EXCL|O_CLOEXEC, NULL);
@@ -608,6 +612,12 @@ TEST(chaseat) {
assert_se(fd_verify_directory(fd) >= 0);
fd = safe_close(fd);
fd = chase_and_openat(tfd, NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME, O_PATH|O_DIRECTORY|O_CLOEXEC, &result);
assert_se(fd >= 0);
assert_se(streq(result, "."));
fd = safe_close(fd);
result = mfree(result);
/* Test chase_and_openatdir() */
assert_se(chase_and_opendirat(tfd, "o/p/e/n/d/i", 0, &result, &dir) >= 0);
+1 -1
View File
@@ -1299,7 +1299,7 @@ static int prepare_ns(const char *process_name) {
/* Copy unit files to make them accessible even when unprivileged. */
assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0);
assert_se(copy_directory(unit_dir, PRIVATE_UNIT_DIR, COPY_MERGE_EMPTY) >= 0);
assert_se(copy_directory_at(AT_FDCWD, unit_dir, AT_FDCWD, PRIVATE_UNIT_DIR, COPY_MERGE_EMPTY) >= 0);
/* Prepare credstore like tmpfiles.d/credstore.conf for LoadCredential= tests. */
FOREACH_STRING(p, "/run/credstore", "/run/credstore.encrypted") {
+1 -1
View File
@@ -1540,7 +1540,7 @@ static int fd_set_attribute(
return log_error_errno(procfs_fd, "Failed to re-open '%s': %m", path);
unsigned previous, current;
r = chattr_full(NULL, procfs_fd, f, item->attribute_mask, &previous, &current, CHATTR_FALLBACK_BITWISE);
r = chattr_full(procfs_fd, NULL, f, item->attribute_mask, &previous, &current, CHATTR_FALLBACK_BITWISE);
if (r == -ENOANO)
log_warning("Cannot set file attributes for '%s', maybe due to incompatibility in specified attributes, "
"previous=0x%08x, current=0x%08x, expected=0x%08x, ignoring.",