Skip to content

Commit

Permalink
repart: Keep existing directory timestamps intact when copying
Browse files Browse the repository at this point in the history
Otherwise, when merging multiple directory trees, the output becomes
unreproducible as the directory timestamps will be changed to the current
time when copying identical directories from the second tree.

We introduce a new copy flag to achieve this behavior.

(cherry picked from commit d850a544bc1f895decb452160c97a884a20b12b7)
(cherry picked from commit d5640c4f8583de2752a7f4e03006a1fa74942da1)
(cherry picked from commit 7a3b3ad)
(cherry picked from commit 87cc4d9)
  • Loading branch information
DaanDeMeyer authored and bluca committed Sep 11, 2024
1 parent f37f685 commit 3adfd9f
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 3 deletions.
4 changes: 2 additions & 2 deletions src/partition/repart.c
Original file line number Diff line number Diff line change
Expand Up @@ -3836,14 +3836,14 @@ static int do_copy_files(Partition *p, const char *root, const Set *denylist) {
sfd, ".",
pfd, fn,
UID_INVALID, GID_INVALID,
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN,
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_RESTORE_DIRECTORY_TIMESTAMPS,
denylist);
} else
r = copy_tree_at(
sfd, ".",
tfd, ".",
UID_INVALID, GID_INVALID,
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN,
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_RESTORE_DIRECTORY_TIMESTAMPS,
denylist);
if (r < 0)
return log_error_errno(r, "Failed to copy '%s%s' to '%s%s': %m",
Expand Down
8 changes: 7 additions & 1 deletion src/shared/copy.c
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,7 @@ static int fd_copy_directory(

_cleanup_close_ int fdf = -EBADF, fdt = -EBADF;
_cleanup_closedir_ DIR *d = NULL;
struct stat dt_st;
bool exists, created;
int r;

Expand Down Expand Up @@ -986,6 +987,9 @@ static int fd_copy_directory(
if (fdt < 0)
return -errno;

if (exists && FLAGS_SET(copy_flags, COPY_RESTORE_DIRECTORY_TIMESTAMPS) && fstat(fdt, &dt_st) < 0)
return -errno;

r = 0;

FOREACH_DIRENT_ALL(de, d, return -errno) {
Expand Down Expand Up @@ -1078,7 +1082,9 @@ static int fd_copy_directory(

(void) copy_xattr(dirfd(d), fdt, copy_flags);
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
}
} else if (FLAGS_SET(copy_flags, COPY_RESTORE_DIRECTORY_TIMESTAMPS))
/* If the directory already exists, make sure the timestamps stay the same as before. */
(void) futimens(fdt, (struct timespec[]) { dt_st.st_atim, dt_st.st_mtim });

if (copy_flags & COPY_FSYNC_FULL) {
if (fsync(fdt) < 0)
Expand Down
1 change: 1 addition & 0 deletions src/shared/copy.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ typedef enum CopyFlags {
COPY_ALL_XATTRS = 1 << 13, /* Preserve all xattrs when copying, not just those in the user namespace */
COPY_HOLES = 1 << 14, /* Copy holes */
COPY_GRACEFUL_WARN = 1 << 15, /* Skip copying file types that aren't supported by the target filesystem */
COPY_RESTORE_DIRECTORY_TIMESTAMPS = 1 << 16, /* Make sure existing directory timestamps don't change during copying. */
} CopyFlags;

typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
Expand Down

0 comments on commit 3adfd9f

Please sign in to comment.