summaryrefslogtreecommitdiff
path: root/src/shared/copy.c
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2023-02-20 20:30:44 +0100
committerDaan De Meyer <daan.j.demeyer@gmail.com>2023-02-22 12:44:36 +0100
commitb63bd125d4fb8ad1905d6c7dc4d87033ecf8148c (patch)
treeb49e4ae1f36c310a56a33579742294ab38bb5882 /src/shared/copy.c
parent5ab863be51ba8a700c30f9d7b4f42ca82836263a (diff)
downloadsystemd-b63bd125d4fb8ad1905d6c7dc4d87033ecf8148c.tar.gz
copy: Support both inode exclusion and contents exclusion
In some cases, we want to exclude a directory's contents but not the directory itself. In other cases, we want to exclude a directory and its contents. Let's extend the denylist logic in copy.h to support both by changing the denylist from a set to hashmap so we can store the deny type as the value. We also modify the repart ExcludeFiles= option to make use of this. If a directory to exclude ends with a "/", we'll only exclude its contents. Otherwise, we'll exclude the full directory.
Diffstat (limited to 'src/shared/copy.c')
-rw-r--r--src/shared/copy.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/src/shared/copy.c b/src/shared/copy.c
index a1df3048ba..9963e10f4d 100644
--- a/src/shared/copy.c
+++ b/src/shared/copy.c
@@ -694,7 +694,7 @@ static int fd_copy_tree_generic(
uid_t override_uid,
gid_t override_gid,
CopyFlags copy_flags,
- const Set *denylist,
+ Hashmap *denylist,
HardlinkContext *hardlink_context,
const char *display_path,
copy_progress_path_t progress_path,
@@ -897,7 +897,7 @@ static int fd_copy_directory(
uid_t override_uid,
gid_t override_gid,
CopyFlags copy_flags,
- const Set *denylist,
+ Hashmap *denylist,
HardlinkContext *hardlink_context,
const char *display_path,
copy_progress_path_t progress_path,
@@ -971,6 +971,11 @@ static int fd_copy_directory(
r = 0;
+ if (PTR_TO_INT(hashmap_get(denylist, st)) == DENY_CONTENTS) {
+ log_debug("%s is in the denylist, not recursing", from);
+ goto finish;
+ }
+
FOREACH_DIRENT_ALL(de, d, return -errno) {
const char *child_display_path = NULL;
_cleanup_free_ char *dp = NULL;
@@ -1000,8 +1005,8 @@ 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);
+ if (PTR_TO_INT(hashmap_get(denylist, &buf)) == DENY_INODE) {
+ log_debug("%s/%s is in the denylist, ignoring", from, de->d_name);
continue;
}
@@ -1050,6 +1055,7 @@ static int fd_copy_directory(
r = q;
}
+finish:
if (created) {
if (fchown(fdt,
uid_is_valid(override_uid) ? override_uid : st->st_uid,
@@ -1111,7 +1117,7 @@ static int fd_copy_tree_generic(
uid_t override_uid,
gid_t override_gid,
CopyFlags copy_flags,
- const Set *denylist,
+ Hashmap *denylist,
HardlinkContext *hardlink_context,
const char *display_path,
copy_progress_path_t progress_path,
@@ -1124,6 +1130,13 @@ static int fd_copy_tree_generic(
override_gid, copy_flags, denylist, hardlink_context, display_path,
progress_path, progress_bytes, userdata);
+ DenyType t = PTR_TO_INT(hashmap_get(denylist, st));
+ if (t == DENY_INODE) {
+ log_debug("%s is in the denylist, ignoring", from);
+ return 0;
+ } else if (t == DENY_CONTENTS)
+ log_debug("%s is configured to have its contents excluded, but is not a directory", from);
+
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. */
if (r == -EEXIST && (copy_flags & COPY_REPLACE)) {
@@ -1145,7 +1158,7 @@ int copy_tree_at_full(
uid_t override_uid,
gid_t override_gid,
CopyFlags copy_flags,
- const Set *denylist,
+ Hashmap *denylist,
copy_progress_path_t progress_path,
copy_progress_bytes_t progress_bytes,
void *userdata) {