Imported Upstream version 2.13.1
[platform/upstream/fontconfig.git] / src / fccache.c
index 7abb750..2b60401 100644 (file)
@@ -51,13 +51,23 @@ FcDirCacheCreateUUID (FcChar8  *dir,
                      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)
     {
@@ -69,7 +79,7 @@ FcDirCacheCreateUUID (FcChar8  *dir,
        struct stat statb;
        struct timeval times[2];
 
-       if (FcStat (dir, &statb) != 0)
+       if (FcStat (target, &statb) != 0)
        {
            ret = FcFalse;
            goto bail1;
@@ -96,9 +106,11 @@ FcDirCacheCreateUUID (FcChar8  *dir,
            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);
@@ -124,19 +136,40 @@ FcDirCacheCreateUUID (FcChar8  *dir,
            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,
@@ -144,25 +177,35 @@ 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);
@@ -176,6 +219,7 @@ FcDirCacheReadUUID (FcChar8  *dir,
     }
     else
        FcHashUuidFree (u);
+    FcStrFree (target);
 }
 #endif
 
@@ -259,19 +303,22 @@ static FcChar8 *
 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
@@ -303,6 +350,7 @@ FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config)
         if (!cache_hashed)
            break;
        (void) unlink ((char *) cache_hashed);
+       FcDirCacheDeleteUUID (dir, config);
        FcStrFree (cache_hashed);
     }
     FcStrListDone (list);
@@ -417,6 +465,7 @@ struct _FcCacheSkip {
     FcCache        *cache;
     FcRef          ref;
     intptr_t       size;
+    void          *allocated;
     dev_t          cache_dev;
     ino_t          cache_ino;
     time_t         cache_mtime;
@@ -542,6 +591,7 @@ FcCacheInsert (FcCache *cache, struct stat *cache_stat)
 
     s->cache = cache;
     s->size = cache->size;
+    s->allocated = NULL;
     FcRefInit (&s->ref, 1);
     if (cache_stat)
     {
@@ -616,6 +666,7 @@ FcCacheRemoveUnlocked (FcCache *cache)
     FcCacheSkip            **update[FC_CACHE_MAX_LEVEL];
     FcCacheSkip            *s, **next;
     int                    i;
+    void            *allocated;
 
     /*
      * Find links along each chain
@@ -633,6 +684,15 @@ FcCacheRemoveUnlocked (FcCache *cache)
        *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);
 }
 
@@ -648,7 +708,7 @@ FcCacheFindByStat (struct stat *cache_stat)
            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);
@@ -702,6 +762,30 @@ FcCacheObjectDereference (void *object)
     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)
 {
@@ -795,7 +879,7 @@ FcCacheOffsetsValid (FcCache *cache)
         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++)
@@ -955,7 +1039,6 @@ FcCache *
 FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
 {
     FcCache *cache = NULL;
-    const FcChar8 *d;
 
 #ifndef _WIN32
     FcDirCacheReadUUID ((FcChar8 *) dir, config);
@@ -965,10 +1048,6 @@ FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
                            &cache, cache_file))
        return NULL;
 
-    d = FcCacheDir (cache);
-    if (FcStrCmp (dir, d))
-       FcHashTableAdd (config->alias_table, (FcChar8 *) d, (FcChar8 *) dir);
-
     return cache;
 }
 
@@ -989,6 +1068,55 @@ 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_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
@@ -1007,10 +1135,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 +1214,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
@@ -1225,9 +1351,9 @@ FcDirCacheWrite (FcCache *cache, FcConfig *config)
 #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",