From 554a2b64934a1cc6815f2df126811271d5c0ac9d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Apr 2021 23:21:21 +0200 Subject: [PATCH 1/3] repart: prefix the correct path with root dir in log output When we copy files into the freshly formatted file system, the mount point prefix must be prepended to the *target* path, not the *source* path. Not just in code but in the log message about it, too. --- src/partition/repart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/partition/repart.c b/src/partition/repart.c index 3e88d38205..9e297f19b9 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -2846,7 +2846,7 @@ static int do_copy_files(Partition *p, const char *fs) { UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS); if (r < 0) - return log_error_errno(r, "Failed to copy %s%s to %s: %m", strempty(arg_root), *source, *target); + return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target); } else { /* We are looking at a regular file */ @@ -2864,7 +2864,7 @@ static int do_copy_files(Partition *p, const char *fs) { r = copy_bytes(sfd, tfd, UINT64_MAX, COPY_REFLINK|COPY_SIGINT); if (r < 0) - return log_error_errno(r, "Failed to copy '%s%s' to '%s': %m", strempty(arg_root), *source, *target); + return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target); (void) copy_xattr(sfd, tfd); (void) copy_access(sfd, tfd); From e28190673ca83d62692dae6d791161bece820030 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Apr 2021 23:22:26 +0200 Subject: [PATCH 2/3] repart: don't use basename() when we called path_extract_filename() anyway already We already have the string, use it. --- src/partition/repart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/partition/repart.c b/src/partition/repart.c index 9e297f19b9..7809641fc8 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -2858,7 +2858,7 @@ static int do_copy_files(Partition *p, const char *fs) { if (pfd < 0) return log_error_errno(pfd, "Failed to open parent directory of target: %m"); - tfd = openat(pfd, basename(*target), O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC, 0700); + tfd = openat(pfd, fn, O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC, 0700); if (tfd < 0) return log_error_errno(errno, "Failed to create target file '%s': %m", *target); From f21a3a82fb6532d0f858c4f59c235af263a4131b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Apr 2021 23:23:07 +0200 Subject: [PATCH 3/3] repart: don't try to extract directory of root dir when copying directories It's OK to specify the root dir as target directory when copying directories. However, in that case path_extract_filename() is going to fail, because the root dir simply has not filename. Let's address that by moving the call further down into the loop, when we made sure that the target dir doesn't exist yet (the root dir always exists, hence this check is sufficient). Moreover, in the branch for copying regular files, also move the calls down, and generate friendly error messages in case people try to overwrite dirs with regular files (and the root dir is just a special case of a dir). Altogether this makes CopyFiles=/some/place:/ work, i.e. copying some dir on the host into the root dir of the newly created fs. Previously this would fail with an error about the inability to extract a filename from "/", needlessly. --- src/partition/repart.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/partition/repart.c b/src/partition/repart.c index 7809641fc8..3b31109952 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -2801,15 +2801,6 @@ static int do_copy_files(Partition *p, const char *fs) { STRV_FOREACH_PAIR(source, target, p->copy_files) { _cleanup_close_ int sfd = -1, pfd = -1, tfd = -1; - _cleanup_free_ char *dn = NULL, *fn = NULL; - - r = path_extract_directory(*target, &dn); - if (r < 0) - return log_error_errno(r, "Failed to extract directory from '%s': %m", *target); - - r = path_extract_filename(*target, &fn); - if (r < 0) - return log_error_errno(r, "Failed to extract filename from '%s': %m", *target); sfd = chase_symlinks_and_open(*source, arg_root, CHASE_PREFIX_ROOT|CHASE_WARN, O_CLOEXEC|O_NOCTTY, NULL); if (sfd < 0) @@ -2823,9 +2814,19 @@ static int do_copy_files(Partition *p, const char *fs) { /* We are looking at a directory */ tfd = chase_symlinks_and_open(*target, fs, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL); if (tfd < 0) { + _cleanup_free_ char *dn = NULL, *fn = NULL; + if (tfd != -ENOENT) return log_error_errno(tfd, "Failed to open target directory '%s': %m", *target); + r = path_extract_filename(*target, &fn); + if (r < 0) + return log_error_errno(r, "Failed to extract filename from '%s': %m", *target); + + r = path_extract_directory(*target, &dn); + if (r < 0) + return log_error_errno(r, "Failed to extract directory from '%s': %m", *target); + r = mkdir_p_root(fs, dn, UID_INVALID, GID_INVALID, 0755); if (r < 0) return log_error_errno(r, "Failed to create parent directory '%s': %m", dn); @@ -2848,8 +2849,21 @@ static int do_copy_files(Partition *p, const char *fs) { if (r < 0) return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target); } else { + _cleanup_free_ char *dn = NULL, *fn = NULL; + /* We are looking at a regular file */ + r = path_extract_filename(*target, &fn); + if (r == -EADDRNOTAVAIL || r == O_DIRECTORY) + return log_error_errno(SYNTHETIC_ERRNO(EISDIR), + "Target path '%s' refers to a directory, but source path '%s' refers to regular file, can't copy.", *target, *source); + if (r < 0) + return log_error_errno(r, "Failed to extract filename from '%s': %m", *target); + + r = path_extract_directory(*target, &dn); + if (r < 0) + return log_error_errno(r, "Failed to extract directory from '%s': %m", *target); + r = mkdir_p_root(fs, dn, UID_INVALID, GID_INVALID, 0755); if (r < 0) return log_error_errno(r, "Failed to create parent directory: %m");