mirror of
https://github.com/systemd/systemd.git
synced 2025-01-12 13:18:14 +03:00
copy: Support passing a deny list of files/directories to not copy
This commit is contained in:
parent
ddfdf86f81
commit
a424958aa6
@ -1122,9 +1122,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);
|
||||
r = copy_tree_at(source_fd, ".", dfd, bn, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL);
|
||||
} else
|
||||
r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
|
||||
r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, 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);
|
||||
|
||||
|
@ -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);
|
||||
r = copy_tree_at(AT_FDCWD, skel, root_fd, ".", UID_INVALID, GID_INVALID, COPY_MERGE|COPY_REPLACE, NULL);
|
||||
if (r == -ENOENT) {
|
||||
log_info("Skeleton directory %s missing, ignoring.", skel);
|
||||
return 0;
|
||||
|
@ -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);
|
||||
r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create local image: %m");
|
||||
|
||||
|
@ -1014,9 +1014,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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
hostfd = safe_close(hostfd);
|
||||
containerfd = safe_close(containerfd);
|
||||
|
@ -3273,13 +3273,15 @@ static int do_copy_files(Partition *p, const char *root) {
|
||||
sfd, ".",
|
||||
pfd, fn,
|
||||
UID_INVALID, GID_INVALID,
|
||||
COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS);
|
||||
COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS,
|
||||
NULL);
|
||||
} else
|
||||
r = copy_tree_at(
|
||||
sfd, ".",
|
||||
tfd, ".",
|
||||
UID_INVALID, GID_INVALID,
|
||||
COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS);
|
||||
COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS,
|
||||
NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target);
|
||||
} else {
|
||||
|
@ -687,6 +687,7 @@ static int fd_copy_tree_generic(
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags,
|
||||
const Set *denylist,
|
||||
HardlinkContext *hardlink_context,
|
||||
const char *display_path,
|
||||
copy_progress_path_t progress_path,
|
||||
@ -877,6 +878,7 @@ static int fd_copy_directory(
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags,
|
||||
const Set *denylist,
|
||||
HardlinkContext *hardlink_context,
|
||||
const char *display_path,
|
||||
copy_progress_path_t progress_path,
|
||||
@ -979,6 +981,11 @@ static int fd_copy_directory(
|
||||
return r;
|
||||
}
|
||||
|
||||
if (set_contains(denylist, &buf)) {
|
||||
log_debug("%s/%s is in the denylist, skipping", from, de->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR(buf.st_mode)) {
|
||||
/*
|
||||
* Don't descend into directories on other file systems, if this is requested. We do a simple
|
||||
@ -1011,7 +1018,10 @@ 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, hardlink_context, child_display_path, progress_path, progress_bytes, userdata);
|
||||
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, denylist,
|
||||
hardlink_context, child_display_path, progress_path, progress_bytes,
|
||||
userdata);
|
||||
|
||||
if (q == -EINTR) /* Propagate SIGINT/SIGTERM up instantly */
|
||||
return q;
|
||||
@ -1082,6 +1092,7 @@ static int fd_copy_tree_generic(
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags,
|
||||
const Set *denylist,
|
||||
HardlinkContext *hardlink_context,
|
||||
const char *display_path,
|
||||
copy_progress_path_t progress_path,
|
||||
@ -1090,7 +1101,9 @@ static int fd_copy_tree_generic(
|
||||
int r;
|
||||
|
||||
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, hardlink_context, display_path, progress_path, progress_bytes, userdata);
|
||||
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);
|
||||
|
||||
r = fd_copy_leaf(df, from, st, dt, to, override_uid, override_gid, copy_flags, hardlink_context, display_path, progress_bytes, userdata);
|
||||
/* We just tried to copy a leaf node of the tree. If it failed because the node already exists *and* the COPY_REPLACE flag has been provided, we should unlink the node and re-copy. */
|
||||
@ -1113,6 +1126,7 @@ int copy_tree_at_full(
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags,
|
||||
const Set *denylist,
|
||||
copy_progress_path_t progress_path,
|
||||
copy_progress_bytes_t progress_bytes,
|
||||
void *userdata) {
|
||||
@ -1126,7 +1140,9 @@ int copy_tree_at_full(
|
||||
if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
return -errno;
|
||||
|
||||
r = fd_copy_tree_generic(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
|
||||
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,
|
||||
progress_bytes, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1188,7 +1204,7 @@ int copy_directory_fd_full(
|
||||
COPY_DEPTH_MAX,
|
||||
UID_INVALID, GID_INVALID,
|
||||
copy_flags,
|
||||
NULL, NULL,
|
||||
NULL, NULL, NULL,
|
||||
progress_path,
|
||||
progress_bytes,
|
||||
userdata);
|
||||
@ -1231,7 +1247,7 @@ int copy_directory_full(
|
||||
COPY_DEPTH_MAX,
|
||||
UID_INVALID, GID_INVALID,
|
||||
copy_flags,
|
||||
NULL, NULL,
|
||||
NULL, NULL, NULL,
|
||||
progress_path,
|
||||
progress_bytes,
|
||||
userdata);
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "set.h"
|
||||
|
||||
typedef enum CopyFlags {
|
||||
COPY_REFLINK = 1 << 0, /* Try to reflink */
|
||||
COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */
|
||||
@ -45,12 +47,12 @@ static inline int copy_file_atomic(const char *from, const char *to, mode_t mode
|
||||
return copy_file_atomic_full(from, to, mode, chattr_flags, chattr_mask, 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, 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) {
|
||||
return copy_tree_at_full(fdf, from, fdt, to, override_uid, override_gid, copy_flags, 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, const Set *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, const Set *denylist) {
|
||||
return copy_tree_at_full(fdf, from, fdt, 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) {
|
||||
return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, 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, const Set *denylist) {
|
||||
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);
|
||||
|
@ -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) == -EEXIST);
|
||||
assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK, 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) == 0);
|
||||
assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE, NULL) == 0);
|
||||
|
||||
assert_se(read_file_at_and_streq(AT_FDCWD, dst, "bar bar\n"));
|
||||
}
|
||||
@ -91,14 +91,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) == -EEXIST);
|
||||
assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK, 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) == 0);
|
||||
assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE, 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"));
|
||||
@ -131,6 +131,8 @@ TEST(copy_file_fd) {
|
||||
}
|
||||
|
||||
TEST(copy_tree) {
|
||||
_cleanup_set_free_ Set *denylist = NULL;
|
||||
_cleanup_free_ char *cp = NULL;
|
||||
char original_dir[] = "/tmp/test-copy_tree/";
|
||||
char copy_dir[] = "/tmp/test-copy_tree-copy/";
|
||||
char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file");
|
||||
@ -138,7 +140,7 @@ TEST(copy_tree) {
|
||||
"link2", "dir1/file");
|
||||
char **hardlinks = STRV_MAKE("hlink", "file",
|
||||
"hlink2", "dir1/file");
|
||||
const char *unixsockp;
|
||||
const char *unixsockp, *ignorep;
|
||||
struct stat st;
|
||||
int xattr_worked = -1; /* xattr support is optional in temporary directories, hence use it if we can,
|
||||
* but don't fail if we can't */
|
||||
@ -184,7 +186,14 @@ TEST(copy_tree) {
|
||||
unixsockp = strjoina(original_dir, "unixsock");
|
||||
assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0);
|
||||
|
||||
assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS) == 0);
|
||||
ignorep = strjoina(original_dir, "ignore/file");
|
||||
assert_se(write_string_file(ignorep, "ignore", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) == 0);
|
||||
assert_se(RET_NERRNO(stat(ignorep, &st)) >= 0);
|
||||
assert_se(cp = memdup(&st, sizeof(st)));
|
||||
assert_se(set_ensure_put(&denylist, &inode_hash_ops, cp) >= 0);
|
||||
TAKE_PTR(cp);
|
||||
|
||||
assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS, denylist) == 0);
|
||||
|
||||
STRV_FOREACH(p, files) {
|
||||
_cleanup_free_ char *buf, *f, *c = NULL;
|
||||
@ -236,8 +245,11 @@ 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) < 0);
|
||||
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK) < 0);
|
||||
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);
|
||||
|
||||
ignorep = strjoina(copy_dir, "ignore/file");
|
||||
assert_se(RET_NERRNO(access(ignorep, F_OK)) == -ENOENT);
|
||||
|
||||
(void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||
(void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||
|
@ -1637,7 +1637,8 @@ static int copy_files(Item *i) {
|
||||
dfd, bn,
|
||||
i->uid_set ? i->uid : UID_INVALID,
|
||||
i->gid_set ? i->gid : GID_INVALID,
|
||||
COPY_REFLINK | COPY_MERGE_EMPTY | COPY_MAC_CREATE | COPY_HARDLINKS);
|
||||
COPY_REFLINK | COPY_MERGE_EMPTY | COPY_MAC_CREATE | COPY_HARDLINKS,
|
||||
NULL);
|
||||
|
||||
fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
|
||||
if (fd < 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user