Re: [PATCH] Please make the output of cache files reproducible

Chris Lamb <[email protected]>
Newsgroups gmane.comp.fonts.fontconfig
Message-ID <1525534754.533462.1361907504.765B2699@webmail.messagingengine.com>
Akira TAGOH wrote:

> How about creating your tool with FcConfigGetFontDirs()? I don't get why
> fc-cache needs to have such options. fc-cache isn't an interface to make
> the config readable.

Good point. Updated patch attached. :)


Best wishes,

-- 
      ,''`.
     : :'  :     Chris Lamb
     `. `'`      [email protected] / chris-lamb.co.uk
       `-

_______________________________________________
Fontconfig mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/fontconfig
0001-Ensure-cache-checksums-are-determinstic.patch (text/x-patch, 3.8 KB)
From ccc5da9ed364df1334a3ff172d89f852d199955b Mon Sep 17 00:00:00 2001
From: Chris Lamb <[email protected]>
Date: Sat, 28 Apr 2018 12:21:24 -0700
Subject: [PATCH] Ensure cache checksums are determinstic

Whilst working on the Reproducible Builds[0] effort, we noticed that
fontconfig generates unreproducible cache files.

This is due to fc-cache uses the modification timestamps of each
directory in the "checksum" and "checksum_nano" members of the _FcCache
struct. This is so that it can identify which cache files are valid
and/or require regeneration.

This patch changes the behaviour of the checksum calculations to prefer
the value of the SOURCE_DATE_EPOCH[1] environment variable over the
directory's own mtime. This variable can then be exported by build
systems to ensure reproducible output.

If SOURCE_DATE_EPOCH is not set or is newer than the mtime of the
directory, the existing behaviour is unchanged.

This work was sponsored by Tails[2].

 [0] https://reproducible-builds.org/
 [1] https://reproducible-builds.org/specs/source-date-epoch/
 [2] https://tails.boum.org/
---
 src/fccache.c | 55 +++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 49 insertions(+), 6 deletions(-)

diff --git a/src/fccache.c b/src/fccache.c
index 7abb750..e74d902 100644
--- a/src/fccache.c
+++ b/src/fccache.c
@@ -989,6 +989,51 @@ FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
     return cache;
 }
 
+static int
+FcDirChecksum (struct stat *statb) {
+    int			ret = (int) statb->st_mtime;
+    char		*endptr;
+    char		*source_date_epoch;
+    unsigned long long	epoch;
+
+    source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+    if (source_date_epoch) {
+	epoch = strtoull(source_date_epoch, &endptr, 10);
+
+	if (endptr == source_date_epoch)
+	    fprintf (stderr,
+		     "Fontconfig: SOURCE_DATE_EPOCH invalid\n");
+	else if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0))
+		|| (errno != 0 && epoch == 0))
+	    fprintf (stderr,
+		     "Fontconfig: SOURCE_DATE_EPOCH: strtoull: %s: %llu\n",
+		     strerror(errno), epoch);
+	else if (*endptr != '\0')
+	    fprintf (stderr,
+		     "Fontconfig: SOURCE_DATE_EPOCHh has trailing garbage\n");
+	else if (epoch > ULONG_MAX)
+	    fprintf (stderr,
+		     "Fontconfig: SOURCE_DATE_EPOCH must be <= %lu but saw: %llu\n",
+		     ULONG_MAX, epoch);
+	else if (epoch < ret)
+	    /* Only override if directory is newer */
+	    ret = (int) epoch;
+    }
+
+    return ret;
+}
+
+static int64_t
+FcDirChecksumNano (struct stat *statb) {
+    /* No nanosecond component to parse */
+    if (getenv("SOURCE_DATE_EPOCH"))
+	return 0;
+#ifdef HAVE_STRUCT_STAT_ST_MTIM
+    return statb->st_mtim.tv_nsec;
+#endif
+    return 0;
+}
+
 /*
  * Validate a cache file by reading the header and checking
  * the magic number and the size field
@@ -1007,10 +1052,10 @@ FcDirCacheValidateHelper (FcConfig *config, int fd, struct stat *fd_stat, struct
 	ret = FcFalse;
     else if (fd_stat->st_size != c.size)
 	ret = FcFalse;
-    else if (c.checksum != (int) dir_stat->st_mtime)
+    else if (c.checksum != FcDirChecksum(dir_stat))
 	ret = FcFalse;
 #ifdef HAVE_STRUCT_STAT_ST_MTIM
-    else if (c.checksum_nano != dir_stat->st_mtim.tv_nsec)
+    else if (c.checksum_nano != FcDirChecksumNano(dir_stat))
 	ret = FcFalse;
 #endif
     return ret;
@@ -1086,10 +1131,8 @@ FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcSt
     cache->magic = FC_CACHE_MAGIC_ALLOC;
     cache->version = FC_CACHE_VERSION_NUMBER;
     cache->size = serialize->size;
-    cache->checksum = (int) dir_stat->st_mtime;
-#ifdef HAVE_STRUCT_STAT_ST_MTIM
-    cache->checksum_nano = dir_stat->st_mtim.tv_nsec;
-#endif
+    cache->checksum = FcDirChecksum(dir_stat);
+    cache->checksum_nano = FcDirChecksumNano(dir_stat);
 
     /*
      * Serialize directory name
-- 
2.17.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.