]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
mkfs-util: Skip non files/directories when calling mcopy 25500/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 23 Nov 2022 13:12:38 +0000 (14:12 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 24 Nov 2022 13:02:22 +0000 (14:02 +0100)
Only files and directories are supported by vfat. When we pass a
symlink to mcopy, it will try to dereference them and copy what the
symlink points at into the vfat partition instead. Let's avoid this
by skipping all unsupported file types when establishing the list of
top level targets that mcopy should copy.

We also use RECURSE_DIR_SORT everywhere when iterating directories
to make things more reproducible.

src/shared/mkfs-util.c

index 5a56c5e473a870829fc2e04dc6e4bad3c80d2762..cd15e88ee012cd1dab08fafdc5d3515ed7997966 100644 (file)
@@ -129,7 +129,8 @@ static int setup_userns(uid_t uid, gid_t gid) {
 
 static int do_mcopy(const char *node, const char *root) {
         _cleanup_strv_free_ char **argv = NULL;
-        _cleanup_closedir_ DIR *rootdir = NULL;
+        _cleanup_close_ int rfd = -1;
+        _cleanup_free_ DirectoryEntries *de = NULL;
         struct stat st;
         int r;
 
@@ -147,15 +148,24 @@ static int do_mcopy(const char *node, const char *root) {
         /* mcopy copies the top level directory instead of everything in it so we have to pass all
          * the subdirectories to mcopy instead to end up with the correct directory structure. */
 
-        rootdir = opendir(root);
-        if (!rootdir)
-                return log_error_errno(errno, "Failed to open directory '%s'", root);
+        rfd = open(root, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+        if (rfd < 0)
+                return log_error_errno(errno, "Failed to open directory '%s': %m", root);
 
-        FOREACH_DIRENT(de, rootdir, return -errno) {
-                char *p = path_join(root, de->d_name);
+        r = readdir_all(rfd, RECURSE_DIR_SORT|RECURSE_DIR_ENSURE_TYPE, &de);
+        if (r < 0)
+                return log_error_errno(r, "Failed to read '%s' contents: %m", root);
+
+        for (size_t i = 0; i < de->n_entries; i++) {
+                char *p = path_join(root, de->entries[i]->d_name);
                 if (!p)
                         return log_oom();
 
+                if (!IN_SET(de->entries[i]->d_type, DT_REG, DT_DIR)) {
+                        log_debug("%s is not a file/directory which are the only file types supported by vfat, ignoring", p);
+                        continue;
+                }
+
                 r = strv_consume(&argv, TAKE_PTR(p));
                 if (r < 0)
                         return log_oom();
@@ -165,7 +175,7 @@ static int do_mcopy(const char *node, const char *root) {
         if (r < 0)
                 return log_oom();
 
-        if (fstat(dirfd(rootdir), &st) < 0)
+        if (fstat(rfd, &st) < 0)
                 return log_error_errno(errno, "Failed to stat '%s': %m", root);
 
         r = safe_fork("(mcopy)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR|FORK_NEW_USERNS|FORK_CLOSE_ALL_FDS, NULL);
@@ -262,7 +272,7 @@ static int make_protofile(const char *root, char **ret) {
               "0 0\n"
               "d--755 0 0\n", f);
 
-        r = recurse_dir_at(AT_FDCWD, root, STATX_TYPE|STATX_MODE, UINT_MAX, 0, protofile_print_item, f);
+        r = recurse_dir_at(AT_FDCWD, root, STATX_TYPE|STATX_MODE, UINT_MAX, RECURSE_DIR_SORT, protofile_print_item, f);
         if (r < 0)
                 return log_error_errno(r, "Failed to recurse through %s: %m", root);