#include "mountpoint-util.h"
#include "nulstr-util.h"
#include "path-util.h"
+#include "recurse-dir.h"
#include "rm-rf.h"
#include "selinux-util.h"
#include "signal-util.h"
.parent_fd = -EBADF,
};
+ _cleanup_free_ DirectoryEntries *des = NULL;
_cleanup_close_ int fdf = -EBADF, fdt = -EBADF;
_cleanup_closedir_ DIR *d = NULL;
struct stat dt_st;
goto finish;
}
- FOREACH_DIRENT_ALL(de, d, return -errno) {
+ /* Walk children in deterministic (alphabetical) order. The natural readdir() order depends on the
+ * source filesystem's directory storage (e.g. ext4 dir hash) and varies across hosts, which leaks
+ * into the destination when it records entries in insertion order (e.g. vfat). Sorting here keeps
+ * copy_tree() reproducible regardless of the source filesystem layout. */
+ r = readdir_all(dirfd(d), RECURSE_DIR_SORT, &des);
+ if (r < 0)
+ return r;
+
+ FOREACH_ARRAY(i, des->entries, des->n_entries) {
+ struct dirent *de = *i;
const char *child_display_path = NULL;
_cleanup_free_ char *dp = NULL;
struct stat buf;
- if (dot_or_dot_dot(de->d_name))
- continue;
-
r = look_for_signals(copy_flags);
if (r < 0)
return r;