Source: ghostscript
Version: 9.15~dfsg-1
Severity: wishlist
Tags: patch
User: reproducible-builds@lists.alioth.debian.org
Usertags: toolchain timestamps
X-Debbugs-Cc: reproducible-builds@lists.alioth.debian.org

Hi,

While working on the "reproducible builds" effort [1], we have noticed
that the ghostscript embeds timestamps on the creation of pdf files.

For the Reproducible Builds effort we are proposing an environment
variable (SOURCE_DATE_EPOCH) [2] that will contain a deterministic epoch
timestamp (based on the latest debian/changelog entry) that could be
used, which should be automatically exported by debhelper in the future [3].

The attached patch proposes a way to use this variable to get
reproducible timestamps in the pdf files generated by ghostscript, if
the variable has been set (if not, it falls back to the old behavior).
With the attached patch packages using ghostscript would then
automatically generate reproducible pdf files.


[1]: https://wiki.debian.org/ReproducibleBuilds
[2]: https://wiki.debian.org/ReproducibleBuilds/TimestampsProposal
[3]: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=791815

Regards,
-- 
Dhole
diff -Nru ghostscript-9.15~dfsg/debian/changelog 
ghostscript-9.15~dfsg/debian/changelog
--- ghostscript-9.15~dfsg/debian/changelog      2015-07-26 20:17:32.000000000 
+0200
+++ ghostscript-9.15~dfsg/debian/changelog      2015-07-28 18:48:03.000000000 
+0200
@@ -1,3 +1,12 @@
+ghostscript (9.15~dfsg-1.0~reproducible1) UNRELEASED; urgency=medium
+
+  [ Peter De Wachter, Eduard Sanou ]
+  * Add patch to allow the build timestamp to be set through the environment
+    variable SOURCE_DATE_EPOCH, and set TZ=UTC in case the external timestamp
+    is used. This is needed for reproducible builds.
+
+ -- Eduard Sanou <dh...@openmailbox.org>  Tue, 28 Jul 2015 16:26:20 +0200
+
 ghostscript (9.15~dfsg-1) unstable; urgency=medium
 
   [ upstream ]
