]> git.wh0rd.org - fontconfig.git/blobdiff - src/fccache.c
Don't use X_OK bit when checking for writable directories (bug 12438)
[fontconfig.git] / src / fccache.c
index ba6af72ea880f751f6968968f2b77f08e95dff65..c43609ccdd735f734fb2341cfbca813a8549dbbe 100644 (file)
@@ -47,7 +47,7 @@ struct MD5Context {
 };
 
 static void MD5Init(struct MD5Context *ctx);
-static void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len);
+static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len);
 static void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
 static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]);
 
@@ -67,7 +67,7 @@ FcDirCacheBasename (const FcChar8 * dir, FcChar8 cache_base[CACHEBASE_LEN])
     struct MD5Context  ctx;
 
     MD5Init (&ctx);
-    MD5Update (&ctx, (unsigned char *)dir, strlen ((char *) dir));
+    MD5Update (&ctx, (const unsigned char *)dir, strlen ((const char *) dir));
 
     MD5Final (hash, &ctx);
 
@@ -104,6 +104,7 @@ FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config)
         if (!cache_hashed)
            break;
        (void) unlink ((char *) cache_hashed);
+       FcStrFree (cache_hashed);
     }
     FcStrListDone (list);
     /* return FcFalse if something went wrong */
@@ -135,7 +136,8 @@ FcDirCacheOpenFile (const FcChar8 *cache_file, struct stat *file_stat)
  */
 static FcBool
 FcDirCacheProcess (FcConfig *config, const FcChar8 *dir, 
-                  FcBool (*callback) (int fd, struct stat *stat, void *closure),
+                  FcBool (*callback) (int fd, struct stat *fd_stat,
+                                      struct stat *dir_stat, void *closure),
                   void *closure, FcChar8 **cache_file_ret)
 {
     int                fd = -1;
@@ -161,20 +163,16 @@ FcDirCacheProcess (FcConfig *config, const FcChar8 *dir,
            break;
         fd = FcDirCacheOpenFile (cache_hashed, &file_stat);
         if (fd >= 0) {
-           if (dir_stat.st_mtime <= file_stat.st_mtime)
+           ret = (*callback) (fd, &file_stat, &dir_stat, closure);
+           close (fd);
+           if (ret)
            {
-               ret = (*callback) (fd, &file_stat, closure);
-               if (ret)
-               {
-                   if (cache_file_ret)
-                       *cache_file_ret = cache_hashed;
-                   else
-                       FcStrFree (cache_hashed);
-                   close (fd);
-                   break;
-               }
+               if (cache_file_ret)
+                   *cache_file_ret = cache_hashed;
+               else
+                   FcStrFree (cache_hashed);
+               break;
            }
-           close (fd);
        }
        FcStrFree (cache_hashed);
     }
@@ -424,11 +422,28 @@ FcCacheFini (void)
     assert (fcCacheMaxLevel == 0);
 }
 
+static FcBool
+FcCacheTimeValid (FcCache *cache, struct stat *dir_stat)
+{
+    struct stat        dir_static;
+
+    if (!dir_stat)
+    {
+       if (stat ((const char *) FcCacheDir (cache), &dir_static) < 0)
+           return FcFalse;
+       dir_stat = &dir_static;
+    }
+    if (FcDebug () & FC_DBG_CACHE)
+       printf ("FcCacheTimeValid dir \"%s\" cache time %d dir time %d\n",
+               FcCacheDir (cache), cache->mtime, (int) dir_stat->st_mtime);
+    return cache->mtime == (int) dir_stat->st_mtime;
+}
+
 /*
  * Map a cache file into memory
  */
 static FcCache *
-FcDirCacheMapFd (int fd, struct stat *fd_stat)
+FcDirCacheMapFd (int fd, struct stat *fd_stat, struct stat *dir_stat)
 {
     FcCache    *cache;
     FcBool     allocated = FcFalse;
@@ -439,7 +454,8 @@ FcDirCacheMapFd (int fd, struct stat *fd_stat)
     if (cache)
        return cache;
     /*
-     * For small cache files, just read them into memory
+     * Lage cache files are mmap'ed, smaller cache files are read. This
+     * balances the system cost of mmap against per-process memory usage.
      */
     if (fd_stat->st_size >= FC_CACHE_MIN_MMAP)
     {
@@ -477,7 +493,8 @@ FcDirCacheMapFd (int fd, struct stat *fd_stat)
     if (cache->magic != FC_CACHE_MAGIC_MMAP || 
        cache->version < FC_CACHE_CONTENT_VERSION ||
        cache->size != fd_stat->st_size ||
-       !FcCacheInsert (cache, fd_stat))
+       !FcCacheInsert (cache, fd_stat) ||
+       !FcCacheTimeValid (cache, dir_stat))
     {
        if (allocated)
            free (cache);
@@ -515,9 +532,9 @@ FcDirCacheUnload (FcCache *cache)
 }
 
 static FcBool
-FcDirCacheMapHelper (int fd, struct stat *fd_stat, void *closure)
+FcDirCacheMapHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure)
 {
-    FcCache *cache = FcDirCacheMapFd (fd, fd_stat);
+    FcCache *cache = FcDirCacheMapFd (fd, fd_stat, dir_stat);
 
     if (!cache)
        return FcFalse;
@@ -546,7 +563,7 @@ FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
     fd = FcDirCacheOpenFile (cache_file, file_stat);
     if (fd < 0)
        return NULL;
-    cache = FcDirCacheMapFd (fd, file_stat);
+    cache = FcDirCacheMapFd (fd, file_stat, NULL);
     close (fd);
     return cache;
 }
