diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-04-21 23:23:07 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-04-21 23:30:49 +0200 |
commit | f21a3a82fb6532d0f858c4f59c235af263a4131b (patch) | |
tree | fa6fd168e5fe3d2098f8bd516e9f4e2a15710252 /src/partition | |
parent | e28190673ca83d62692dae6d791161bece820030 (diff) | |
download | systemd-f21a3a82fb6532d0f858c4f59c235af263a4131b.tar.gz |
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.
Diffstat (limited to 'src/partition')
-rw-r--r-- | src/partition/repart.c | 32 |
1 files 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"); |