Merge pull request #28833 from DaanDeMeyer/copy-subvolume
repart: Add Subvolumes= setting
This commit is contained in:
@@ -500,6 +500,21 @@
|
||||
attributes.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Subvolumes=</varname></term>
|
||||
|
||||
<listitem><para>Takes one or more absolute paths, separated by whitespace, each declaring a directory
|
||||
that should be a subvolume within the new file system. This option may be used more than once to
|
||||
specify multiple directories. Note that this setting does not create the directories themselves, that
|
||||
can be configured with <varname>MakeDirectories=</varname> and <varname>CopyFiles=</varname>.</para>
|
||||
|
||||
<para>Note that this option only takes effect if the target filesystem supports subvolumes, such as
|
||||
<literal>btrfs</literal>.</para>
|
||||
|
||||
<para>Note that due to limitations of <literal>mkfs.btrfs</literal>, this option is only supported
|
||||
when running with <option>--offline=no</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Encrypt=</varname></term>
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <linux/btrfs.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "btrfs.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "path-util.h"
|
||||
|
||||
int btrfs_validate_subvolume_name(const char *name) {
|
||||
|
||||
if (!filename_is_valid(name))
|
||||
return -EINVAL;
|
||||
|
||||
if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int extract_subvolume_name(const char *path, char **ret) {
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(ret);
|
||||
|
||||
r = path_extract_filename(path, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = btrfs_validate_subvolume_name(fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_subvol_make(int dir_fd, const char *path) {
|
||||
struct btrfs_ioctl_vol_args args = {};
|
||||
_cleanup_free_ char *subvolume = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(!isempty(path));
|
||||
|
||||
r = extract_subvolume_name(path, &subvolume);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = path_extract_directory(path, NULL);
|
||||
if (r >= 0) {
|
||||
fd = open_parent_at(dir_fd, path, O_RDONLY|O_CLOEXEC|O_CLOEXEC, 0);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
dir_fd = fd;
|
||||
}
|
||||
|
||||
strncpy(args.name, subvolume, sizeof(args.name)-1);
|
||||
|
||||
return RET_NERRNO(ioctl(dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args));
|
||||
}
|
||||
|
||||
int btrfs_subvol_make_fallback(int dir_fd, const char *path, mode_t mode) {
|
||||
mode_t old, combined;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
/* Let's work like mkdir(), i.e. take the specified mode, and mask it with the current umask. */
|
||||
old = umask(~mode);
|
||||
combined = old | ~mode;
|
||||
if (combined != ~mode)
|
||||
umask(combined);
|
||||
r = btrfs_subvol_make(dir_fd, path);
|
||||
umask(old);
|
||||
|
||||
if (r >= 0)
|
||||
return 1; /* subvol worked */
|
||||
if (r != -ENOTTY)
|
||||
return r;
|
||||
|
||||
if (mkdirat(dir_fd, path, mode) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0; /* plain directory */
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
int btrfs_validate_subvolume_name(const char *name);
|
||||
|
||||
int btrfs_subvol_make(int dir_fd, const char *path);
|
||||
|
||||
int btrfs_subvol_make_fallback(int dir_fd, const char *path, mode_t mode);
|
||||
+5
-1
@@ -9,6 +9,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "btrfs.h"
|
||||
#include "dirent-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@@ -1110,7 +1111,10 @@ int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags
|
||||
}
|
||||
|
||||
if (FLAGS_SET(open_flags, O_DIRECTORY|O_CREAT)) {
|
||||
r = RET_NERRNO(mkdirat(dir_fd, path, mode));
|
||||
if (FLAGS_SET(xopen_flags, XO_SUBVOLUME))
|
||||
r = btrfs_subvol_make_fallback(dir_fd, path, mode);
|
||||
else
|
||||
r = RET_NERRNO(mkdirat(dir_fd, path, mode));
|
||||
if (r == -EEXIST) {
|
||||
if (FLAGS_SET(open_flags, O_EXCL))
|
||||
return -EEXIST;
|
||||
|
||||
+2
-1
@@ -133,7 +133,8 @@ 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);
|
||||
|
||||
typedef enum XOpenFlags {
|
||||
XO_LABEL = 1 << 0,
|
||||
XO_LABEL = 1 << 0,
|
||||
XO_SUBVOLUME = 1 << 1,
|
||||
} XOpenFlags;
|
||||
|
||||
int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
|
||||
|
||||
@@ -8,6 +8,7 @@ basic_sources = files(
|
||||
'argv-util.c',
|
||||
'arphrd-util.c',
|
||||
'audit-util.c',
|
||||
'btrfs.c',
|
||||
'build.c',
|
||||
'bus-label.c',
|
||||
'cap-list.c',
|
||||
|
||||
+10
-5
@@ -5,6 +5,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "btrfs.h"
|
||||
#include "chase.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
@@ -209,7 +210,7 @@ int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, g
|
||||
return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper);
|
||||
}
|
||||
|
||||
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m) {
|
||||
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, char **subvolumes) {
|
||||
_cleanup_free_ char *pp = NULL, *bn = NULL;
|
||||
_cleanup_close_ int dfd = -EBADF;
|
||||
int r;
|
||||
@@ -227,7 +228,7 @@ int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m
|
||||
return r;
|
||||
else {
|
||||
/* Extracting the parent dir worked, hence we aren't top-level? Recurse up first. */
|
||||
r = mkdir_p_root(root, pp, uid, gid, m);
|
||||
r = mkdir_p_root(root, pp, uid, gid, m, subvolumes);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -242,11 +243,15 @@ int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mkdirat(dfd, bn, m) < 0) {
|
||||
if (errno == EEXIST)
|
||||
if (path_strv_contains(subvolumes, p))
|
||||
r = btrfs_subvol_make_fallback(dfd, bn, m);
|
||||
else
|
||||
r = RET_NERRNO(mkdirat(dfd, bn, m));
|
||||
if (r < 0) {
|
||||
if (r == -EEXIST)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uid_is_valid(uid) || gid_is_valid(gid)) {
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ static inline int mkdir_parents(const char *path, mode_t mode) {
|
||||
int mkdir_parents_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
|
||||
int mkdir_p(const char *path, mode_t mode);
|
||||
int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
|
||||
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m);
|
||||
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, char **subvolumes);
|
||||
|
||||
/* The following are used to implement the mkdir_xyz_label() calls, don't use otherwise. */
|
||||
typedef int (*mkdirat_func_t)(int dir_fd, const char *pathname, mode_t mode);
|
||||
|
||||
@@ -1116,7 +1116,9 @@ int path_extract_directory(const char *path, char **ret) {
|
||||
if (!path_is_valid(a))
|
||||
return -EINVAL;
|
||||
|
||||
*ret = TAKE_PTR(a);
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1414,9 +1414,9 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) {
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to open destination '%s': %m", arg_target);
|
||||
|
||||
r = copy_tree_at(source_fd, ".", dfd, bn, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL);
|
||||
r = copy_tree_at(source_fd, ".", dfd, bn, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL, NULL);
|
||||
} else
|
||||
r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL);
|
||||
r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to copy '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image);
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ int home_create_directory_or_subvolume(UserRecord *h, HomeSetup *setup, UserReco
|
||||
|
||||
case USER_SUBVOLUME:
|
||||
WITH_UMASK(0077)
|
||||
r = btrfs_subvol_make(d);
|
||||
r = btrfs_subvol_make(AT_FDCWD, d);
|
||||
|
||||
if (r >= 0) {
|
||||
log_info("Subvolume created.");
|
||||
|
||||
@@ -2383,7 +2383,7 @@ int home_create_luks(
|
||||
return log_oom();
|
||||
|
||||
/* Prefer using a btrfs subvolume if we can, fall back to directory otherwise */
|
||||
r = btrfs_subvol_make_fallback(subdir, 0700);
|
||||
r = btrfs_subvol_make_fallback(AT_FDCWD, subdir, 0700);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create user directory in mounted image file: %m");
|
||||
|
||||
|
||||
+1
-1
@@ -1036,7 +1036,7 @@ static int copy_skel(int root_fd, const char *skel) {
|
||||
|
||||
assert(root_fd >= 0);
|
||||
|
||||
r = copy_tree_at(AT_FDCWD, skel, root_fd, ".", UID_INVALID, GID_INVALID, COPY_MERGE|COPY_REPLACE, NULL);
|
||||
r = copy_tree_at(AT_FDCWD, skel, root_fd, ".", UID_INVALID, GID_INVALID, COPY_MERGE|COPY_REPLACE, NULL, NULL);
|
||||
if (r == -ENOENT) {
|
||||
log_info("Skeleton directory %s missing, ignoring.", skel);
|
||||
return 0;
|
||||
|
||||
@@ -225,7 +225,7 @@ static int tar_import_fork_tar(TarImport *i) {
|
||||
(void) rm_rf(d, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
|
||||
|
||||
if (i->flags & IMPORT_BTRFS_SUBVOL)
|
||||
r = btrfs_subvol_make_fallback(d, 0755);
|
||||
r = btrfs_subvol_make_fallback(AT_FDCWD, d, 0755);
|
||||
else
|
||||
r = RET_NERRNO(mkdir(d, 0755));
|
||||
if (r == -EEXIST && (i->flags & IMPORT_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
|
||||
|
||||
@@ -245,7 +245,7 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
||||
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
|
||||
BTRFS_SNAPSHOT_RECURSIVE);
|
||||
else
|
||||
r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS, NULL);
|
||||
r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create local image: %m");
|
||||
|
||||
@@ -516,7 +516,7 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
|
||||
(void) rm_rf(where, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
|
||||
|
||||
if (i->flags & PULL_BTRFS_SUBVOL)
|
||||
r = btrfs_subvol_make_fallback(where, 0755);
|
||||
r = btrfs_subvol_make_fallback(AT_FDCWD, where, 0755);
|
||||
else
|
||||
r = RET_NERRNO(mkdir(where, 0755));
|
||||
if (r == -EEXIST && (i->flags & PULL_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
|
||||
|
||||
@@ -1019,9 +1019,9 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
|
||||
* 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
|
||||
* the UID/GIDs as they are. */
|
||||
if (copy_from)
|
||||
r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags, NULL);
|
||||
r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags, NULL, NULL);
|
||||
else
|
||||
r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags, NULL);
|
||||
r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags, NULL, NULL);
|
||||
|
||||
hostfd = safe_close(hostfd);
|
||||
containerfd = safe_close(containerfd);
|
||||
|
||||
+81
-9
@@ -243,6 +243,7 @@ typedef struct Partition {
|
||||
char **exclude_files_source;
|
||||
char **exclude_files_target;
|
||||
char **make_directories;
|
||||
char **subvolumes;
|
||||
EncryptMode encrypt;
|
||||
VerityMode verity;
|
||||
char *verity_match_key;
|
||||
@@ -389,6 +390,7 @@ static Partition* partition_free(Partition *p) {
|
||||
strv_free(p->exclude_files_source);
|
||||
strv_free(p->exclude_files_target);
|
||||
strv_free(p->make_directories);
|
||||
strv_free(p->subvolumes);
|
||||
free(p->verity_match_key);
|
||||
|
||||
free(p->roothash);
|
||||
@@ -417,6 +419,7 @@ static void partition_foreignize(Partition *p) {
|
||||
p->exclude_files_source = strv_free(p->exclude_files_source);
|
||||
p->exclude_files_target = strv_free(p->exclude_files_target);
|
||||
p->make_directories = strv_free(p->make_directories);
|
||||
p->subvolumes = strv_free(p->subvolumes);
|
||||
p->verity_match_key = mfree(p->verity_match_key);
|
||||
|
||||
p->priority = 0;
|
||||
@@ -1503,7 +1506,7 @@ static int config_parse_make_dirs(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Partition *partition = ASSERT_PTR(data);
|
||||
char ***sv = ASSERT_PTR(data);
|
||||
const char *p = ASSERT_PTR(rvalue);
|
||||
int r;
|
||||
|
||||
@@ -1531,7 +1534,7 @@ static int config_parse_make_dirs(
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
r = strv_consume(&partition->make_directories, TAKE_PTR(d));
|
||||
r = strv_consume(sv, TAKE_PTR(d));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
@@ -1626,7 +1629,7 @@ static int partition_read_definition(Partition *p, const char *path, const char
|
||||
{ "Partition", "CopyFiles", config_parse_copy_files, 0, &p->copy_files },
|
||||
{ "Partition", "ExcludeFiles", config_parse_exclude_files, 0, &p->exclude_files_source },
|
||||
{ "Partition", "ExcludeFilesTarget", config_parse_exclude_files, 0, &p->exclude_files_target },
|
||||
{ "Partition", "MakeDirectories", config_parse_make_dirs, 0, p },
|
||||
{ "Partition", "MakeDirectories", config_parse_make_dirs, 0, &p->make_directories },
|
||||
{ "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt },
|
||||
{ "Partition", "Verity", config_parse_verity, 0, &p->verity },
|
||||
{ "Partition", "VerityMatchKey", config_parse_string, 0, &p->verity_match_key },
|
||||
@@ -1636,6 +1639,7 @@ static int partition_read_definition(Partition *p, const char *path, const char
|
||||
{ "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
|
||||
{ "Partition", "SplitName", config_parse_string, 0, &p->split_name_format },
|
||||
{ "Partition", "Minimize", config_parse_minimize, 0, &p->minimize },
|
||||
{ "Partition", "Subvolumes", config_parse_make_dirs, 0, &p->subvolumes },
|
||||
{}
|
||||
};
|
||||
int r;
|
||||
@@ -1749,6 +1753,10 @@ static int partition_read_definition(Partition *p, const char *path, const char
|
||||
"SizeMinBytes=/SizeMaxBytes= cannot be used with Verity=%s",
|
||||
verity_mode_to_string(p->verity));
|
||||
|
||||
if (!strv_isempty(p->subvolumes) && arg_offline != 0)
|
||||
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"Subvolumes= can only be used with --offline=no");
|
||||
|
||||
/* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */
|
||||
if ((IN_SET(p->type.designator,
|
||||
PARTITION_ROOT_VERITY,
|
||||
@@ -4304,6 +4312,66 @@ static int make_copy_files_denylist(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_subvolume_path(const char *path, Set **subvolumes) {
|
||||
_cleanup_free_ struct stat *st = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(subvolumes);
|
||||
|
||||
st = new(struct stat, 1);
|
||||
if (!st)
|
||||
return log_oom();
|
||||
|
||||
r = chase_and_stat(path, arg_root, CHASE_PREFIX_ROOT, NULL, st);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to stat source file '%s/%s': %m", strempty(arg_root), path);
|
||||
|
||||
r = set_ensure_put(subvolumes, &inode_hash_ops, st);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (r > 0)
|
||||
TAKE_PTR(st);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int make_subvolumes_set(
|
||||
Context *context,
|
||||
const Partition *p,
|
||||
const char *source,
|
||||
const char *target,
|
||||
Set **ret) {
|
||||
_cleanup_set_free_ Set *subvolumes = NULL;
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
assert(p);
|
||||
assert(target);
|
||||
assert(ret);
|
||||
|
||||
STRV_FOREACH(subvolume, p->subvolumes) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
|
||||
const char *s = path_startswith(*subvolume, target);
|
||||
if (!s)
|
||||
continue;
|
||||
|
||||
path = path_join(source, s);
|
||||
if (!path)
|
||||
return log_oom();
|
||||
|
||||
r = add_subvolume_path(path, &subvolumes);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(subvolumes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_copy_files(Context *context, Partition *p, const char *root) {
|
||||
int r;
|
||||
|
||||
@@ -4337,12 +4405,17 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
|
||||
|
||||
STRV_FOREACH_PAIR(source, target, p->copy_files) {
|
||||
_cleanup_hashmap_free_ Hashmap *denylist = NULL;
|
||||
_cleanup_set_free_ Set *subvolumes_by_source_inode = NULL;
|
||||
_cleanup_close_ int sfd = -EBADF, pfd = -EBADF, tfd = -EBADF;
|
||||
|
||||
r = make_copy_files_denylist(context, p, *source, *target, &denylist);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = make_subvolumes_set(context, p, *source, *target, &subvolumes_by_source_inode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
sfd = chase_and_open(*source, arg_root, CHASE_PREFIX_ROOT, O_CLOEXEC|O_NOCTTY, NULL);
|
||||
if (sfd < 0)
|
||||
return log_error_errno(sfd, "Failed to open source file '%s%s': %m", strempty(arg_root), *source);
|
||||
@@ -4368,7 +4441,7 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);
|
||||
|
||||
r = mkdir_p_root(root, dn, UID_INVALID, GID_INVALID, 0755);
|
||||
r = mkdir_p_root(root, dn, UID_INVALID, GID_INVALID, 0755, p->subvolumes);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create parent directory '%s': %m", dn);
|
||||
|
||||
@@ -4381,14 +4454,14 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
|
||||
pfd, fn,
|
||||
UID_INVALID, GID_INVALID,
|
||||
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE,
|
||||
denylist);
|
||||
denylist, subvolumes_by_source_inode);
|
||||
} else
|
||||
r = copy_tree_at(
|
||||
sfd, ".",
|
||||
tfd, ".",
|
||||
UID_INVALID, GID_INVALID,
|
||||
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE,
|
||||
denylist);
|
||||
denylist, subvolumes_by_source_inode);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to copy '%s%s' to '%s%s': %m",
|
||||
strempty(arg_root), *source, strempty(root), *target);
|
||||
@@ -4408,7 +4481,7 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);
|
||||
|
||||
r = mkdir_p_root(root, dn, UID_INVALID, GID_INVALID, 0755);
|
||||
r = mkdir_p_root(root, dn, UID_INVALID, GID_INVALID, 0755, p->subvolumes);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create parent directory: %m");
|
||||
|
||||
@@ -4440,8 +4513,7 @@ static int do_make_directories(Partition *p, const char *root) {
|
||||
assert(root);
|
||||
|
||||
STRV_FOREACH(d, p->make_directories) {
|
||||
|
||||
r = mkdir_p_root(root, *d, UID_INVALID, GID_INVALID, 0755);
|
||||
r = mkdir_p_root(root, *d, UID_INVALID, GID_INVALID, 0755, p->subvolumes);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create directory '%s' in file system: %m", *d);
|
||||
}
|
||||
|
||||
+3
-98
@@ -42,36 +42,6 @@
|
||||
* device nodes (that reference drivers) rather than fds to normal
|
||||
* files or directories. */
|
||||
|
||||
static int validate_subvolume_name(const char *name) {
|
||||
|
||||
if (!filename_is_valid(name))
|
||||
return -EINVAL;
|
||||
|
||||
if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int extract_subvolume_name(const char *path, char **ret) {
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(ret);
|
||||
|
||||
r = path_extract_filename(path, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = validate_subvolume_name(fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_is_subvol_at(int dir_fd, const char *path) {
|
||||
struct stat st;
|
||||
|
||||
@@ -88,71 +58,6 @@ int btrfs_is_subvol_at(int dir_fd, const char *path) {
|
||||
return is_fs_type_at(dir_fd, path, BTRFS_SUPER_MAGIC);
|
||||
}
|
||||
|
||||
int btrfs_subvol_make_fd(int fd, const char *subvolume) {
|
||||
struct btrfs_ioctl_vol_args args = {};
|
||||
_cleanup_close_ int real_fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(subvolume);
|
||||
|
||||
r = validate_subvolume_name(subvolume);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* If an O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal
|
||||
* with O_PATH. */
|
||||
fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY, O_PATH|O_DIRECTORY, &real_fd);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
strncpy(args.name, subvolume, sizeof(args.name)-1);
|
||||
|
||||
return RET_NERRNO(ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args));
|
||||
}
|
||||
|
||||
int btrfs_subvol_make(const char *path) {
|
||||
_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);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
return btrfs_subvol_make_fd(fd, subvolume);
|
||||
}
|
||||
|
||||
int btrfs_subvol_make_fallback(const char *path, mode_t mode) {
|
||||
mode_t old, combined;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
/* Let's work like mkdir(), i.e. take the specified mode, and mask it with the current umask. */
|
||||
old = umask(~mode);
|
||||
combined = old | ~mode;
|
||||
if (combined != ~mode)
|
||||
umask(combined);
|
||||
r = btrfs_subvol_make(path);
|
||||
umask(old);
|
||||
|
||||
if (r >= 0)
|
||||
return 1; /* subvol worked */
|
||||
if (r != -ENOTTY)
|
||||
return r;
|
||||
|
||||
if (mkdir(path, mode) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0; /* plain directory */
|
||||
}
|
||||
|
||||
int btrfs_subvol_set_read_only_at(int dir_fd, const char *path, bool b) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
uint64_t flags, nflags;
|
||||
@@ -1131,7 +1036,7 @@ int btrfs_subvol_remove_at(int dir_fd, const char *path, BtrfsRemoveFlags flags)
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
r = validate_subvolume_name(subvolume);
|
||||
r = btrfs_validate_subvolume_name(subvolume);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1551,7 +1456,7 @@ int btrfs_subvol_snapshot_at_full(
|
||||
if (new_fd < 0)
|
||||
return new_fd;
|
||||
|
||||
r = validate_subvolume_name(subvolume);
|
||||
r = btrfs_validate_subvolume_name(subvolume);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1565,7 +1470,7 @@ int btrfs_subvol_snapshot_at_full(
|
||||
if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
|
||||
return -EISDIR;
|
||||
|
||||
r = btrfs_subvol_make_fd(new_fd, subvolume);
|
||||
r = btrfs_subvol_make(new_fd, subvolume);
|
||||
if (r < 0) {
|
||||
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. */
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "btrfs.h"
|
||||
#include "copy.h"
|
||||
#include "time-util.h"
|
||||
|
||||
@@ -70,11 +71,6 @@ int btrfs_quota_scan_start(int fd);
|
||||
int btrfs_quota_scan_wait(int fd);
|
||||
int btrfs_quota_scan_ongoing(int fd);
|
||||
|
||||
int btrfs_subvol_make(const char *path);
|
||||
int btrfs_subvol_make_fd(int fd, const char *subvolume);
|
||||
|
||||
int btrfs_subvol_make_fallback(const char *path, mode_t);
|
||||
|
||||
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);
|
||||
|
||||
+10
-6
@@ -730,6 +730,7 @@ static int fd_copy_tree_generic(
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags,
|
||||
Hashmap *denylist,
|
||||
Set *subvolumes,
|
||||
HardlinkContext *hardlink_context,
|
||||
const char *display_path,
|
||||
copy_progress_path_t progress_path,
|
||||
@@ -933,6 +934,7 @@ static int fd_copy_directory(
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags,
|
||||
Hashmap *denylist,
|
||||
Set *subvolumes,
|
||||
HardlinkContext *hardlink_context,
|
||||
const char *display_path,
|
||||
copy_progress_path_t progress_path,
|
||||
@@ -986,7 +988,7 @@ static int fd_copy_directory(
|
||||
|
||||
fdt = xopenat_lock(dt, to,
|
||||
O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|(exists ? 0 : O_CREAT|O_EXCL),
|
||||
(copy_flags & COPY_MAC_CREATE ? XO_LABEL : 0),
|
||||
(copy_flags & COPY_MAC_CREATE ? XO_LABEL : 0)|(set_contains(subvolumes, st) ? XO_SUBVOLUME : 0),
|
||||
st->st_mode & 07777,
|
||||
copy_flags & COPY_LOCK_BSD ? LOCK_BSD : LOCK_NONE,
|
||||
LOCK_EX);
|
||||
@@ -1068,7 +1070,7 @@ static int fd_copy_directory(
|
||||
|
||||
q = fd_copy_tree_generic(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device,
|
||||
depth_left-1, override_uid, override_gid, copy_flags & ~COPY_LOCK_BSD,
|
||||
denylist, hardlink_context, child_display_path, progress_path,
|
||||
denylist, subvolumes, hardlink_context, child_display_path, progress_path,
|
||||
progress_bytes, userdata);
|
||||
|
||||
if (q == -EINTR) /* Propagate SIGINT/SIGTERM up instantly */
|
||||
@@ -1145,6 +1147,7 @@ static int fd_copy_tree_generic(
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags,
|
||||
Hashmap *denylist,
|
||||
Set *subvolumes,
|
||||
HardlinkContext *hardlink_context,
|
||||
const char *display_path,
|
||||
copy_progress_path_t progress_path,
|
||||
@@ -1157,8 +1160,8 @@ static int fd_copy_tree_generic(
|
||||
|
||||
if (S_ISDIR(st->st_mode))
|
||||
return fd_copy_directory(df, from, st, dt, to, original_device, depth_left-1, override_uid,
|
||||
override_gid, copy_flags, denylist, hardlink_context, display_path,
|
||||
progress_path, progress_bytes, userdata);
|
||||
override_gid, copy_flags, denylist, subvolumes, hardlink_context,
|
||||
display_path, progress_path, progress_bytes, userdata);
|
||||
|
||||
DenyType t = PTR_TO_INT(hashmap_get(denylist, st));
|
||||
if (t == DENY_INODE) {
|
||||
@@ -1189,6 +1192,7 @@ int copy_tree_at_full(
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags,
|
||||
Hashmap *denylist,
|
||||
Set *subvolumes,
|
||||
copy_progress_path_t progress_path,
|
||||
copy_progress_bytes_t progress_bytes,
|
||||
void *userdata) {
|
||||
@@ -1204,7 +1208,7 @@ int copy_tree_at_full(
|
||||
return -errno;
|
||||
|
||||
r = fd_copy_tree_generic(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid,
|
||||
override_gid, copy_flags, denylist, NULL, NULL, progress_path,
|
||||
override_gid, copy_flags, denylist, subvolumes, NULL, NULL, progress_path,
|
||||
progress_bytes, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1273,7 +1277,7 @@ int copy_directory_at_full(
|
||||
COPY_DEPTH_MAX,
|
||||
UID_INVALID, GID_INVALID,
|
||||
copy_flags,
|
||||
NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
progress_path,
|
||||
progress_bytes,
|
||||
userdata);
|
||||
|
||||
+5
-5
@@ -76,12 +76,12 @@ static inline int copy_file_atomic(const char *from, const char *to, mode_t mode
|
||||
return copy_file_atomic_full(from, to, mode, 0, 0, copy_flags, NULL, NULL);
|
||||
}
|
||||
|
||||
int copy_tree_at_full(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, Hashmap *denylist, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
|
||||
static inline int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, Hashmap *denylist) {
|
||||
return copy_tree_at_full(fdf, from, fdt, to, override_uid, override_gid, copy_flags, denylist, NULL, NULL, NULL);
|
||||
int copy_tree_at_full(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, Hashmap *denylist, Set *subvolumes, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
|
||||
static inline int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, Hashmap *denylist, Set *subvolumes) {
|
||||
return copy_tree_at_full(fdf, from, fdt, to, override_uid, override_gid, copy_flags, denylist, subvolumes, NULL, NULL, NULL);
|
||||
}
|
||||
static inline int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, Hashmap *denylist) {
|
||||
return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, denylist, NULL, NULL, NULL);
|
||||
static inline int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, Hashmap *denylist, Set *subvolumes) {
|
||||
return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, denylist, subvolumes, 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);
|
||||
|
||||
@@ -1936,7 +1936,7 @@ static int mount_partition(
|
||||
|
||||
if (directory) {
|
||||
/* Automatically create missing mount points inside the image, if necessary. */
|
||||
r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755);
|
||||
r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755, NULL);
|
||||
if (r < 0 && r != -EROFS)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ int btrfs_subvol_make_label(const char *path) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = btrfs_subvol_make(path);
|
||||
r = btrfs_subvol_make(AT_FDCWD, path);
|
||||
mac_selinux_create_file_clear();
|
||||
|
||||
if (r < 0)
|
||||
|
||||
@@ -48,7 +48,7 @@ int main(int argc, char *argv[]) {
|
||||
safe_close(fd);
|
||||
}
|
||||
|
||||
r = btrfs_subvol_make("/xxxtest");
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxtest");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
@@ -97,33 +97,33 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make("/xxxrectest");
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make("/xxxrectest/xxxrectest2");
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest2");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make("/xxxrectest/xxxrectest3");
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest3");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make("/xxxrectest/xxxrectest3/sub");
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest3/sub");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
if (mkdir("/xxxrectest/dir", 0755) < 0)
|
||||
log_error_errno(errno, "Failed to make directory: %m");
|
||||
|
||||
r = btrfs_subvol_make("/xxxrectest/dir/xxxrectest4");
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/dir/xxxrectest4");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
if (mkdir("/xxxrectest/dir/xxxrectest4/dir", 0755) < 0)
|
||||
log_error_errno(errno, "Failed to make directory: %m");
|
||||
|
||||
r = btrfs_subvol_make("/xxxrectest/dir/xxxrectest4/dir/xxxrectest5");
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/dir/xxxrectest4/dir/xxxrectest5");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
@@ -142,7 +142,7 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to recursively remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make("/xxxquotatest");
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxquotatest");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
@@ -150,7 +150,7 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to set up auto qgroup: %m");
|
||||
|
||||
r = btrfs_subvol_make("/xxxquotatest/beneath");
|
||||
r = btrfs_subvol_make(AT_FDCWD, "/xxxquotatest/beneath");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
|
||||
@@ -67,11 +67,11 @@ TEST(copy_tree_replace_file) {
|
||||
|
||||
/* The file exists- now overwrite original contents, and test the COPY_REPLACE flag. */
|
||||
|
||||
assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK, NULL) == -EEXIST);
|
||||
assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK, NULL, NULL) == -EEXIST);
|
||||
|
||||
assert_se(read_file_at_and_streq(AT_FDCWD, dst, "foo foo foo\n"));
|
||||
|
||||
assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE, NULL) == 0);
|
||||
assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE, NULL, NULL) == 0);
|
||||
|
||||
assert_se(read_file_at_and_streq(AT_FDCWD, dst, "bar bar\n"));
|
||||
}
|
||||
@@ -92,14 +92,14 @@ TEST(copy_tree_replace_dirs) {
|
||||
assert_se(write_string_file_at(dst, "bar", "dest file 2", WRITE_STRING_FILE_CREATE) == 0);
|
||||
|
||||
/* Copying without COPY_REPLACE should fail because the destination file already exists. */
|
||||
assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK, NULL) == -EEXIST);
|
||||
assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK, NULL, NULL) == -EEXIST);
|
||||
|
||||
assert_se(read_file_at_and_streq(src, "foo", "src file 1\n"));
|
||||
assert_se(read_file_at_and_streq(src, "bar", "src file 2\n"));
|
||||
assert_se(read_file_at_and_streq(dst, "foo", "dest file 1\n"));
|
||||
assert_se(read_file_at_and_streq(dst, "bar", "dest file 2\n"));
|
||||
|
||||
assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE, NULL) == 0);
|
||||
assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE, NULL, NULL) == 0);
|
||||
|
||||
assert_se(read_file_at_and_streq(src, "foo", "src file 1\n"));
|
||||
assert_se(read_file_at_and_streq(src, "bar", "src file 2\n"));
|
||||
@@ -191,7 +191,7 @@ TEST(copy_tree) {
|
||||
assert_se(hashmap_ensure_put(&denylist, &inode_hash_ops, cp, INT_TO_PTR(DENY_INODE)) >= 0);
|
||||
TAKE_PTR(cp);
|
||||
|
||||
assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS, denylist) == 0);
|
||||
assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS, denylist, NULL) == 0);
|
||||
|
||||
STRV_FOREACH(p, files) {
|
||||
_cleanup_free_ char *buf = NULL, *f = NULL, *c = NULL;
|
||||
@@ -243,8 +243,8 @@ TEST(copy_tree) {
|
||||
assert_se(stat(unixsockp, &st) >= 0);
|
||||
assert_se(S_ISSOCK(st.st_mode));
|
||||
|
||||
assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK, denylist) < 0);
|
||||
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK, denylist) < 0);
|
||||
assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK, denylist, NULL) < 0);
|
||||
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK, denylist, NULL) < 0);
|
||||
|
||||
ignorep = strjoina(copy_dir, "ignore/file");
|
||||
assert_se(RET_NERRNO(access(ignorep, F_OK)) == -ENOENT);
|
||||
|
||||
@@ -96,7 +96,7 @@ TEST(mkdir_p_root) {
|
||||
assert_se(mkdtemp_malloc("/tmp/test-mkdir-XXXXXX", &tmp) >= 0);
|
||||
|
||||
assert_se(p = path_join(tmp, "run/aaa/bbb"));
|
||||
assert_se(mkdir_p_root(tmp, "/run/aaa/bbb", UID_INVALID, GID_INVALID, 0755) >= 0);
|
||||
assert_se(mkdir_p_root(tmp, "/run/aaa/bbb", UID_INVALID, GID_INVALID, 0755, NULL) >= 0);
|
||||
assert_se(is_dir(p, false) > 0);
|
||||
assert_se(is_dir(p, true) > 0);
|
||||
|
||||
@@ -109,18 +109,18 @@ TEST(mkdir_p_root) {
|
||||
|
||||
p = mfree(p);
|
||||
assert_se(p = path_join(tmp, "var/run/hoge/foo/baz"));
|
||||
assert_se(mkdir_p_root(tmp, "/var/run/hoge/foo/baz", UID_INVALID, GID_INVALID, 0755) >= 0);
|
||||
assert_se(mkdir_p_root(tmp, "/var/run/hoge/foo/baz", UID_INVALID, GID_INVALID, 0755, NULL) >= 0);
|
||||
assert_se(is_dir(p, false) > 0);
|
||||
assert_se(is_dir(p, true) > 0);
|
||||
|
||||
p = mfree(p);
|
||||
assert_se(p = path_join(tmp, "not-exists"));
|
||||
assert_se(mkdir_p_root(p, "/aaa", UID_INVALID, GID_INVALID, 0755) == -ENOENT);
|
||||
assert_se(mkdir_p_root(p, "/aaa", UID_INVALID, GID_INVALID, 0755, NULL) == -ENOENT);
|
||||
|
||||
p = mfree(p);
|
||||
assert_se(p = path_join(tmp, "regular-file"));
|
||||
assert_se(touch(p) >= 0);
|
||||
assert_se(mkdir_p_root(p, "/aaa", UID_INVALID, GID_INVALID, 0755) == -ENOTDIR);
|
||||
assert_se(mkdir_p_root(p, "/aaa", UID_INVALID, GID_INVALID, 0755, NULL) == -ENOTDIR);
|
||||
|
||||
/* FIXME: The tests below do not work.
|
||||
p = mfree(p);
|
||||
|
||||
@@ -1866,7 +1866,7 @@ static int copy_files(Context *c, Item *i) {
|
||||
i->uid_set ? i->uid : UID_INVALID,
|
||||
i->gid_set ? i->gid : GID_INVALID,
|
||||
COPY_REFLINK | ((i->append_or_force) ? COPY_MERGE : COPY_MERGE_EMPTY) | COPY_MAC_CREATE | COPY_HARDLINKS,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
|
||||
fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
|
||||
if (fd < 0) {
|
||||
@@ -1932,7 +1932,7 @@ static int create_directory_or_subvolume(
|
||||
subvol = false;
|
||||
else {
|
||||
WITH_UMASK((~mode) & 0777)
|
||||
r = btrfs_subvol_make_fd(pfd, bn);
|
||||
r = btrfs_subvol_make(pfd, bn);
|
||||
}
|
||||
} else
|
||||
r = 0;
|
||||
|
||||
Reference in New Issue
Block a user