@@ -556,7 +573,7 @@ FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
  * the magic number and the size field
  */
 static FcBool
-FcDirCacheValidateHelper (int fd, struct stat *fd_stat, void *closure)
+FcDirCacheValidateHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure)
 {
     FcBool  ret = FcTrue;
     FcCache    c;
@@ -569,6 +586,8 @@ FcDirCacheValidateHelper (int fd, struct stat *fd_stat, void *closure)
        ret = FcFalse;
     else if (fd_stat->st_size != c.size)
        ret = FcFalse;
+    else if (c.mtime != (int) dir_stat->st_mtime)
+       ret = FcFalse;
     return ret;
 }
 
@@ -596,7 +615,7 @@ FcDirCacheValid (const FcChar8 *dir)
  * Build a cache structure from the given contents
  */
 FcCache *
-FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, FcStrSet *dirs)
+FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs)
 {
     FcSerialize        *serialize = FcSerializeCreate ();
     FcCache *cache;
@@ -644,6 +663,7 @@ FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, FcStrSet *dirs)
     cache->magic = FC_CACHE_MAGIC_ALLOC;
     cache->version = FC_CACHE_CONTENT_VERSION;
     cache->size = serialize->size;
+    cache->mtime = (int) dir_stat->st_mtime;
 
     /*
      * Serialize directory name
@@ -707,7 +727,7 @@ FcMakeDirectory (const FcChar8 *dir)
     parent = FcStrDirname (dir);
     if (!parent)
        return FcFalse;
-    if (access ((char *) parent, W_OK|X_OK) == 0)
+    if (access ((char *) parent, F_OK) == 0)
        ret = mkdir ((char *) dir, 0777) == 0;
     else if (access ((char *) parent, F_OK) == -1)
        ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0777) == 0);
@@ -740,7 +760,7 @@ FcDirCacheWrite (FcCache *cache, FcConfig *config)
     if (!list)
        return FcFalse;
     while ((test_dir = FcStrListNext (list))) {
-       if (access ((char *) test_dir, W_OK|X_OK) == 0)
+       if (access ((char *) test_dir, W_OK) == 0)
        {
            cache_dir = test_dir;
            break;
@@ -826,16 +846,17 @@ FcDirCacheWrite (FcCache *cache, FcConfig *config)
  * Hokey little macro trick to permit the definitions of C functions
  * with the same name as CPP macros
  */
-#define args(x...)         (x)
+#define args1(x)           (x)
+#define args2(x,y)         (x,y)
 
 const FcChar8 *
-FcCacheDir args(const FcCache *c)
+FcCacheDir args1(const FcCache *c)
 {
     return FcCacheDir (c);
 }
 
 FcFontSet *
-FcCacheCopySet args(const FcCache *c)
+FcCacheCopySet args1(const FcCache *c)
 {
     FcFontSet  *old = FcCacheSet (c);
     FcFontSet  *new = FcFontSetCreate ();
@@ -858,19 +879,19 @@ FcCacheCopySet args(const FcCache *c)
 }
 
 const FcChar8 *
-FcCacheSubdir args(const FcCache *c, int i)
+FcCacheSubdir args2(const FcCache *c, int i)
 {
     return FcCacheSubdir (c, i);
 }
 
 int
-FcCacheNumSubdir args(const FcCache *c)
+FcCacheNumSubdir args1(const FcCache *c)
 {
     return c->dirs_count;
 }
 
 int
-FcCacheNumFont args(const FcCache *c)
+FcCacheNumFont args1(const FcCache *c)
 {
     return FcCacheSet(c)->nfont;
 }
@@ -929,7 +950,7 @@ static void MD5Init(struct MD5Context *ctx)
  * Update context to reflect the concatenation of another buffer full
  * of bytes.
  */
-static void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len)
+static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len)
 {
     FcChar32 t;