From f33c8ba8091b73150de30bb9df6cdbee6308099e Mon Sep 17 00:00:00 2001 From: Dan Bungert Date: Tue, 10 Jun 2025 16:01:37 -0600 Subject: [PATCH] lb_binary_layered: second take on fixing mtimes --- debian/install | 1 + live-build/lb_binary_layered | 13 ++++++++++-- sync-mtime | 38 ++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100755 sync-mtime diff --git a/debian/install b/debian/install index 665a5443..c30d0f39 100644 --- a/debian/install +++ b/debian/install @@ -4,3 +4,4 @@ get-ppa-fingerprint usr/share/livecd-rootfs minimize-manual usr/share/livecd-rootfs checkout-translations-branch usr/share/livecd-rootfs update-source-catalog usr/share/livecd-rootfs +sync-mtime usr/share/livecd-rootfs diff --git a/live-build/lb_binary_layered b/live-build/lb_binary_layered index 75dfe9c7..f12e3512 100755 --- a/live-build/lb_binary_layered +++ b/live-build/lb_binary_layered @@ -163,15 +163,24 @@ build_layered_squashfs () { # (rather than the default which is to skip copies based # on size + mtime) # --no-times to not copy mtimes from source to dest (we - # don't care about mtime in the image and want to + # do care about mtime in the image but want to # deduplicate files that have indentical contents but - # different mtimes) + # different mtimes, and mtime will be fixed below) # --del because we want to remove files that have been # deleted in this layer. rsync -aXHAS --checksum --no-times --del chroot/ chroot-2/ umount chroot-2 rmdir chroot-2 overlay_dir="$overlay_dir-2" + # We use rsync with --no-times rsync (see above) + # for the absolute best size reduction. But there are + # cases where we want mtime preservation to match what + # was found in the original archive packages, such as + # keeping .py mtime in sync with the matching .pyc. + # Operate on the upperdir directly, so that we are only + # modifying mtime on files that are actually changed in + # this layer. LP: #2107332 + /usr/share/livecd-rootfs/sync-mtime chroot "$overlay_dir" fi create_squashfs "${overlay_dir}" ${squashfs_f} diff --git a/sync-mtime b/sync-mtime new file mode 100755 index 00000000..e27c0543 --- /dev/null +++ b/sync-mtime @@ -0,0 +1,38 @@ +#!/usr/bin/python3 + +# usage: sync-mtime src dst +# +# synchronize atime/mtime on files between src and dst. +# +# src and dst are directories, where dst is expected to contain a subset of the +# files found in src. for each file present in dst or a subdirectory thereof, +# if atime/mtime differ between the same file in src and that file in dst, +# update atime/mtime on the file in dst. + +import os +import sys +from pathlib import Path + + +def time_eq(a: os.stat_result, b: os.stat_result) -> bool: + return ( + (a.st_mtime_ns == b.st_mtime_ns) and + (a.st_atime_ns == b.st_atime_ns) + ) + + +src, dst = sys.argv[1:] +for dirpath, dirnames, filenames in Path(dst).walk(): + for filename in filenames: + dst_file = dirpath / filename + if not dst_file.is_file(): + continue + src_file = src / dst_file.relative_to(dst) + + src_stat = src_file.stat(follow_symlinks=False) + dst_stat = dst_file.stat(follow_symlinks=False) + if time_eq(src_stat, dst_stat): + continue + + ns = (src_stat.st_atime_ns, src_stat.st_mtime_ns) + os.utime(dst_file, ns=ns, follow_symlinks=False)