FcBool force,
FcConfig *config)
{
+ const FcChar8 *sysroot = FcConfigGetSysRoot (config);
+ FcChar8 *target;
FcBool ret = FcTrue;
#ifndef _WIN32
FcChar8 *uuidname;
- uuidname = FcStrBuildFilename (dir, ".uuid", NULL);
+ if (sysroot)
+ target = FcStrBuildFilename (sysroot, dir, NULL);
+ else
+ target = FcStrdup (dir);
+ uuidname = FcStrBuildFilename (target, ".uuid", NULL);
+
if (!uuidname)
+ {
+ FcStrFree (target);
return FcFalse;
+ }
if (force || access ((const char *) uuidname, F_OK) < 0)
{
struct stat statb;
struct timeval times[2];
- if (FcStat (dir, &statb) != 0)
+ if (FcStat (target, &statb) != 0)
{
ret = FcFalse;
goto bail1;
hash_add = FcHashTableReplace;
else
hash_add = FcHashTableAdd;
- if (!hash_add (config->uuid_table, dir, uuid))
+ if (!hash_add (config->uuid_table, target, uuid))
{
ret = FcFalse;
+ FcAtomicDeleteNew (atomic);
+ close (fd);
goto bail3;
}
uuid_unparse (uuid, out);
times[0].tv_usec = 0;
times[1].tv_usec = 0;
#endif
- if (utimes ((const char *) dir, times) != 0)
+ if (utimes ((const char *) target, times) != 0)
{
- fprintf (stderr, "Unable to revert mtime: %s\n", dir);
+ fprintf (stderr, "Unable to revert mtime: %s\n", target);
}
}
}
- bail1:
+bail1:
FcStrFree (uuidname);
+ FcStrFree (target);
#endif
return ret;
}
+FcBool
+FcDirCacheDeleteUUID (const FcChar8 *dir,
+ FcConfig *config)
+{
+ const FcChar8 *sysroot = FcConfigGetSysRoot (config);
+ FcChar8 *target;
+ FcBool ret = FcTrue;
+
+ if (sysroot)
+ target = FcStrBuildFilename (sysroot, dir, ".uuid", NULL);
+ else
+ target = FcStrBuildFilename (dir, ".uuid", NULL);
+
+ ret = unlink ((char *) target) == 0;
+ FcHashTableRemove (config->uuid_table, target);
+ FcStrFree(target);
+
+ return ret;
+}
+
#ifndef _WIN32
static void
FcDirCacheReadUUID (FcChar8 *dir,
{
void *u;
uuid_t uuid;
+ const FcChar8 *sysroot = FcConfigGetSysRoot (config);
+ FcChar8 *target;
- if (!FcHashTableFind (config->uuid_table, dir, &u))
+ if (sysroot)
+ target = FcStrBuildFilename (sysroot, dir, NULL);
+ else
+ target = FcStrdup (dir);
+
+ if (!FcHashTableFind (config->uuid_table, target, &u))
{
- FcChar8 *uuidname = FcStrBuildFilename (dir, ".uuid", NULL);
+ FcChar8 *uuidname = FcStrBuildFilename (target, ".uuid", NULL);
int fd;
if ((fd = FcOpen ((char *) uuidname, O_RDONLY)) >= 0)
{
char suuid[37];
+ ssize_t len;
memset (suuid, 0, sizeof (suuid));
- if (read (fd, suuid, 36) > 0)
+ len = read (fd, suuid, 36);
+ if (len != -1)
{
+ suuid[len] = 0;
memset (uuid, 0, sizeof (uuid));
if (uuid_parse (suuid, uuid) == 0)
{
if (FcDebug () & FC_DBG_CACHE)
printf ("FcDirCacheReadUUID %s -> %s\n", uuidname, suuid);
- FcHashTableAdd (config->uuid_table, dir, uuid);
+ FcHashTableAdd (config->uuid_table, target, uuid);
}
}
close (fd);
}
else
FcHashUuidFree (u);
+ FcStrFree (target);
}
#endif
FcDirCacheBasenameUUID (const FcChar8 *dir, FcChar8 cache_base[CACHEBASE_LEN], FcConfig *config)
{
void *u;
- FcChar8 *alias;
+ FcChar8 *target;
+ const FcChar8 *sysroot = FcConfigGetSysRoot (config);
- if (!FcHashTableFind (config->alias_table, dir, (void **)&alias))
- alias = FcStrdup (dir);
- if (FcHashTableFind (config->uuid_table, alias, &u))
+ if (sysroot)
+ target = FcStrBuildFilename (sysroot, dir, NULL);
+ else
+ target = FcStrdup (dir);
+ if (FcHashTableFind (config->uuid_table, target, &u))
{
uuid_unparse (u, (char *) cache_base);
strcat ((char *) cache_base, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX);
FcHashUuidFree (u);
- FcStrFree (alias);
+ FcStrFree (target);
return cache_base;
}
- FcStrFree (alias);
+ FcStrFree (target);
return NULL;
}
#endif
if (!cache_hashed)
break;
(void) unlink ((char *) cache_hashed);
+ FcDirCacheDeleteUUID (dir, config);
FcStrFree (cache_hashed);
}
FcStrListDone (list);
FcCache *cache;
FcRef ref;
intptr_t size;
+ void *allocated;
dev_t cache_dev;
ino_t cache_ino;
time_t cache_mtime;
s->cache = cache;
s->size = cache->size;
+ s->allocated = NULL;
FcRefInit (&s->ref, 1);
if (cache_stat)
{
FcCacheSkip **update[FC_CACHE_MAX_LEVEL];
FcCacheSkip *s, **next;
int i;
+ void *allocated;
/*
* Find links along each chain
*update[i] = s->next[i];
while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL)
fcCacheMaxLevel--;
+
+ allocated = s->allocated;
+ while (allocated)
+ {
+ /* First element in allocated chunk is the free list */
+ next = *(void **)allocated;
+ free (allocated);
+ allocated = next;
+ }
free (s);
}
s->cache_mtime == cache_stat->st_mtime)
{
#ifdef HAVE_STRUCT_STAT_ST_MTIM
- if (s->cache_mtime != cache_stat->st_mtim.tv_nsec)
+ if (s->cache_mtime_nano != cache_stat->st_mtim.tv_nsec)
continue;
#endif
FcRefInc (&s->ref);
unlock_cache ();
}
+void *
+FcCacheAllocate (FcCache *cache, size_t len)
+{
+ FcCacheSkip *skip;
+ void *allocated = NULL;
+
+ lock_cache ();
+ skip = FcCacheFindByAddrUnlocked (cache);
+ if (skip)
+ {
+ void *chunk = malloc (sizeof (void *) + len);
+ if (chunk)
+ {
+ /* First element in allocated chunk is the free list */
+ *(void **)chunk = skip->allocated;
+ skip->allocated = chunk;
+ /* Return the rest */
+ allocated = ((FcChar8 *)chunk) + sizeof (void *);
+ }
+ }
+ unlock_cache ();
+ return allocated;
+}
+
void
FcCacheFini (void)
{
if (fs->nfont > (end - (char *) fs) / sizeof (FcPattern))
return FcFalse;
- if (fs->fonts != 0 && !FcIsEncodedOffset(fs->fonts))
+ if (!FcIsEncodedOffset(fs->fonts))
return FcFalse;
for (i = 0; i < fs->nfont; i++)
FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
{
FcCache *cache = NULL;
- const FcChar8 *d;
#ifndef _WIN32
FcDirCacheReadUUID ((FcChar8 *) dir, config);
&cache, cache_file))
return NULL;
- d = FcCacheDir (cache);
- if (FcStrCmp (dir, d))
- FcHashTableAdd (config->alias_table, (FcChar8 *) d, (FcChar8 *) dir);
-
return cache;
}
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_EPOCH 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)
+{
+#ifdef HAVE_STRUCT_STAT_ST_MTIM
+ /* No nanosecond component to parse */
+ if (getenv("SOURCE_DATE_EPOCH"))
+ return 0;
+ return statb->st_mtim.tv_nsec;
+#else
+ return 0;
+#endif
+}
+
/*
* Validate a cache file by reading the header and checking
* the magic number and the size field
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;
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
#endif
FcDirCacheBasenameMD5 (dir, cache_base);
cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL);
+ FcStrFree (cache_dir);
if (!cache_hashed)
return FcFalse;
- FcStrFree (cache_dir);
if (FcDebug () & FC_DBG_CACHE)
printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n",