Skip to content

Commit 3adfd9f

Browse files
DaanDeMeyerbluca
authored andcommitted
repart: Keep existing directory timestamps intact when copying
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 d850a54) (cherry picked from commit d5640c4) (cherry picked from commit 7a3b3ad) (cherry picked from commit 87cc4d9)
1 parent f37f685 commit 3adfd9f

File tree

3 files changed

+10
-3
lines changed

3 files changed

+10
-3
lines changed

src/partition/repart.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3836,14 +3836,14 @@ static int do_copy_files(Partition *p, const char *root, const Set *denylist) {
38363836
sfd, ".",
38373837
pfd, fn,
38383838
UID_INVALID, GID_INVALID,
3839-
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN,
3839+
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_RESTORE_DIRECTORY_TIMESTAMPS,
38403840
denylist);
38413841
} else
38423842
r = copy_tree_at(
38433843
sfd, ".",
38443844
tfd, ".",
38453845
UID_INVALID, GID_INVALID,
3846-
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN,
3846+
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_RESTORE_DIRECTORY_TIMESTAMPS,
38473847
denylist);
38483848
if (r < 0)
38493849
return log_error_errno(r, "Failed to copy '%s%s' to '%s%s': %m",

src/shared/copy.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,7 @@ static int fd_copy_directory(
928928

929929
_cleanup_close_ int fdf = -EBADF, fdt = -EBADF;
930930
_cleanup_closedir_ DIR *d = NULL;
931+
struct stat dt_st;
931932
bool exists, created;
932933
int r;
933934

@@ -986,6 +987,9 @@ static int fd_copy_directory(
986987
if (fdt < 0)
987988
return -errno;
988989

990+
if (exists && FLAGS_SET(copy_flags, COPY_RESTORE_DIRECTORY_TIMESTAMPS) && fstat(fdt, &dt_st) < 0)
991+
return -errno;
992+
989993
r = 0;
990994

991995
FOREACH_DIRENT_ALL(de, d, return -errno) {
@@ -1078,7 +1082,9 @@ static int fd_copy_directory(
10781082

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

10831089
if (copy_flags & COPY_FSYNC_FULL) {
10841090
if (fsync(fdt) < 0)

src/shared/copy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ typedef enum CopyFlags {
2828
COPY_ALL_XATTRS = 1 << 13, /* Preserve all xattrs when copying, not just those in the user namespace */
2929
COPY_HOLES = 1 << 14, /* Copy holes */
3030
COPY_GRACEFUL_WARN = 1 << 15, /* Skip copying file types that aren't supported by the target filesystem */
31+
COPY_RESTORE_DIRECTORY_TIMESTAMPS = 1 << 16, /* Make sure existing directory timestamps don't change during copying. */
3132
} CopyFlags;
3233

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

0 commit comments

Comments
 (0)