]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: don't try to extract directory of root dir when copying directories 19390/head
authorLennart Poettering <lennart@poettering.net>
Wed, 21 Apr 2021 21:23:07 +0000 (23:23 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 21 Apr 2021 21:30:49 +0000 (23:30 +0200)
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

index 7809641fc8807484c6bfa481a972259a92d4500f..3b311099525b7ed3caddf9f8d9f137f7dc281a36 100644 (file)
@@ -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");