diff options
author | Daan De Meyer <daan.j.demeyer@gmail.com> | 2023-02-20 20:30:44 +0100 |
---|---|---|
committer | Daan De Meyer <daan.j.demeyer@gmail.com> | 2023-02-22 12:44:36 +0100 |
commit | b63bd125d4fb8ad1905d6c7dc4d87033ecf8148c (patch) | |
tree | b49e4ae1f36c310a56a33579742294ab38bb5882 /src/shared/copy.c | |
parent | 5ab863be51ba8a700c30f9d7b4f42ca82836263a (diff) | |
download | systemd-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.c | 25 |
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) { |