From 0275d0a656de921693f22c4b3dbd780670698829 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Bobbio?= <lunar@debian.org>
Date: Tue, 27 Aug 2013 22:38:31 +0200
Subject: [PATCH 1/3] Use a single timestamp when building a .deb

In order to make build reproducible in the future, we now use a single
timestamp in all ar headers and for all members of the control.tar and data.tar
archives.

Previously, each ar header would have the current time of its creation.
This level of precision is not really needed and the time of the beginning of
the build is good enough.

The tar members were previously using the mtime of the files on the filesystem.
In almost all cases, the files are created/copied during the package build, so
again, using the time of the creation of the .deb does not make much of a
difference.
---
 dpkg-deb/build.c   |   40 +++++++++++++++++++++++++++-------------
 dpkg-split/split.c |    4 ++--
 lib/dpkg/ar.c      |   12 ++++++------
 lib/dpkg/ar.h      |    6 +++---
 4 files changed, 38 insertions(+), 24 deletions(-)

diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c
index 99b014d..73e5bdd 100644
--- a/dpkg-deb/build.c
+++ b/dpkg-deb/build.c
@@ -38,6 +38,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <time.h>
 
 #include <dpkg/i18n.h>
 #include <dpkg/dpkg.h>
@@ -382,8 +383,9 @@ pkg_get_pathname(const char *dir, struct pkginfo *pkg)
   return path;
 }
 
+#define MTIME_ARG_LENGTH 30 /* length of --mtime=@18446744073709551616 + \0 */
 static void
-create_control_tar(const char *dir, int gzfd)
+create_control_tar(const char *dir, int gzfd, time_t mtime)
 {
   int p1[2], p2[2], p3[2];
   pid_t c1, c2, c3, c4;
@@ -394,13 +396,16 @@ create_control_tar(const char *dir, int gzfd)
   m_pipe(p2);
   c1 = subproc_fork();
   if (!c1) {
+    char mtime_arg[MTIME_ARG_LENGTH];
+
+    snprintf(mtime_arg, MTIME_ARG_LENGTH, "--mtime=@%lu", mtime);
     m_dup2(p1[0], 0); close(p1[0]); close(p1[1]);
     m_dup2(p2[1], 1); close(p2[0]); close(p2[1]);
     if (chdir(dir))
       ohshite(_("failed to chdir to `%.255s'"), dir);
     if (chdir(BUILDCONTROLDIR))
       ohshite(_("failed to chdir to `%.255s'"), ".../DEBIAN");
-    execlp(TAR, "tar", "-cf", "-", "--format=gnu", "--null", "-T", "-", "--no-recursion", NULL);
+    execlp(TAR, "tar", "-cf", "-", "--format=gnu", "--null", mtime_arg, "-T", "-", "--no-recursion", NULL);
     ohshite(_("unable to execute %s (%s)"), "tar -cf", TAR);
   }
   close(p1[0]);
@@ -456,6 +461,7 @@ create_control_tar(const char *dir, int gzfd)
   subproc_wait_check(c2, "gzip -9c", 0);
   subproc_wait_check(c1, "tar -cf", 0);
 }
+#undef MTIME_ARG_LENGTH
 
 static void
 write_format_zero_deb_header(const char *debar, int arfd, int gzfd)
@@ -476,7 +482,7 @@ write_format_zero_deb_header(const char *debar, int arfd, int gzfd)
 }
 
 static void
-write_deb_header(const char *debar, int arfd, int gzfd)
+write_deb_header(const char *debar, int arfd, int gzfd, time_t time)
 {
   const char deb_magic[] = ARCHIVEVERSION "\n";
 
@@ -490,8 +496,8 @@ write_deb_header(const char *debar, int arfd, int gzfd)
   }
 
   dpkg_ar_put_magic(debar, arfd);
-  dpkg_ar_member_put_mem(debar, arfd, DEBMAGIC, deb_magic, strlen(deb_magic));
-  dpkg_ar_member_put_file(debar, arfd, ADMINMEMBER, gzfd, -1);
+  dpkg_ar_member_put_mem(debar, arfd, DEBMAGIC, deb_magic, time, strlen(deb_magic));
+  dpkg_ar_member_put_file(debar, arfd, ADMINMEMBER, gzfd, time, -1);
 }
 
 static int
