Hi again,

Some quick clarifications.

Jonathan Nieder wrote:

> GNU patch just _preserves_ file timestamps when patching.  Could
> dpkg-source do that?

No, dpkg-source shouldn't (Bug#105750).  It also seems I misunderstood
patch's behavior --- sorry for the nonsense.

> (NEEDSWORK: does not handle nanosecond timestamps.)

Core perl does not seem to provide an interface to futimens (I'll file
a bug against Time::HiRes), so I guess nanosecond timestamps will have
to wait.

[...]
> +sub touch_patched_files {
[...]
> +     my $fn = shift @files;

Should use $files[0] without shifting so all timestamps get the same
resolution.

> +     utime(undef, undef, $fn) ||
> +         syserr(_g("cannot change timestamp for %s"), $fn);
> +     lstat($fn) ||
> +         syserr(_g("cannot read timestamp from %s"), $fn);

Can fail for a deletion patch.  Better to loop to find a file to
touch.

[...]
> +     touch_patched_files($now, %{$analysis->{'filepatched'}});

Missing "keys".  Some other typos.  The following might actually work.
Thoughts?

-- 8< --
Subject: dpkg-source: use utime(undef, ...) to touch patched files

Since 1.13.14~20 (2006-02-10), dpkg-source touches the files it
patches when unpacking, with a single date.  This way, the order of
mtimes does not depend on the order in which the files were patched,
which is convenient when e.g. configure.in and configure are patched.

More precisely, dpkg-source uses code like the following:

        my $now = time();
        foreach my $fn (@patched_files) {
                utime($now, $now, $fn);
        }

Unfortunately when the filesystem is NFS, "touch" and normal
modification set mtime and atime to the current time on the server
side, while time() returns the current time on the client side.
The two clocks can disagree, producing breakage.

So use utime(undef, undef, $fn) to set mtime for the first file to
the server side time and copy it (rounded down to a number of seconds)
to all patched files.

Fixes: http://bugs.debian.org/613023
Reported-by: Stéphane Glondu <glo...@debian.org>
Signed-off-by: Jonathan Nieder <jrnie...@gmail.com>
---
Support for nanosecond-resolution timestamps can come later.  At
least this does not seem to make it worse.

 scripts/Dpkg/Source/Patch.pm |   44 ++++++++++++++++++++++++++++++++++++-----
 1 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/scripts/Dpkg/Source/Patch.pm b/scripts/Dpkg/Source/Patch.pm
index 59d1004..07bc381 100644
--- a/scripts/Dpkg/Source/Patch.pm
+++ b/scripts/Dpkg/Source/Patch.pm
@@ -465,6 +465,39 @@ sub prepare_apply {
     }
 }
 
+sub touch_patched_files {
+    my ($now, @files) = @_;
+    return unless @files;
+
+    unless (defined($now)) {
+       # On NFS, "utime(undef, undef, $file)" sets mtime and atime to the
+       # current time on the server side.  The time() function returns
+       # the current time on the client side.  Sadly, the two can disagree.
+       #
+       # Everything else (normal modification, "touch") uses the time on
+       # the server side, so to avoid problems in the presence of time
+       # skew, we should, too.
+
+       my $touched;
+       foreach my $fn (@files) {
+           if (utime(undef, undef, $fn)) {
+               $touched = $fn;
+               last;
+           } elsif ($! != ENOENT) {
+               syserr(_g("cannot change timestamp for %s"), $fn);
+           }
+       }
+       return unless defined($touched);
+       lstat($touched) ||
+           syserr(_g("cannot read timestamp from %s"), $touched);
+       $now = (lstat("_"))[9];
+    }
+
+    utime($now, $now, @files) ||
+       $! == ENOENT ||
+       syserr(_g("cannot change timestamp of patched file"));
+}
+
 sub apply {
     my ($self, $destdir, %opts) = @_;
     # Set default values to options
@@ -500,13 +533,12 @@ sub apply {
     }
     $self->close();
     # Reset the timestamp of all the patched files
-    # and remove .dpkg-orig files
-    my $now = $opts{"timestamp"} || time;
+    if ($opts{"force_timestamp"}) {
+       my $now = $opts{"timestamp"} || undef;
+       touch_patched_files($now, keys %{$analysis->{'filepatched'}});
+    }
+    # Remove .dpkg-orig files
     foreach my $fn (keys %{$analysis->{'filepatched'}}) {
-       if ($opts{"force_timestamp"}) {
-           utime($now, $now, $fn) || $! == ENOENT ||
-               syserr(_g("cannot change timestamp for %s"), $fn);
-       }
        if ($opts{"remove_backup"}) {
            $fn .= ".dpkg-orig";
            unlink($fn) || syserr(_g("remove patch backup file %s"), $fn);
-- 
1.7.4.1




--
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Reply via email to