Source: ghostscript Version: 9.15~dfsg-1 Severity: wishlist Tags: patch User: reproducible-bui...@lists.alioth.debian.org Usertags: toolchain timestamps X-Debbugs-Cc: reproducible-bui...@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
signature.asc
Description: OpenPGP digital signature