diff -Nru 
ghostscript-9.15~dfsg/debian/patches/2010_add_build_timestamp_setting.patch 
ghostscript-9.15~dfsg/debian/patches/2010_add_build_timestamp_setting.patch
--- ghostscript-9.15~dfsg/debian/patches/2010_add_build_timestamp_setting.patch 
1970-01-01 01:00:00.000000000 +0100
+++ ghostscript-9.15~dfsg/debian/patches/2010_add_build_timestamp_setting.patch 
2015-07-29 15:59:49.000000000 +0200
@@ -0,0 +1,122 @@
+Description: Allow the build timestamp to be externally set
+ In order to make Ghostscript output reproducible, we need a way to
+ set the build timestamp to other values than the current time.
+ We now consistently use gp_get_realtime() instead of directly calling
+ time() or gp_get_usertime() and make gp_get_realtime() use the value
+ found in the SOURCE_DATE_EPOCH environment variable if set. Also,
+ environment timezone is fixed to UTC if SOURCE_DATE_EPOCH is used to
+ avoid variations.
+Author: Peter De Wachter <pdewa...@gmail.com>, Eduard Sanou 
<dh...@openmailbox.org>
+
+Index: ghostscript-9.15~dfsg-1.0~reproducible1/base/gp_unix.c
+===================================================================
+--- ghostscript-9.15~dfsg-1.0~reproducible1.orig/base/gp_unix.c
++++ ghostscript-9.15~dfsg-1.0~reproducible1/base/gp_unix.c
+@@ -16,6 +16,7 @@
+ 
+ /* Unix-specific routines for Ghostscript */
+ 
++#include "errno_.h"
+ #include "pipe_.h"
+ #include "string_.h"
+ #include "time_.h"
+@@ -145,6 +146,7 @@ void
+ gp_get_realtime(long *pdt)
+ {
+     struct timeval tp;
++    const char *env;
+ 
+ #if gettimeofday_no_timezone    /* older versions of SVR4 */
+     {
+@@ -164,6 +166,26 @@ gp_get_realtime(long *pdt)
+     }
+ #endif
+ 
++    env = getenv("SOURCE_DATE_EPOCH");
++    if (env) {
++        char *end;
++        long timestamp;
++
++        errno = 0;
++        timestamp = strtol(env, &end, 10);
++        if (env == end || *end || errno != 0) {
++            lprintf("Ghostscript: SOURCE_DATE_EPOCH is not a number!\n");
++            timestamp = 0;
++        }
++
++        tp.tv_sec = timestamp;
++        tp.tv_usec = 0;
++
++        /* We need to fix the environment timezone to get reproducible */
++        /* results when parsing the result of gp_get_realtime. */
++        setenv("TZ", "UTC", 1);
++    }
++
+     /* tp.tv_sec is #secs since Jan 1, 1970 */
+     pdt[0] = tp.tv_sec;
+ 
+Index: ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpdf.c
+===================================================================
+--- ghostscript-9.15~dfsg-1.0~reproducible1.orig/devices/vector/gdevpdf.c
++++ ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpdf.c
+@@ -389,12 +389,14 @@ pdf_initialize_ids(gx_device_pdf * pdev)
+      */
+     {
+         struct tm tms;
++        long secs_ns[2];
+         time_t t;
+         char buf[1+2+4+2+2+2+2+2+1+2+1+2+1+1+1]; /* 
(D:yyyymmddhhmmssZhh'mm')\0 */
+         int timeoffset;
+         char timesign;
+ 
+-        time(&t);
++        gp_get_realtime(secs_ns);
++        t = secs_ns[0];
+         tms = *gmtime(&t);
+         tms.tm_isdst = -1;
+         timeoffset = (int)difftime(t, mktime(&tms)); /* tz+dst in seconds */
+@@ -437,7 +439,7 @@ pdf_compute_fileID(gx_device_pdf * pdev)
+     if (s == NULL)
+         return_error(gs_error_VMerror);
+     pdev->KeyLength = 0; /* Disable encryption. Not so important though. */
+-    gp_get_usertime(secs_ns);
++    gp_get_realtime(secs_ns);
+     sputs(s, (byte *)secs_ns, sizeof(secs_ns), &ignore);
+     sputs(s, (const byte *)pdev->fname, strlen(pdev->fname), &ignore);
+     pdev->strm = s;
+Index: ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpdfe.c
+===================================================================
+--- ghostscript-9.15~dfsg-1.0~reproducible1.orig/devices/vector/gdevpdfe.c
++++ ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpdfe.c
+@@ -200,10 +200,12 @@ pdf_xmp_time(char *buf, int buf_length)
+ {
+     /* We don't write a day time because we don't have a time zone. */
+     struct tm tms;
++    long secs_ns[2];
+     time_t t;
+     char buf1[4+1+2+1+2+1]; /* yyyy-mm-dd\0 */
+ 
+-    time(&t);
++    gp_get_realtime(secs_ns);
++    t = secs_ns[0];
+     tms = *localtime(&t);
+     gs_sprintf(buf1,
+             "%04d-%02d-%02d",
+Index: ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpsu.c
+===================================================================
+--- ghostscript-9.15~dfsg-1.0~reproducible1.orig/devices/vector/gdevpsu.c
++++ ghostscript-9.15~dfsg-1.0~reproducible1/devices/vector/gdevpsu.c
+@@ -183,10 +183,12 @@ psw_begin_file_header(FILE *f, const gx_
+     fprintf(f, "%%%%Creator: %s %ld (%s)\n", gs_product, (long)gs_revision,
+             dev->dname);
+     {
++        long secs_ns[2];
+         time_t t;
+         struct tm tms;
+ 
+-        time(&t);
++        gp_get_realtime(secs_ns);
++        t = secs_ns[0];
+         tms = *localtime(&t);
+         fprintf(f, "%%%%CreationDate: %d/%02d/%02d %02d:%02d:%02d\n",
+                 tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
diff -Nru ghostscript-9.15~dfsg/debian/patches/series 
ghostscript-9.15~dfsg/debian/patches/series
--- ghostscript-9.15~dfsg/debian/patches/series 2015-07-26 12:00:49.000000000 
+0200
+++ ghostscript-9.15~dfsg/debian/patches/series 2015-07-28 16:32:03.000000000 
+0200
@@ -9,3 +9,4 @@
 2007_suggest_install_ghostscript-doc_in_code.patch
 2008_mention_ghostscript-x_in_docs.patch
 2009_avoid_ramfs.patch
+2010_add_build_timestamp_setting.patch

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
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