Commit dc4a78d3 authored by Chris Lamb's avatar Chris Lamb Committed by Federico Mena Quintero

Make PDF output reproducible if the SOURCE_DATE_EPOCH envvar is set

Whilst working on the Reproducible Builds effort [0], we noticed
that rsvg-convert does not create reproducible output.

This is because it calls cairo_pdf_surface_create_for_stream
without setting a modification time, thus leading to the current
date always being generated.

An alternative patch *could* use the creation time of the input
file, but this would be misleading metadata when applied to the
output - it was not created at the same time as the input.

This has also been filed in Debian [1].

 [0] https://reproducible-builds.org/
 [1] https://bugs.debian.org/890027Signed-off-by: Chris Lamb's avatarChris Lamb <chris@chris-lamb.co.uk>
parent 6dbc5700
......@@ -41,7 +41,7 @@ dnl ===========================================================================
GLIB_REQUIRED=2.52.0
GIO_REQUIRED=2.24.0
LIBXML_REQUIRED=2.9.0
CAIRO_REQUIRED=1.2.0
CAIRO_REQUIRED=1.15.4
PANGO_REQUIRED=1.38.0
GDK_PIXBUF_REQUIRED=2.20
GTK3_REQUIRED=3.10.0
......
......@@ -30,9 +30,11 @@
#include "config.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <locale.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
......@@ -143,6 +145,13 @@ main (int argc, char **argv)
double unscaled_width, unscaled_height;
int scaled_width, scaled_height;
char buffer[25];
char *endptr;
char *source_date_epoch;
time_t now;
struct tm *build_time;
unsigned long long epoch;
#ifdef G_OS_WIN32
HANDLE handle;
#endif
......@@ -349,9 +358,42 @@ main (int argc, char **argv)
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
scaled_width, scaled_height);
#ifdef CAIRO_HAS_PDF_SURFACE
else if (!strcmp (format, "pdf"))
else if (!strcmp (format, "pdf")) {
surface = cairo_pdf_surface_create_for_stream (rsvg_cairo_write_func, output_file,
scaled_width, scaled_height);
source_date_epoch = getenv("SOURCE_DATE_EPOCH");
if (source_date_epoch) {
errno = 0;
epoch = strtoull(source_date_epoch, &endptr, 10);
if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0))
|| (errno != 0 && epoch == 0)) {
g_printerr (_("Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n"),
strerror(errno));
exit (1);
}
if (endptr == source_date_epoch) {
g_printerr (_("Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n"),
endptr);
exit (1);
}
if (*endptr != '\0') {
g_printerr (_("Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n"),
endptr);
exit (1);
}
if (epoch > ULONG_MAX) {
g_printerr (_("Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to %lu but was found to be: %llu \n"),
ULONG_MAX, epoch);
exit (1);
}
now = (time_t) epoch;
build_time = gmtime(&now);
g_assert (strftime (buffer, sizeof (buffer), "%Y-%m-%dT%H:%M:%S%z", build_time));
cairo_pdf_surface_set_metadata (surface,
CAIRO_PDF_METADATA_CREATE_DATE,
buffer);
}
}
#endif
#ifdef CAIRO_HAS_PS_SURFACE
else if (!strcmp (format, "ps") || !strcmp (format, "eps")){
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment