]> git.wh0rd.org - fontconfig.git/commitdiff
Skip broken caches. Cache files are auto-written, don't rewrite in fc-cache.
authorKeith Packard <keithp@neko.keithp.com>
Thu, 31 Aug 2006 04:59:53 +0000 (21:59 -0700)
committerKeith Packard <keithp@neko.keithp.com>
Thu, 31 Aug 2006 04:59:53 +0000 (21:59 -0700)
Validate cache contents and skip broken caches, looking down cache path for
valid ones.

Every time a directory is scanned, it will be written to a cache file if
possible, so fc-cache doesn't need to re-write the cache file. This makes
detecting when the cache was generated a bit tricky, so we guess that if the
cache wasn't valid before running and is valid afterwards, the cache file
was written.

Also, allow empty charsets to be serialized with null leaves/numbers.

Eliminate a leak in FcEdit by switching to FcObject sooner.

Call FcFini from fc-match to make valgrind happy.

fc-cache/fc-cache.c
fc-match/fc-match.c
src/fccache.c
src/fccfg.c
src/fccharset.c
src/fcdir.c
src/fcint.h
src/fcxml.c

index 134d33dbb8d3244e33c8ce0fe931708738206ed4..9df90ccea2f0814836097a0abbde58ccdc172e0e 100644 (file)
@@ -130,6 +130,7 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
     FcStrSet   *subdirs;
     FcStrList  *sublist;
     struct stat        statb;
+    FcBool     was_valid;
     
     /*
      * Now scan all of the directories into separate databases
@@ -160,14 +161,14 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
        set = FcFontSetCreate ();
        if (!set)
        {
-           fprintf (stderr, "Can't create font set\n");
+           fprintf (stderr, "%s: Can't create font set\n", dir);
            ret++;
            continue;
        }
        subdirs = FcStrSetCreate ();
        if (!subdirs)
        {
-           fprintf (stderr, "Can't create directory set\n");
+           fprintf (stderr, "%s: Can't create directory set\n", dir);
            ret++;
            FcFontSetDestroy (set);
            continue;
@@ -219,15 +220,18 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
        if (really_force)
            FcDirCacheUnlink (dir, config);
 
+       if (!force)
+           was_valid = FcDirCacheValid (dir, config);
+       
        if (!FcDirScanConfig (set, subdirs, FcConfigGetBlanks (config), dir, force, config))
        {
-           fprintf (stderr, "\"%s\": error scanning\n", dir);
+           fprintf (stderr, "%s: error scanning\n", dir);
            FcFontSetDestroy (set);
            FcStrSetDestroy (subdirs);
            ret++;
            continue;
        }
-       if (!force && FcDirCacheValid (dir, config))
+       if (!force && was_valid)
        {
            if (verbose)
                printf ("skipping, %d fonts, %d dirs\n",
@@ -239,15 +243,10 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
                printf ("caching, %d fonts, %d dirs\n", 
                        set->nfont, nsubdirs (subdirs));
 
-           /* This is the only reason we can't combine 
-            * Valid w/HasCurrentArch... */
-            if (!FcDirCacheValid (dir, config))
-                if (!FcDirCacheUnlink (dir, config))
-                    ret++;
-
-           if (!FcDirSave (set, subdirs, dir))
+           if (!FcDirCacheValid (dir, config))
            {
-               fprintf (stderr, "Can't save cache for \"%s\"\n", dir);
+               fprintf (stderr, "%s: failed to write cache\n", dir);
+               (void) FcDirCacheUnlink (dir, config);
                ret++;
            }
        }
@@ -256,7 +255,7 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
        FcStrSetDestroy (subdirs);
        if (!sublist)
        {
-           fprintf (stderr, "Can't create subdir list in \"%s\"\n", dir);
+           fprintf (stderr, "%s: Can't create subdir list\n", dir);
            ret++;
            continue;
        }
index d9742c97ea22298e1ab3103b28fbc4b68f549ab5..5f36f004fd0abeca1e97982e0a9d4ac038b60ecf 100644 (file)
@@ -187,5 +187,6 @@ main (int argc, char **argv)
        }
        FcFontSetDestroy (fs);
     }
+    FcFini ();
     return 0;
 }
index 9f35f297820025107daa6fe4894f3dd9198221a8..1411766fadcfec7e60c51ce1e875eb98fdb615af 100644 (file)
@@ -39,9 +39,6 @@
 #define O_BINARY 0
 #endif
 
-static int
-FcDirCacheOpen (FcConfig *config, const FcChar8 *dir, off_t *size);
-
 struct MD5Context {
         FcChar32 buf[4];
         FcChar32 bits[2];
@@ -53,23 +50,6 @@ static void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len);
 static void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
 static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]);
 
-#define FC_DBG_CACHE_REF    1024
-
-/* Does not check that the cache has the appropriate arch section. */
-FcBool
-FcDirCacheValid (const FcChar8 *dir, FcConfig *config)
-{
-    int fd;
-
-    fd = FcDirCacheOpen (config, dir, NULL);
-
-    if (fd < 0)
-       return FcFalse;
-    close (fd);
-
-    return FcTrue;
-}
-
 #define CACHEBASE_LEN (1 + 32 + 1 + sizeof (FC_ARCHITECTURE) + sizeof (FC_CACHE_SUFFIX))
 
 static const char bin2hex[] = { '0', '1', '2', '3',
@@ -209,27 +189,31 @@ FcCacheRead (FcConfig *config)
     return 0;
 }
 
-/* Opens the cache file for 'dir' for reading.
- * This searches the list of cache dirs for the relevant cache file,
- * returning the first one found.
+/* 
+ * Look for a cache file for the specified dir. Attempt
+ * to use each one we find, stopping when the callback
+ * indicates success
  */
-static int
-FcDirCacheOpen (FcConfig *config, const FcChar8 *dir, off_t *size)
+static FcBool
+FcDirCacheProcess (FcConfig *config, const FcChar8 *dir, 
+                  FcBool (*callback) (int fd, off_t size, void *closure),
+                  void *closure)
 {
     int                fd = -1;
     FcChar8    cache_base[CACHEBASE_LEN];
     FcStrList  *list;
     FcChar8    *cache_dir;
     struct stat file_stat, dir_stat;
+    FcBool     ret = FcFalse;
 
     if (stat ((char *) dir, &dir_stat) < 0)
-        return -1;
+        return FcFalse;
 
     FcDirCacheBasename (dir, cache_base);
 
     list = FcStrListCreate (config->cacheDirs);
     if (!list)
-        return -1;
+        return FcFalse;
        
     while ((cache_dir = FcStrListNext (list)))
     {
@@ -242,43 +226,29 @@ FcDirCacheOpen (FcConfig *config, const FcChar8 *dir, off_t *size)
            if (fstat (fd, &file_stat) >= 0 &&
                dir_stat.st_mtime <= file_stat.st_mtime)
            {
-               if (size)
-                   *size = file_stat.st_size;
-               break;
+               ret = (*callback) (fd, file_stat.st_size, closure);
+               if (ret)
+               {
+                   close (fd);
+                   break;
+               }
            }
            close (fd);
-           fd = -1;
        }
     }
     FcStrListDone (list);
     
-    return fd;
-}
-
-void
-FcDirCacheUnmap (FcCache *cache)
-{
-    if (cache->magic == FC_CACHE_MAGIC_COPY)
-    {
-       free (cache);
-       return;
-    }
-#if defined(HAVE_MMAP) || defined(__CYGWIN__)
-    munmap (cache, cache->size);
-#elif defined(_WIN32)
-    UnmapViewOfFile (cache);
-#endif
+    return ret;
 }
 
-/* read serialized state from the cache file */
-FcCache *
-FcDirCacheMap (int fd, off_t size)
+static FcBool
+FcDirCacheLoad (int fd, off_t size, void *closure)
 {
     FcCache    *cache;
     FcBool     allocated = FcFalse;
 
     if (size < sizeof (FcCache))
-       return NULL;
+       return FcFalse;
 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
     cache = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0);
 #elif defined(_WIN32)
@@ -299,12 +269,12 @@ FcDirCacheMap (int fd, off_t size)
     {
        cache = malloc (size);
        if (!cache)
-           return NULL;
+           return FcFalse;
 
        if (read (fd, cache, size) != size)
        {
            free (cache);
-           return NULL;
+           return FcFalse;
        }
        allocated = FcTrue;
     } 
@@ -321,41 +291,41 @@ FcDirCacheMap (int fd, off_t size)
            UnmapViewOfFile (cache);
 #endif
        }
-       return NULL;
+       return FcFalse;
     }
 
     /* Mark allocated caches so they're freed rather than unmapped */
     if (allocated)
        cache->magic = FC_CACHE_MAGIC_COPY;
        
-    return cache;
+    *((FcCache **) closure) = cache;
+    return FcTrue;
+}
+
+FcCache *
+FcDirCacheMap (int fd, off_t size)
+{
+    FcCache *cache;
+
+    if (FcDirCacheLoad (fd, size, &cache))
+       return cache;
+    return NULL;
 }
 
 FcBool
 FcDirCacheRead (FcFontSet * set, FcStrSet * dirs, 
                const FcChar8 *dir, FcConfig *config)
 {
-    int                fd;
     FcCache    *cache;
-    off_t      size;
     int                i;
     FcFontSet  *cache_set;
     intptr_t   *cache_dirs;
     FcPattern   **cache_fonts;
 
-    fd = FcDirCacheOpen (config, dir, &size);
-    if (fd < 0)
+    if (!FcDirCacheProcess (config, dir, 
+                           FcDirCacheLoad,
+                           &cache))
        return FcFalse;
-
-    cache = FcDirCacheMap (fd, size);
-    
-    if (!cache)
-    {
-       if (FcDebug() & FC_DBG_CACHE)
-           printf ("FcDirCacheRead failed to map cache for %s\n", dir);
-       close (fd);
-       return FcFalse;
-    }
     
     cache_set = FcCacheSet (cache);
     cache_fonts = FcFontSetFonts(cache_set);
@@ -383,10 +353,48 @@ FcDirCacheRead (FcFontSet * set, FcStrSet * dirs,
     if (config)
        FcConfigAddFontDir (config, (FcChar8 *)dir);
     
-    close (fd);
     return FcTrue;
 }
     
+static FcBool
+FcDirCacheValidate (int fd, off_t size, void *closure)
+{
+    FcBool  ret = FcTrue;
+    FcCache    c;
+    struct stat        file_stat;
+    
+    if (read (fd, &c, sizeof (FcCache)) != sizeof (FcCache))
+       ret = FcFalse;
+    else if (fstat (fd, &file_stat) < 0)
+       ret = FcFalse;
+    else if (c.magic != FC_CACHE_MAGIC)
+       ret = FcFalse;
+    else if (file_stat.st_size != c.size)
+       ret = FcFalse;
+    return ret;
+}
+
+FcBool
+FcDirCacheValid (const FcChar8 *dir, FcConfig *config)
+{
+    return FcDirCacheProcess (config, dir, FcDirCacheValidate, NULL);
+}
+
+void
+FcDirCacheUnmap (FcCache *cache)
+{
+    if (cache->magic == FC_CACHE_MAGIC_COPY)
+    {
+       free (cache);
+       return;
+    }
+#if defined(HAVE_MMAP) || defined(__CYGWIN__)
+    munmap (cache, cache->size);
+#elif defined(_WIN32)
+    UnmapViewOfFile (cache);
+#endif
+}
+
 /*
  * Cache file is:
  *
index 4377ce61a3f2685c0d2d1f22c7f796af69c006e3..bcc3bd28d5525839c600b574beace725967648b9 100644 (file)
@@ -77,39 +77,9 @@ FcConfigCreate (void)
     if (!config->rejectPatterns)
        goto bail7;
 
-    config->cache = 0;
-    if (FcConfigHome())
-       if (!FcConfigSetCache (config, (FcChar8 *) ("~/" FC_USER_CACHE_FILE)))
-           goto bail8;
-
-#ifdef _WIN32
-    if (config->cache == 0)
-    {
-       /* If no home, use the temp folder. */
-       FcChar8     dummy[1];
-       int         templen = GetTempPath (1, dummy);
-       FcChar8     *temp = malloc (templen + 1);
-
-       if (temp)
-       {
-           FcChar8 *cache_dir;
-
-           GetTempPath (templen + 1, temp);
-           cache_dir = FcStrPlus (temp, FC_USER_CACHE_FILE);
-           free (temp);
-           if (!FcConfigSetCache (config, cache_dir))
-           {
-               FcStrFree (cache_dir);
-               goto bail8;
-           }
-           FcStrFree (cache_dir);
-       }
-    }
-#endif
-
     config->cacheDirs = FcStrSetCreate ();
     if (!config->cacheDirs)
-       goto bail9;
+       goto bail8;
     
     config->blanks = 0;
 
@@ -119,13 +89,13 @@ FcConfigCreate (void)
     for (set = FcSetSystem; set <= FcSetApplication; set++)
        config->fonts[set] = 0;
 
+    config->caches = NULL;
+
     config->rescanTime = time(0);
     config->rescanInterval = 30;    
     
     return config;
 
-bail9:
-    FcStrFree (config->cache);
 bail8:
     FcFontSetDestroy (config->rejectPatterns);
 bail7:
@@ -226,6 +196,7 @@ void
 FcConfigDestroy (FcConfig *config)
 {
     FcSetName  set;
+    FcCacheList        *cl, *cl_next;
 
     if (config == _fcConfig)
        _fcConfig = 0;
@@ -242,15 +213,19 @@ FcConfigDestroy (FcConfig *config)
     if (config->blanks)
        FcBlanksDestroy (config->blanks);
 
-    if (config->cache)
-       FcStrFree (config->cache);
-
     FcSubstDestroy (config->substPattern);
     FcSubstDestroy (config->substFont);
     for (set = FcSetSystem; set <= FcSetApplication; set++)
        if (config->fonts[set])
            FcFontSetDestroy (config->fonts[set]);
 
+    for (cl = config->caches; cl; cl = cl_next)
+    {
+       cl_next = cl->next;
+       FcDirCacheUnmap (cl->cache);
+       free (cl);
+    }
+
     free (config);
     FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
 }
@@ -453,30 +428,10 @@ FcConfigGetConfigFiles (FcConfig    *config)
     return FcStrListCreate (config->configFiles);
 }
 
-FcBool
-FcConfigSetCache (FcConfig     *config,
-                 const FcChar8 *c)
-{
-    FcChar8    *new = FcStrCopyFilename (c);
-    
-    if (!new)
-       return FcFalse;
-    if (config->cache)
-       FcStrFree (config->cache);
-    config->cache = new;
-    return FcTrue;
-}
-
 FcChar8 *
 FcConfigGetCache (FcConfig  *config)
 {
-    if (!config)
-    {
-       config = FcConfigGetCurrent ();
-       if (!config)
-           return 0;
-    }
-    return config->cache;
+    return NULL;
 }
 
 FcFontSet *
@@ -502,7 +457,18 @@ FcConfigSetFonts (FcConfig *config,
     config->fonts[set] = fonts;
 }
 
+FcBool
+FcConfigAddCache (FcConfig *config, FcCache *cache)
+{
+    FcCacheList        *cl = malloc (sizeof (FcCacheList));
 
+    if (!cl)
+       return FcFalse;
+    cl->cache = cache;
+    cl->next = config->caches;
+    config->caches = cl;
+    return FcTrue;
+}
 
 FcBlanks *
 FcConfigGetBlanks (FcConfig    *config)
index 96dcbe7169e4c545e2f24ecf06631703f3e50c61..3a93c4a96cec00723e6a696a817f3530a2803507 100644 (file)
@@ -1297,32 +1297,40 @@ FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
     cs_serialized->ref = FC_REF_CONSTANT;
     cs_serialized->num = cs->num;
 
-    leaves = FcCharSetLeaves (cs);
-    leaves_serialized = FcSerializePtr (serialize, leaves);
-    if (!leaves_serialized)
-       return NULL;
-
-    cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
-                                                 leaves_serialized);
-    
-    numbers = FcCharSetNumbers (cs);
-    numbers_serialized = FcSerializePtr (serialize, numbers);
-    if (!numbers)
-       return NULL;
-
-    cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
-                                                  numbers_serialized);
-
-    for (i = 0; i < cs->num; i++)
+    if (cs->num)
     {
-       leaf = FcCharSetLeaf (cs, i);
-       leaf_serialized = FcSerializePtr (serialize, leaf);
-       if (!leaf_serialized)
+       leaves = FcCharSetLeaves (cs);
+       leaves_serialized = FcSerializePtr (serialize, leaves);
+       if (!leaves_serialized)
+           return NULL;
+    
+       cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
+                                                     leaves_serialized);
+       
+       numbers = FcCharSetNumbers (cs);
+       numbers_serialized = FcSerializePtr (serialize, numbers);
+       if (!numbers)
            return NULL;
-       *leaf_serialized = *leaf;
-       leaves_serialized[i] = FcPtrToOffset (leaves_serialized, 
-                                             leaf_serialized);
-       numbers_serialized[i] = numbers[i];
+    
+       cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
+                                                      numbers_serialized);
+    
+       for (i = 0; i < cs->num; i++)
+       {
+           leaf = FcCharSetLeaf (cs, i);
+           leaf_serialized = FcSerializePtr (serialize, leaf);
+           if (!leaf_serialized)
+               return NULL;
+           *leaf_serialized = *leaf;
+           leaves_serialized[i] = FcPtrToOffset (leaves_serialized, 
+                                                 leaf_serialized);
+           numbers_serialized[i] = numbers[i];
+       }
+    }
+    else
+    {
+       cs_serialized->leaves_offset = 0;
+       cs_serialized->numbers_offset = 0;
     }
     
     return cs_serialized;
index 013686789a60f8817266a876848ef56db9d9df61..3aeb4c98da80f5a0529262a2628244c864b29e78 100644 (file)
@@ -288,5 +288,5 @@ FcDirScan (FcFontSet            *set,
 FcBool
 FcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir)
 {
-    return FcDirCacheWrite (set, dirs, dir, FcConfigGetCurrent ());
+    return FcFalse;
 }
index c62a5bb370fddf7694e0e3a92d1ed0bce223b255..96de69591f4f548d2562e309457867d2c1e42a0b 100644 (file)
@@ -405,6 +405,11 @@ struct _FcBlanks {
     FcChar32   *blanks;
 };
 
+typedef struct _FcCacheList {
+    struct _FcCacheList *next;
+    FcCache            *cache;
+} FcCacheList;
+
 struct _FcConfig {
     /*
      * File names loaded from the configuration -- saved here as the
@@ -412,7 +417,6 @@ struct _FcConfig {
      * and those directives may occur in any order
      */
     FcStrSet   *configDirs;        /* directories to scan for fonts */
-    FcChar8    *cache;             /* name of per-user cache file */
     /*
      * Set of allowed blank chars -- used to
      * trim fonts of bogus glyphs
@@ -455,6 +459,11 @@ struct _FcConfig {
      * match preferrentially
      */
     FcFontSet  *fonts[FcSetApplication + 1];
+    /*
+     * Font cache information is mapped from cache files
+     * the configuration is destroyed, the files need to be unmapped
+     */
+    FcCacheList        *caches;
     /*
      * Fontconfig can periodically rescan the system configuration
      * and font directories.  This rescanning occurs when font
@@ -525,10 +534,6 @@ FcBool
 FcConfigAddConfigFile (FcConfig                *config,
                       const FcChar8    *f);
 
-FcBool
-FcConfigSetCache (FcConfig     *config,
-                 const FcChar8 *c);
-
 FcBool
 FcConfigAddBlank (FcConfig     *config,
                  FcChar32      blank);
@@ -570,6 +575,10 @@ FcConfigAcceptFont (FcConfig           *config,
 FcFileTime
 FcConfigModifiedTime (FcConfig *config);
 
+FcBool
+FcConfigAddCache (FcConfig *config, FcCache *cache);
+
+/* fcserialize.c */
 intptr_t
 FcAlignSize (intptr_t size);
     
index 608f834b94afe51cc2602f599d3e4f919caa6552..5b7e19118fefb79bb8fb45fa905f8fd4dbbe2bb3 100644 (file)
@@ -668,7 +668,7 @@ FcTestCreate (FcConfigParse *parse,
 
 static FcEdit *
 FcEditCreate (FcConfigParse    *parse,
-             const char        *field,
+             FcObject          object,
              FcOp              op,
              FcExpr            *expr,
              FcValueBinding    binding)
@@ -680,7 +680,7 @@ FcEditCreate (FcConfigParse *parse,
        const FcObjectType      *o;
 
        e->next = 0;
-       e->object = FcObjectFromName (field);
+       e->object = object;
        e->op = op;
        e->expr = expr;
        e->binding = binding;
@@ -1410,7 +1410,7 @@ FcParseAlias (FcConfigParse *parse)
     if (prefer)
     {
        edit = FcEditCreate (parse, 
-                            FcConfigSaveField ("family"),
+                            FC_FAMILY_OBJECT,
                             FcOpPrepend,
                             prefer,
                             FcValueBindingWeak);
@@ -1423,7 +1423,7 @@ FcParseAlias (FcConfigParse *parse)
     {
        next = edit;
        edit = FcEditCreate (parse,
-                            FcConfigSaveField ("family"),
+                            FC_FAMILY_OBJECT,
                             FcOpAppend,
                             accept,
                             FcValueBindingWeak);
@@ -1436,7 +1436,7 @@ FcParseAlias (FcConfigParse *parse)
     {
        next = edit;
        edit = FcEditCreate (parse,
-                            FcConfigSaveField ("family"),
+                            FC_FAMILY_OBJECT,
                             FcOpAppendLast,
                             def,
                             FcValueBindingWeak);
@@ -1791,7 +1791,8 @@ FcParseEdit (FcConfigParse *parse)
        }
     }
     expr = FcPopBinary (parse, FcOpComma);
-    edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
+    edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
+                        mode, expr, binding);
     if (!edit)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -2074,11 +2075,7 @@ FcEndElement(void *userData, const XML_Char *name)
            FcConfigMessage (parse, FcSevereError, "out of memory");
            break;
        }
-       if (!FcStrUsesHome (data) || FcConfigHome ())
-       {
-           if (!FcConfigSetCache (parse->config, data))
-               FcConfigMessage (parse, FcSevereError, "out of memory");
-       }
+       /* discard this data; no longer used */
        FcStrFree (data);
        break;
     case FcElementInclude: