Manually finds the location of the timestamp, and replaces it with the
timestamp from the top debian changelog entry.

Adds a dependency on Parse::DebianChangelog.
---
 Makefile.PL                                 |  1 +
 lib/File/StripNondeterminism.pm             |  6 +++
 lib/File/StripNondeterminism/handlers/pe.pm | 72 +++++++++++++++++++++++++++++
 3 files changed, 79 insertions(+)
 create mode 100644 lib/File/StripNondeterminism/handlers/pe.pm

diff --git a/Makefile.PL b/Makefile.PL
index 0a40613..8c07ace 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -13,6 +13,7 @@ WriteMakefile(
        PREREQ_PM => {
                'Archive::Zip'  => 0,
                'Getopt::Long'  => 0,
+               'Parse::DebianChangelog'        => 0,
        },
        LICENSE         => "gpl",
        dist            => { COMPRESS => 'gzip -9nf', SUFFIX => 'gz', },
diff --git a/lib/File/StripNondeterminism.pm b/lib/File/StripNondeterminism.pm
index 9f86acd..89f0ac5 100644
--- a/lib/File/StripNondeterminism.pm
+++ b/lib/File/StripNondeterminism.pm
@@ -25,6 +25,7 @@ use File::StripNondeterminism::handlers::ar;
 use File::StripNondeterminism::handlers::gzip;
 use File::StripNondeterminism::handlers::jar;
 use File::StripNondeterminism::handlers::javadoc;
+use File::StripNondeterminism::handlers::pe;
 use File::StripNondeterminism::handlers::pomproperties;
 use File::StripNondeterminism::handlers::zip;
 
@@ -63,6 +64,10 @@ sub get_normalizer_for_file {
        if (m/\.html$/ && 
File::StripNondeterminism::handlers::javadoc::is_javadoc_file($_)) {
                return 
\&File::StripNondeterminism::handlers::javadoc::normalize;
        }
+       # PE executables
+       if (m/\.(exe|dll|cpl|ocx|sys|scr|drv|efi|fon)/ && _get_file_type($_) =~ 
m/PE32.? executable/) {
+               return \&File::StripNondeterminism::handlers::pe::normalize;
+       }
        # pomproperties
        if (m/pom\.properties$/ && 
File::StripNondeterminism::handlers::pomproperties::is_pom_properties_file($_)) 
{
                return 
\&File::StripNondeterminism::handlers::pomproperties::normalize;
@@ -80,6 +85,7 @@ sub get_normalizer_by_name {
        return \&File::StripNondeterminism::handlers::gzip::normalize if $_ eq 
'gzip';
        return \&File::StripNondeterminism::handlers::jar::normalize if $_ eq 
'jar';
        return \&File::StripNondeterminism::handlers::javadoc::normalize if $_ 
eq 'javadoc';
+       return \&File::StripNondeterminism::handlers::pe::normalize if $_ eq 
'pe';
        return \&File::StripNondeterminism::handlers::pomproperties::normalize 
if $_ eq 'pomproperties';
        return \&File::StripNondeterminism::handlers::zip::normalize if $_ eq 
'zip';
        return undef;
diff --git a/lib/File/StripNondeterminism/handlers/pe.pm 
b/lib/File/StripNondeterminism/handlers/pe.pm
new file mode 100644
index 0000000..ec04cad
--- /dev/null
+++ b/lib/File/StripNondeterminism/handlers/pe.pm
@@ -0,0 +1,72 @@
+#
+# This file is part of strip-nondeterminism.
+#
+# strip-nondeterminism is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# strip-nondeterminism is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with strip-nondeterminism.  If not, see <http://www.gnu.org/licenses/>.
+#
+package File::StripNondeterminism::handlers::pe;
+
+use strict;
+use warnings;
+
+use Cwd;
+use Fcntl ":seek";
+use Parse::DebianChangelog;
+
+# "cd .." until we find a debian/ directory; fixes cwd afterwards
+sub debian_dir {
+       my $dir = getcwd;
+       while (! -d "debian") {
+               chdir("..") or die("couldn't find a debian directory: $!");
+               die("found the root while looking for debian directory: $!")
+                       if (getcwd eq "/");
+       }
+       my $found = getcwd;
+       chdir($dir) or die("couldn't undo my mess: $!");
+       return "$found/debian";
+}
+
+my $target_time = (Parse::DebianChangelog
+       ->init({infile => debian_dir() . "/changelog"})->data)[0]
+               ->Timestamp;
+
+sub normalize {
+       my ($filename) = @_;
+       open(my $f, "+<", $filename) or die("couldn't open $filename: $!");
+       binmode($f);
+       read($f, my $mx, 2) or die("couldn't try to read initial header: $!");
+       return if ($mx ne 'MZ');
+
+       seek($f, 0x3A, SEEK_CUR) or die("couldn't jump to e_lfanew location: 
$!");
+       read($f, my $encoded_off, 4) or die("couldn't read e_lfanew field: $!");
+       my $off = unpack("V", $encoded_off);
+       seek($f, $off, SEEK_SET) or die("couldn't seek to start of PE section: 
$!");
+
+       read($f, my $pe, 2) or die("couldn't read PE header: $!");
+       return if $pe ne 'PE';
+
+       seek($f, 2+2+2, SEEK_CUR) or die("couldn't skip mMachine and 
mNumberOfSections: $!");
+       read($f, my $encoded_time, 4) or die("couldn't read timestamp: $!");
+       my $time = unpack("V", $encoded_time);
+
+       print("$time < $target_time") if $time < $target_time;
+       die("file from the future: $encoded_time)") if time > time;
+
+       $encoded_time = pack("V", $target_time);
+
+       seek($f, -4, SEEK_CUR) or die("impossibly couldn't seek to where we 
were before: $!");
+       print $f $encoded_time;
+       close($f) or die("couldn't close file: $!");
+}
+
+1;
-- 
2.1.0


_______________________________________________
Reproducible-builds mailing list
Reproducible-builds@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/reproducible-builds

Reply via email to