@@ -514,8 +520,9 @@ setup_temp_gz(char const * target_name)
   return gzfd;
 }
 
+#define MTIME_ARG_LENGTH 30 /* length of --mtime=@18446744073709551616 + \0 */
 static void
-create_data_tar(const char *dir, int gzfd)
+create_data_tar(const char *dir, int gzfd, time_t mtime)
 {
   int p1[2], p2[2], p3[2], p4[2];
   pid_t c1, c2, c3, c4;
@@ -528,11 +535,14 @@ create_data_tar(const char *dir, int gzfd)
   m_pipe(p2);
   c1 = subproc_fork();
   if (!c1) {
+    char mtime_arg[MTIME_ARG_LENGTH];
+
+    snprintf(mtime_arg, MTIME_ARG_LENGTH, "--mtime=@%lu", mtime);
     m_dup2(p1[0], 0); close(p1[0]); close(p1[1]);
     m_dup2(p2[1], 1); close(p2[0]); close(p2[1]);
     if (chdir(dir))
       ohshite(_("failed to chdir to `%.255s'"), dir);
-    execlp(TAR, "tar", "-cf", "-", "--format=gnu", "--null", "-T", "-", "--no-recursion", NULL);
+    execlp(TAR, "tar", "-cf", "-", "--format=gnu", "--null", mtime_arg, "-T", "-", "--no-recursion", NULL);
     ohshite(_("unable to execute %s (%s)"), "tar -cf", TAR);
   }
   close(p1[0]);
@@ -598,9 +608,10 @@ create_data_tar(const char *dir, int gzfd)
   subproc_wait_check(c2, _("<compress> from tar -cf"), 0);
   subproc_wait_check(c1, "tar -cf", 0);
 }
+#undef MTIME_ARG_LENGTH
 
 static void
-write_data_tar(const char *debar, int arfd, int gzfd)
+write_data_tar(const char *debar, int arfd, int gzfd, time_t time)
 {
   char datamember[16 + 1];
 
@@ -610,7 +621,7 @@ write_data_tar(const char *debar, int arfd, int gzfd)
   if (lseek(gzfd, 0, SEEK_SET))
     ohshite(_("failed to rewind temporary file (%s)"), _("data member"));
 
-  dpkg_ar_member_put_file(debar, arfd, datamember, gzfd, -1);
+  dpkg_ar_member_put_file(debar, arfd, datamember, gzfd, time, -1);
 }
 
 static void
@@ -683,12 +694,15 @@ do_build(const char *const *argv)
 {
   const char *debar, *dir;
   bool subdir;
+  time_t build_timestamp;
   int arfd;
   int gzfd;
 
   /* Decode our arguments. */
   decode_arguments(argv, &dir, &subdir, &debar);
 
+  build_timestamp = time(NULL);
+
   /* Perform some sanity checks on the to-be-build package. */
   check_build_sanity(dir, subdir, &debar);
 
@@ -698,11 +712,11 @@ do_build(const char *const *argv)
 
   gzfd = setup_temp_gz(_("control member"));
 
-  create_control_tar(dir, gzfd);
+  create_control_tar(dir, gzfd, build_timestamp);
 
   /* We have our first file for the ar-archive. Write a header for it
    * to the package and insert it. */
-  write_deb_header(debar, arfd, gzfd);
+  write_deb_header(debar, arfd, gzfd, build_timestamp);
 
   close(gzfd);
 
@@ -715,10 +729,10 @@ do_build(const char *const *argv)
   } else {
     gzfd = setup_temp_gz(_("data member"));
   }
-  create_data_tar(dir, gzfd);
+  create_data_tar(dir, gzfd, build_timestamp);
   /* Okay, we have data.tar as well now, add it to the ar wrapper. */
   if (deb_format.major != 0) {
-    write_data_tar(debar, arfd, gzfd);
+    write_data_tar(debar, arfd, gzfd, build_timestamp);
     if (fsync(gzfd))
       ohshite(_("unable to close temporary file for data member"));
   }
