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:
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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, ¤t, CHATTR_FALLBACK_BITWISE);
|
||||
r = chattr_full(procfs_fd, NULL, f, item->attribute_mask, &previous, ¤t, 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.",
|
||||
|
||||
Reference in New Issue
Block a user