free(f);
}
-typedef enum SubvolumeFlags {
- SUBVOLUME_RO = 1 << 0,
- _SUBVOLUME_FLAGS_MASK = SUBVOLUME_RO,
- _SUBVOLUME_FLAGS_INVALID = -EINVAL,
- _SUBVOLUME_FLAGS_ERRNO_MAX = -ERRNO_MAX, /* Ensure the whole errno range fits into this enum */
-} SubvolumeFlags;
-
-static SubvolumeFlags subvolume_flags_from_string_one(const char *s) {
+static BtrfsSubvolFlags subvolume_flags_from_string_one(const char *s) {
/* This is a bitmask (i.e. not dense), hence we don't use the "string-table.h" stuff here. */
assert(s);
if (streq(s, "ro"))
- return SUBVOLUME_RO;
+ return BTRFS_SUBVOL_RO;
- return _SUBVOLUME_FLAGS_INVALID;
+ if (streq(s, "nodatacow"))
+ return BTRFS_SUBVOL_NODATACOW;
+
+ return _BTRFS_SUBVOL_FLAGS_INVALID;
}
-static SubvolumeFlags subvolume_flags_from_string(const char *s) {
- SubvolumeFlags flags = 0;
+static BtrfsSubvolFlags subvolume_flags_from_string(const char *s) {
+ BtrfsSubvolFlags flags = 0;
int r;
assert(s);
for (;;) {
_cleanup_free_ char *f = NULL;
- SubvolumeFlags ff;
+ BtrfsSubvolFlags ff;
r = extract_first_word(&s, &f, ",", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
typedef struct Subvolume {
char *path;
- SubvolumeFlags flags;
+ BtrfsSubvolFlags flags;
} Subvolume;
static Subvolume* subvolume_free(Subvolume *s) {
}
if (f) {
- SubvolumeFlags flags = subvolume_flags_from_string(f);
+ BtrfsSubvolFlags flags = subvolume_flags_from_string(f);
if (flags == -EBADRQC) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Unknown subvolume flag in subvolume, ignoring: %s", f);
continue;
return 0;
}
-static int add_subvolume_path(const char *path, Set **subvolumes) {
+static int add_subvolume_path(const char *path, BtrfsSubvolFlags flags, Hashmap **subvolumes) {
_cleanup_free_ struct stat *st = NULL;
int r;
if (r < 0)
return log_error_errno(r, "Failed to stat source file '%s/%s': %m", strempty(arg_copy_source), path);
- r = set_ensure_consume(subvolumes, &inode_hash_ops, TAKE_PTR(st));
+ r = hashmap_ensure_put(subvolumes, &inode_hash_ops, st, INT_TO_PTR(flags));
if (r < 0)
return log_oom();
+ TAKE_PTR(st);
+
return 0;
}
-static int make_subvolumes_strv(const Partition *p, char ***ret) {
- _cleanup_strv_free_ char **subvolumes = NULL;
+static int make_subvolumes_hashmap(const Partition *p, Hashmap **ret) {
+ _cleanup_hashmap_free_ Hashmap *hashmap = NULL;
Subvolume *subvolume;
int r;
assert(p);
assert(ret);
- ORDERED_HASHMAP_FOREACH(subvolume, p->subvolumes)
- if (strv_extend(&subvolumes, subvolume->path) < 0)
+ ORDERED_HASHMAP_FOREACH(subvolume, p->subvolumes) {
+ _cleanup_free_ char *path = NULL;
+
+ path = strdup(subvolume->path);
+ if (!path)
return log_oom();
+ r = hashmap_ensure_put(&hashmap, &path_hash_ops_free, path, INT_TO_PTR(subvolume->flags));
+ if (r < 0)
+ return log_oom();
+
+ TAKE_PTR(path);
+ }
+
if (p->suppressing) {
- char **suppressing;
+ Hashmap *suppressing;
- r = make_subvolumes_strv(p->suppressing, &suppressing);
+ r = make_subvolumes_hashmap(p->suppressing, &suppressing);
if (r < 0)
return r;
- r = strv_extend_strv_consume(&subvolumes, suppressing, /* filter_duplicates= */ true);
+ r = hashmap_merge(hashmap, suppressing);
if (r < 0)
return log_oom();
}
- *ret = TAKE_PTR(subvolumes);
+ *ret = TAKE_PTR(hashmap);
return 0;
}
-static int make_subvolumes_set(
+static int make_subvolumes_by_source_inode_hashmap(
const Partition *p,
const char *source,
const char *target,
- Set **ret) {
+ Hashmap **ret) {
- _cleanup_strv_free_ char **paths = NULL;
- _cleanup_set_free_ Set *subvolumes = NULL;
+ _cleanup_hashmap_free_ Hashmap *hashmap = NULL;
+ Subvolume *subvolume;
int r;
assert(p);
assert(target);
assert(ret);
- r = make_subvolumes_strv(p, &paths);
- if (r < 0)
- return r;
-
- STRV_FOREACH(subvolume, paths) {
+ ORDERED_HASHMAP_FOREACH(subvolume, p->subvolumes) {
_cleanup_free_ char *path = NULL;
- const char *s = path_startswith(*subvolume, target);
+ const char *s = path_startswith(subvolume->path, target);
if (!s)
continue;
if (!path)
return log_oom();
- r = add_subvolume_path(path, &subvolumes);
+ r = add_subvolume_path(path, subvolume->flags, &hashmap);
+ if (r < 0)
+ return r;
+ }
+
+ if (p->suppressing) {
+ Hashmap *suppressing;
+
+ r = make_subvolumes_by_source_inode_hashmap(p->suppressing, source, target, &suppressing);
if (r < 0)
return r;
+
+ r = hashmap_merge(hashmap, suppressing);
+ if (r < 0)
+ return log_oom();
}
- *ret = TAKE_PTR(subvolumes);
+ *ret = TAKE_PTR(hashmap);
return 0;
}
}
static int do_copy_files(Context *context, Partition *p, const char *root) {
- _cleanup_strv_free_ char **subvolumes = NULL;
+ _cleanup_hashmap_free_ Hashmap *subvolumes = NULL;
int r;
assert(p);
assert(root);
- r = make_subvolumes_strv(p, &subvolumes);
+ r = make_subvolumes_hashmap(p, &subvolumes);
if (r < 0)
return r;
FOREACH_ARRAY(line, copy_files, n_copy_files) {
_cleanup_hashmap_free_ Hashmap *denylist = NULL;
- _cleanup_set_free_ Set *subvolumes_by_source_inode = NULL;
+ _cleanup_hashmap_free_ Hashmap *subvolumes_by_source_inode = NULL;
_cleanup_close_ int sfd = -EBADF, pfd = -EBADF, tfd = -EBADF;
usec_t ts = epoch_or_infinity();
if (r > 0)
continue;
- r = make_subvolumes_set(p, line->source, line->target, &subvolumes_by_source_inode);
+ r = make_subvolumes_by_source_inode_hashmap(p, line->source, line->target, &subvolumes_by_source_inode);
if (r < 0)
return r;
}
static int do_make_directories(Partition *p, const char *root) {
- _cleanup_strv_free_ char **subvolumes = NULL;
+ _cleanup_hashmap_free_ Hashmap *subvolumes = NULL;
_cleanup_free_ char **override_dirs = NULL;
int r;
assert(p);
assert(root);
- r = make_subvolumes_strv(p, &subvolumes);
+ r = make_subvolumes_hashmap(p, &subvolumes);
if (r < 0)
return r;
int r;
ORDERED_HASHMAP_FOREACH(subvolume, p->subvolumes) {
- if (!FLAGS_SET(subvolume->flags, SUBVOLUME_RO))
+ if (!FLAGS_SET(subvolume->flags, BTRFS_SUBVOL_RO))
continue;
path = path_join(root, subvolume->path);
if (streq_ptr(subvolume->path, default_subvolume) && !strextend(&s, "default"))
return log_oom();
- if (FLAGS_SET(subvolume->flags, SUBVOLUME_RO) && !strextend_with_separator(&s, "-", "ro"))
+ if (FLAGS_SET(subvolume->flags, BTRFS_SUBVOL_RO) && !strextend_with_separator(&s, "-", "ro"))
return log_oom();
if (!strextend_with_separator(&s, ":", subvolume->path))
return 0;
}
+static int append_btrfs_inode_flags(char ***l, OrderedHashmap *subvolumes) {
+ Subvolume *subvolume;
+ int r;
+
+ assert(l);
+
+ ORDERED_HASHMAP_FOREACH(subvolume, subvolumes) {
+ if (!FLAGS_SET(subvolume->flags, BTRFS_SUBVOL_NODATACOW))
+ continue;
+
+ _cleanup_free_ char *s = strjoin("nodatacow:", subvolume->path);
+ if (!s)
+ return log_oom();
+
+ r = strv_extend_many(l, "--inode-flags", s);
+ if (r < 0)
+ return log_oom();
+ }
+
+ return 0;
+}
+
static int finalize_extra_mkfs_options(const Partition *p, const char *root, char ***ret) {
_cleanup_strv_free_ char **sv = NULL;
int r;
if (r < 0)
return r;
+ r = append_btrfs_inode_flags(&sv, p->subvolumes);
+ if (r < 0)
+ return r;
+
if (p->suppressing) {
r = append_btrfs_subvols(&sv, p->suppressing->subvolumes, NULL);
if (r < 0)
return r;
+
+ r = append_btrfs_inode_flags(&sv, p->suppressing->subvolumes);
+ if (r < 0)
+ return r;
}
}
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, 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) {
+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, Hashmap *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, Hashmap *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, Set *subvolumes) {
+static inline int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, Hashmap *denylist, Hashmap *subvolumes) {
return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, denylist, subvolumes, NULL, NULL, NULL);
}