diff --git a/dpkg-split/split.c b/dpkg-split/split.c
index c8f9f5c..802ebe2 100644
--- a/dpkg-split/split.c
+++ b/dpkg-split/split.c
@@ -217,13 +217,13 @@ mksplit(const char *file_src, const char *prefix, off_t maxpartsize,
 		              (intmax_t)st.st_size, (intmax_t)partsize,
 		              curpart, nparts, arch);
 		dpkg_ar_member_put_mem(file_dst.buf, fd_dst, PARTMAGIC,
-		                       partmagic.buf, partmagic.used);
+		                       partmagic.buf, time(NULL), partmagic.used);
 		varbuf_reset(&partmagic);
 
 		/* Write the data part. */
 		varbuf_printf(&partname, "data.%d", curpart);
 		dpkg_ar_member_put_file(file_dst.buf, fd_dst, partname.buf,
-		                        fd_src, cur_partsize);
+		                        fd_src, time(NULL), cur_partsize);
 		varbuf_reset(&partname);
 
 		close(fd_dst);
diff --git a/lib/dpkg/ar.c b/lib/dpkg/ar.c
index 3c07a59..3e937c5 100644
--- a/lib/dpkg/ar.c
+++ b/lib/dpkg/ar.c
@@ -89,7 +89,7 @@ dpkg_ar_put_magic(const char *ar_name, int ar_fd)
 
 void
 dpkg_ar_member_put_header(const char *ar_name, int ar_fd,
-                          const char *name, off_t size)
+                          const char *name, time_t timestamp, off_t size)
 {
 	char header[sizeof(struct ar_hdr) + 1];
 	int n;
@@ -100,7 +100,7 @@ dpkg_ar_member_put_header(const char *ar_name, int ar_fd,
 		ohshit(_("ar member size %jd too large"), size);
 
 	n = sprintf(header, "%-16s%-12lu0     0     100644  %-10jd`\n",
-	            name, time(NULL), (intmax_t)size);
+	            name, timestamp, (intmax_t)size);
 	if (n != sizeof(struct ar_hdr))
 		ohshit(_("generated corrupt ar header for '%s'"), ar_name);
 
@@ -110,9 +110,9 @@ dpkg_ar_member_put_header(const char *ar_name, int ar_fd,
 
 void
 dpkg_ar_member_put_mem(const char *ar_name, int ar_fd,
-                       const char *name, const void *data, size_t size)
+                       const char *name, const void *data, time_t timestamp, size_t size)
 {
-	dpkg_ar_member_put_header(ar_name, ar_fd, name, size);
+	dpkg_ar_member_put_header(ar_name, ar_fd, name, timestamp, size);
 
 	/* Copy data contents. */
 	if (fd_write(ar_fd, data, size) < 0)
@@ -125,7 +125,7 @@ dpkg_ar_member_put_mem(const char *ar_name, int ar_fd,
 
 void
 dpkg_ar_member_put_file(const char *ar_name, int ar_fd,
-                        const char *name, int fd, off_t size)
+                        const char *name, int fd, time_t timestamp, off_t size)
 {
 	struct dpkg_error err;
 
@@ -137,7 +137,7 @@ dpkg_ar_member_put_file(const char *ar_name, int ar_fd,
 		size = st.st_size;
 	}
 
-	dpkg_ar_member_put_header(ar_name, ar_fd, name, size);
+	dpkg_ar_member_put_header(ar_name, ar_fd, name, timestamp, size);
 
 	/* Copy data contents. */
 	if (fd_fd_copy(fd, ar_fd, size, &err) < 0)
diff --git a/lib/dpkg/ar.h b/lib/dpkg/ar.h
index ec822c8..af7997b 100644
--- a/lib/dpkg/ar.h
+++ b/lib/dpkg/ar.h
@@ -43,11 +43,11 @@ bool dpkg_ar_member_is_illegal(struct ar_hdr *arh);
 
 void dpkg_ar_put_magic(const char *ar_name, int ar_fd);
 void dpkg_ar_member_put_header(const char *ar_name, int ar_fd,
-                               const char *name, off_t size);
+                               const char *name, time_t timestamp, off_t size);
 void dpkg_ar_member_put_file(const char *ar_name, int ar_fd, const char *name,
-                             int fd, off_t size);
+                             int fd, time_t timestamp, off_t size);
 void dpkg_ar_member_put_mem(const char *ar_name, int ar_fd, const char *name,
-                            const void *data, size_t size);
+                            const void *data, time_t timestamp, size_t size);
 off_t dpkg_ar_member_get_size(const char *ar_name, struct ar_hdr *arh);
 
 /** @} */
-- 
1.7.10.4

