610b8f0b77a4c988744946a59f6c35acf9a7a239
[platform/upstream/fontconfig.git] / src / fccache.c
1 /*
2  * Copyright © 2000 Keith Packard
3  * Copyright © 2005 Patrick Lam
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of the author(s) not be used in
10  * advertising or publicity pertaining to distribution of the software without
11  * specific, written prior permission.  The authors make no
12  * representations about the suitability of this software for any purpose.  It
13  * is provided "as is" without express or implied warranty.
14  *
15  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21  * PERFORMANCE OF THIS SOFTWARE.
22  */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "fcint.h"
27 #include "fcarch.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <dirent.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <time.h>
35 #include <assert.h>
36 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
37 #  include <unistd.h>
38 #  include <sys/mman.h>
39 #endif
40
41 #ifndef O_BINARY
42 #define O_BINARY 0
43 #endif
44
45
46 struct MD5Context {
47         FcChar32 buf[4];
48         FcChar32 bits[2];
49         unsigned char in[64];
50 };
51
52 static void MD5Init(struct MD5Context *ctx);
53 static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len);
54 static void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
55 static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]);
56
57 #define CACHEBASE_LEN (1 + 32 + 1 + sizeof (FC_ARCHITECTURE) + sizeof (FC_CACHE_SUFFIX))
58
59 static FcBool
60 FcCacheIsMmapSafe (int fd)
61 {
62     enum {
63       MMAP_NOT_INITIALIZED = 0,
64       MMAP_USE,
65       MMAP_DONT_USE,
66       MMAP_CHECK_FS,
67     } status;
68     static void *static_status;
69
70     status = (intptr_t) fc_atomic_ptr_get (&static_status);
71
72     if (status == MMAP_NOT_INITIALIZED)
73     {
74         const char *env = getenv ("FONTCONFIG_USE_MMAP");
75         FcBool use;
76         if (env && FcNameBool ((const FcChar8 *) env, &use))
77             status =  use ? MMAP_USE : MMAP_DONT_USE;
78         else
79             status = MMAP_CHECK_FS;
80         (void) fc_atomic_ptr_cmpexch (&static_status, NULL, (void *) status);
81     }
82
83     if (status == MMAP_CHECK_FS)
84         return FcIsFsMmapSafe (fd);
85     else
86         return status == MMAP_USE;
87
88 }
89
90 static const char bin2hex[] = { '0', '1', '2', '3',
91                                 '4', '5', '6', '7',
92                                 '8', '9', 'a', 'b',
93                                 'c', 'd', 'e', 'f' };
94
95 static FcChar8 *
96 FcDirCacheBasename (const FcChar8 * dir, FcChar8 cache_base[CACHEBASE_LEN])
97 {
98     unsigned char       hash[16];
99     FcChar8             *hex_hash;
100     int                 cnt;
101     struct MD5Context   ctx;
102
103     MD5Init (&ctx);
104     MD5Update (&ctx, (const unsigned char *)dir, strlen ((const char *) dir));
105
106     MD5Final (hash, &ctx);
107
108     cache_base[0] = '/';
109     hex_hash = cache_base + 1;
110     for (cnt = 0; cnt < 16; ++cnt)
111     {
112         hex_hash[2*cnt  ] = bin2hex[hash[cnt] >> 4];
113         hex_hash[2*cnt+1] = bin2hex[hash[cnt] & 0xf];
114     }
115     hex_hash[2*cnt] = 0;
116     strcat ((char *) cache_base, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX);
117
118     return cache_base;
119 }
120
121 FcBool
122 FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config)
123 {
124     FcChar8     *cache_hashed = NULL;
125     FcChar8     cache_base[CACHEBASE_LEN];
126     FcStrList   *list;
127     FcChar8     *cache_dir;
128
129     FcDirCacheBasename (dir, cache_base);
130
131     list = FcStrListCreate (config->cacheDirs);
132     if (!list)
133         return FcFalse;
134         
135     while ((cache_dir = FcStrListNext (list)))
136     {
137         cache_hashed = FcStrPlus (cache_dir, cache_base);
138         if (!cache_hashed)
139             break;
140         (void) unlink ((char *) cache_hashed);
141         FcStrFree (cache_hashed);
142     }
143     FcStrListDone (list);
144     /* return FcFalse if something went wrong */
145     if (cache_dir)
146         return FcFalse;
147     return FcTrue;
148 }
149
150 static int
151 FcDirCacheOpenFile (const FcChar8 *cache_file, struct stat *file_stat)
152 {
153     int fd;
154
155 #ifdef _WIN32
156     if (FcStat (cache_file, file_stat) < 0)
157         return -1;
158 #endif
159     fd = FcOpen((char *) cache_file, O_RDONLY | O_BINARY);
160     if (fd < 0)
161         return fd;
162 #ifndef _WIN32
163     if (fstat (fd, file_stat) < 0)
164     {
165         close (fd);
166         return -1;
167     }
168 #endif
169     return fd;
170 }
171
172 /*
173  * Look for a cache file for the specified dir. Attempt
174  * to use each one we find, stopping when the callback
175  * indicates success
176  */
177 static FcBool
178 FcDirCacheProcess (FcConfig *config, const FcChar8 *dir,
179                    FcBool (*callback) (int fd, struct stat *fd_stat,
180                                        struct stat *dir_stat, void *closure),
181                    void *closure, FcChar8 **cache_file_ret)
182 {
183     int         fd = -1;
184     FcChar8     cache_base[CACHEBASE_LEN];
185     FcStrList   *list;
186     FcChar8     *cache_dir;
187     struct stat file_stat, dir_stat;
188     FcBool      ret = FcFalse;
189
190     if (FcStatChecksum (dir, &dir_stat) < 0)
191         return FcFalse;
192
193     FcDirCacheBasename (dir, cache_base);
194
195     list = FcStrListCreate (config->cacheDirs);
196     if (!list)
197         return FcFalse;
198         
199     while ((cache_dir = FcStrListNext (list)))
200     {
201         FcChar8 *cache_hashed = FcStrPlus (cache_dir, cache_base);
202         if (!cache_hashed)
203             break;
204         fd = FcDirCacheOpenFile (cache_hashed, &file_stat);
205         if (fd >= 0) {
206             ret = (*callback) (fd, &file_stat, &dir_stat, closure);
207             close (fd);
208             if (ret)
209             {
210                 if (cache_file_ret)
211                     *cache_file_ret = cache_hashed;
212                 else
213                     FcStrFree (cache_hashed);
214                 break;
215             }
216         }
217         FcStrFree (cache_hashed);
218     }
219     FcStrListDone (list);
220
221     return ret;
222 }
223
224 #define FC_CACHE_MIN_MMAP   1024
225
226 /*
227  * Skip list element, make sure the 'next' pointer is the last thing
228  * in the structure, it will be allocated large enough to hold all
229  * of the necessary pointers
230  */
231
232 typedef struct _FcCacheSkip FcCacheSkip;
233
234 struct _FcCacheSkip {
235     FcCache         *cache;
236     FcRef           ref;
237     intptr_t        size;
238     dev_t           cache_dev;
239     ino_t           cache_ino;
240     time_t          cache_mtime;
241     FcCacheSkip     *next[1];
242 };
243
244 /*
245  * The head of the skip list; pointers for every possible level
246  * in the skip list, plus the largest level in the list
247  */
248
249 #define FC_CACHE_MAX_LEVEL  16
250
251 /* Protected by cache_lock below */
252 static FcCacheSkip      *fcCacheChains[FC_CACHE_MAX_LEVEL];
253 static int              fcCacheMaxLevel;
254
255
256 static int32_t
257 FcRandom(void)
258 {
259     int32_t result;
260
261 #if HAVE_RANDOM_R
262     static struct random_data fcrandbuf;
263     static char statebuf[256];
264     static FcBool initialized = FcFalse;
265
266     if (initialized != FcTrue)
267     {
268         initstate_r(time(NULL), statebuf, 256, &fcrandbuf);
269         initialized = FcTrue;
270     }
271
272     random_r(&fcrandbuf, &result);
273 #elif HAVE_RANDOM
274     static char statebuf[256];
275     char *state;
276     static FcBool initialized = FcFalse;
277
278     if (initialized != FcTrue)
279     {
280         state = initstate(time(NULL), statebuf, 256);
281         initialized = FcTrue;
282     }
283     else
284         state = setstate(statebuf);
285
286     result = random();
287
288     setstate(state);
289 #elif HAVE_LRAND48
290     result = lrand48();
291 #elif HAVE_RAND_R
292     static unsigned int seed = time(NULL);
293
294     result = rand_r(&seed);
295 #elif HAVE_RAND
296     static FcBool initialized = FcFalse;
297
298     if (initialized != FcTrue)
299     {
300         srand(time(NULL));
301         initialized = FcTrue;
302     }
303     result = rand();
304 #else
305 # error no random number generator function available.
306 #endif
307
308     return result;
309 }
310
311
312 static FcMutex *cache_lock;
313
314 static void
315 lock_cache (void)
316 {
317   FcMutex *lock;
318 retry:
319   lock = fc_atomic_ptr_get (&cache_lock);
320   if (!lock) {
321     lock = (FcMutex *) malloc (sizeof (FcMutex));
322     FcMutexInit (lock);
323     if (!fc_atomic_ptr_cmpexch (&cache_lock, NULL, lock)) {
324       FcMutexFinish (lock);
325       goto retry;
326     }
327
328     FcMutexLock (lock);
329     /* Initialize random state */
330     FcRandom ();
331     return;
332   }
333   FcMutexLock (lock);
334 }
335
336 static void
337 unlock_cache (void)
338 {
339   FcMutexUnlock (cache_lock);
340 }
341
342 static void
343 free_lock (void)
344 {
345   FcMutex *lock;
346   lock = fc_atomic_ptr_get (&cache_lock);
347   if (lock && fc_atomic_ptr_cmpexch (&cache_lock, lock, NULL)) {
348     FcMutexFinish (lock);
349     free (lock);
350   }
351 }
352
353
354
355 /*
356  * Generate a random level number, distributed
357  * so that each level is 1/4 as likely as the one before
358  *
359  * Note that level numbers run 1 <= level <= MAX_LEVEL
360  */
361 static int
362 random_level (void)
363 {
364     /* tricky bit -- each bit is '1' 75% of the time */
365     long int    bits = FcRandom () | FcRandom ();
366     int level = 0;
367
368     while (++level < FC_CACHE_MAX_LEVEL)
369     {
370         if (bits & 1)
371             break;
372         bits >>= 1;
373     }
374     return level;
375 }
376
377 /*
378  * Insert cache into the list
379  */
380 static FcBool
381 FcCacheInsert (FcCache *cache, struct stat *cache_stat)
382 {
383     FcCacheSkip    **update[FC_CACHE_MAX_LEVEL];
384     FcCacheSkip    *s, **next;
385     int             i, level;
386
387     lock_cache ();
388
389     /*
390      * Find links along each chain
391      */
392     next = fcCacheChains;
393     for (i = fcCacheMaxLevel; --i >= 0; )
394     {
395         for (; (s = next[i]); next = s->next)
396             if (s->cache > cache)
397                 break;
398         update[i] = &next[i];
399     }
400
401     /*
402      * Create new list element
403      */
404     level = random_level ();
405     if (level > fcCacheMaxLevel)
406     {
407         level = fcCacheMaxLevel + 1;
408         update[fcCacheMaxLevel] = &fcCacheChains[fcCacheMaxLevel];
409         fcCacheMaxLevel = level;
410     }
411
412     s = malloc (sizeof (FcCacheSkip) + (level - 1) * sizeof (FcCacheSkip *));
413     if (!s)
414         return FcFalse;
415
416     s->cache = cache;
417     s->size = cache->size;
418     FcRefInit (&s->ref, 1);
419     if (cache_stat)
420     {
421         s->cache_dev = cache_stat->st_dev;
422         s->cache_ino = cache_stat->st_ino;
423         s->cache_mtime = cache_stat->st_mtime;
424     }
425     else
426     {
427         s->cache_dev = 0;
428         s->cache_ino = 0;
429         s->cache_mtime = 0;
430     }
431
432     /*
433      * Insert into all fcCacheChains
434      */
435     for (i = 0; i < level; i++)
436     {
437         s->next[i] = *update[i];
438         *update[i] = s;
439     }
440
441     unlock_cache ();
442     return FcTrue;
443 }
444
445 static FcCacheSkip *
446 FcCacheFindByAddrUnlocked (void *object)
447 {
448     int     i;
449     FcCacheSkip    **next = fcCacheChains;
450     FcCacheSkip    *s;
451
452     if (!object)
453         return NULL;
454
455     /*
456      * Walk chain pointers one level at a time
457      */
458     for (i = fcCacheMaxLevel; --i >= 0;)
459         while (next[i] && (char *) object >= ((char *) next[i]->cache + next[i]->size))
460             next = next[i]->next;
461     /*
462      * Here we are
463      */
464     s = next[0];
465     if (s && (char *) object < ((char *) s->cache + s->size))
466         return s;
467     return NULL;
468 }
469
470 static FcCacheSkip *
471 FcCacheFindByAddr (void *object)
472 {
473     FcCacheSkip *ret;
474     lock_cache ();
475     ret = FcCacheFindByAddrUnlocked (object);
476     unlock_cache ();
477     return ret;
478 }
479
480 static void
481 FcCacheRemoveUnlocked (FcCache *cache)
482 {
483     FcCacheSkip     **update[FC_CACHE_MAX_LEVEL];
484     FcCacheSkip     *s, **next;
485     int             i;
486
487     /*
488      * Find links along each chain
489      */
490     next = fcCacheChains;
491     for (i = fcCacheMaxLevel; --i >= 0; )
492     {
493         for (; (s = next[i]); next = s->next)
494             if (s->cache >= cache)
495                 break;
496         update[i] = &next[i];
497     }
498     s = next[0];
499     for (i = 0; i < fcCacheMaxLevel && *update[i] == s; i++)
500         *update[i] = s->next[i];
501     while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL)
502         fcCacheMaxLevel--;
503     free (s);
504 }
505
506 static FcCache *
507 FcCacheFindByStat (struct stat *cache_stat)
508 {
509     FcCacheSkip     *s;
510
511     lock_cache ();
512     for (s = fcCacheChains[0]; s; s = s->next[0])
513         if (s->cache_dev == cache_stat->st_dev &&
514             s->cache_ino == cache_stat->st_ino &&
515             s->cache_mtime == cache_stat->st_mtime)
516         {
517             FcRefInc (&s->ref);
518             unlock_cache ();
519             return s->cache;
520         }
521     unlock_cache ();
522     return NULL;
523 }
524
525 static void
526 FcDirCacheDisposeUnlocked (FcCache *cache)
527 {
528     FcCacheRemoveUnlocked (cache);
529
530     switch (cache->magic) {
531     case FC_CACHE_MAGIC_ALLOC:
532         free (cache);
533         break;
534     case FC_CACHE_MAGIC_MMAP:
535 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
536         munmap (cache, cache->size);
537 #elif defined(_WIN32)
538         UnmapViewOfFile (cache);
539 #endif
540         break;
541     }
542 }
543
544 void
545 FcCacheObjectReference (void *object)
546 {
547     FcCacheSkip *skip = FcCacheFindByAddr (object);
548
549     if (skip)
550         FcRefInc (&skip->ref);
551 }
552
553 void
554 FcCacheObjectDereference (void *object)
555 {
556     FcCacheSkip *skip;
557
558     lock_cache ();
559     skip = FcCacheFindByAddrUnlocked (object);
560     if (skip)
561     {
562         if (FcRefDec (&skip->ref) == 1)
563             FcDirCacheDisposeUnlocked (skip->cache);
564     }
565     unlock_cache ();
566 }
567
568 void
569 FcCacheFini (void)
570 {
571     int             i;
572
573     for (i = 0; i < FC_CACHE_MAX_LEVEL; i++)
574         assert (fcCacheChains[i] == NULL);
575     assert (fcCacheMaxLevel == 0);
576
577     free_lock ();
578 }
579
580 static FcBool
581 FcCacheTimeValid (FcCache *cache, struct stat *dir_stat)
582 {
583     struct stat dir_static;
584
585     if (!dir_stat)
586     {
587         if (FcStatChecksum (FcCacheDir (cache), &dir_static) < 0)
588             return FcFalse;
589         dir_stat = &dir_static;
590     }
591     if (FcDebug () & FC_DBG_CACHE)
592         printf ("FcCacheTimeValid dir \"%s\" cache checksum %d dir checksum %d\n",
593                 FcCacheDir (cache), cache->checksum, (int) dir_stat->st_mtime);
594     return cache->checksum == (int) dir_stat->st_mtime;
595 }
596
597 /*
598  * Map a cache file into memory
599  */
600 static FcCache *
601 FcDirCacheMapFd (int fd, struct stat *fd_stat, struct stat *dir_stat)
602 {
603     FcCache     *cache;
604     FcBool      allocated = FcFalse;
605
606     if (fd_stat->st_size < (int) sizeof (FcCache))
607         return NULL;
608     cache = FcCacheFindByStat (fd_stat);
609     if (cache)
610     {
611         if (FcCacheTimeValid (cache, dir_stat))
612             return cache;
613         FcDirCacheUnload (cache);
614         cache = NULL;
615     }
616
617     /*
618      * Large cache files are mmap'ed, smaller cache files are read. This
619      * balances the system cost of mmap against per-process memory usage.
620      */
621     if (FcCacheIsMmapSafe (fd) && fd_stat->st_size >= FC_CACHE_MIN_MMAP)
622     {
623 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
624         cache = mmap (0, fd_stat->st_size, PROT_READ, MAP_SHARED, fd, 0);
625 #ifdef HAVE_POSIX_FADVISE
626         posix_fadvise (fd, 0, fd_stat->st_size, POSIX_FADV_WILLNEED);
627 #endif
628         if (cache == MAP_FAILED)
629             cache = NULL;
630 #elif defined(_WIN32)
631         {
632             HANDLE hFileMap;
633
634             cache = NULL;
635             hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
636                                          PAGE_READONLY, 0, 0, NULL);
637             if (hFileMap != NULL)
638             {
639                 cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0,
640                                        fd_stat->st_size);
641                 CloseHandle (hFileMap);
642             }
643         }
644 #endif
645     }
646     if (!cache)
647     {
648         cache = malloc (fd_stat->st_size);
649         if (!cache)
650             return NULL;
651
652         if (read (fd, cache, fd_stat->st_size) != fd_stat->st_size)
653         {
654             free (cache);
655             return NULL;
656         }
657         allocated = FcTrue;
658     }
659     if (cache->magic != FC_CACHE_MAGIC_MMAP ||
660         cache->version < FC_CACHE_CONTENT_VERSION ||
661         cache->size != (intptr_t) fd_stat->st_size ||
662         !FcCacheTimeValid (cache, dir_stat) ||
663         !FcCacheInsert (cache, fd_stat))
664     {
665         if (allocated)
666             free (cache);
667         else
668         {
669 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
670             munmap (cache, fd_stat->st_size);
671 #elif defined(_WIN32)
672             UnmapViewOfFile (cache);
673 #endif
674         }
675         return NULL;
676     }
677
678     /* Mark allocated caches so they're freed rather than unmapped */
679     if (allocated)
680         cache->magic = FC_CACHE_MAGIC_ALLOC;
681         
682     return cache;
683 }
684
685 void
686 FcDirCacheReference (FcCache *cache, int nref)
687 {
688     FcCacheSkip *skip = FcCacheFindByAddr (cache);
689
690     if (skip)
691         FcRefAdd (&skip->ref, nref);
692 }
693
694 void
695 FcDirCacheUnload (FcCache *cache)
696 {
697     FcCacheObjectDereference (cache);
698 }
699
700 static FcBool
701 FcDirCacheMapHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure)
702 {
703     FcCache *cache = FcDirCacheMapFd (fd, fd_stat, dir_stat);
704
705     if (!cache)
706         return FcFalse;
707     *((FcCache **) closure) = cache;
708     return FcTrue;
709 }
710
711 FcCache *
712 FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
713 {
714     FcCache *cache = NULL;
715
716     if (!FcDirCacheProcess (config, dir,
717                             FcDirCacheMapHelper,
718                             &cache, cache_file))
719         return NULL;
720     return cache;
721 }
722
723 FcCache *
724 FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
725 {
726     int fd;
727     FcCache *cache;
728     struct stat my_file_stat;
729
730     if (!file_stat)
731         file_stat = &my_file_stat;
732     fd = FcDirCacheOpenFile (cache_file, file_stat);
733     if (fd < 0)
734         return NULL;
735     cache = FcDirCacheMapFd (fd, file_stat, NULL);
736     close (fd);
737     return cache;
738 }
739
740 /*
741  * Validate a cache file by reading the header and checking
742  * the magic number and the size field
743  */
744 static FcBool
745 FcDirCacheValidateHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure FC_UNUSED)
746 {
747     FcBool  ret = FcTrue;
748     FcCache     c;
749
750     if (read (fd, &c, sizeof (FcCache)) != sizeof (FcCache))
751         ret = FcFalse;
752     else if (c.magic != FC_CACHE_MAGIC_MMAP)
753         ret = FcFalse;
754     else if (c.version < FC_CACHE_CONTENT_VERSION)
755         ret = FcFalse;
756     else if (fd_stat->st_size != c.size)
757         ret = FcFalse;
758     else if (c.checksum != (int) dir_stat->st_mtime)
759         ret = FcFalse;
760     return ret;
761 }
762
763 static FcBool
764 FcDirCacheValidConfig (const FcChar8 *dir, FcConfig *config)
765 {
766     return FcDirCacheProcess (config, dir,
767                               FcDirCacheValidateHelper,
768                               NULL, NULL);
769 }
770
771 FcBool
772 FcDirCacheValid (const FcChar8 *dir)
773 {
774     FcConfig    *config;
775
776     config = FcConfigGetCurrent ();
777     if (!config)
778         return FcFalse;
779
780     return FcDirCacheValidConfig (dir, config);
781 }
782
783 /*
784  * Build a cache structure from the given contents
785  */
786 FcCache *
787 FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs)
788 {
789     FcSerialize *serialize = FcSerializeCreate ();
790     FcCache *cache;
791     int i;
792     FcChar8     *dir_serialize;
793     intptr_t    *dirs_serialize;
794     FcFontSet   *set_serialize;
795
796     if (!serialize)
797         return NULL;
798     /*
799      * Space for cache structure
800      */
801     FcSerializeReserve (serialize, sizeof (FcCache));
802     /*
803      * Directory name
804      */
805     if (!FcStrSerializeAlloc (serialize, dir))
806         goto bail1;
807     /*
808      * Subdirs
809      */
810     FcSerializeAlloc (serialize, dirs, dirs->num * sizeof (FcChar8 *));
811     for (i = 0; i < dirs->num; i++)
812         if (!FcStrSerializeAlloc (serialize, dirs->strs[i]))
813             goto bail1;
814
815     /*
816      * Patterns
817      */
818     if (!FcFontSetSerializeAlloc (serialize, set))
819         goto bail1;
820
821     /* Serialize layout complete. Now allocate space and fill it */
822     cache = malloc (serialize->size);
823     if (!cache)
824         goto bail1;
825     /* shut up valgrind */
826     memset (cache, 0, serialize->size);
827
828     serialize->linear = cache;
829
830     cache->magic = FC_CACHE_MAGIC_ALLOC;
831     cache->version = FC_CACHE_CONTENT_VERSION;
832     cache->size = serialize->size;
833     cache->checksum = (int) dir_stat->st_mtime;
834
835     /*
836      * Serialize directory name
837      */
838     dir_serialize = FcStrSerialize (serialize, dir);
839     if (!dir_serialize)
840         goto bail2;
841     cache->dir = FcPtrToOffset (cache, dir_serialize);
842
843     /*
844      * Serialize sub dirs
845      */
846     dirs_serialize = FcSerializePtr (serialize, dirs);
847     if (!dirs_serialize)
848         goto bail2;
849     cache->dirs = FcPtrToOffset (cache, dirs_serialize);
850     cache->dirs_count = dirs->num;
851     for (i = 0; i < dirs->num; i++)
852     {
853         FcChar8 *d_serialize = FcStrSerialize (serialize, dirs->strs[i]);
854         if (!d_serialize)
855             goto bail2;
856         dirs_serialize[i] = FcPtrToOffset (dirs_serialize, d_serialize);
857     }
858
859     /*
860      * Serialize font set
861      */
862     set_serialize = FcFontSetSerialize (serialize, set);
863     if (!set_serialize)
864         goto bail2;
865     cache->set = FcPtrToOffset (cache, set_serialize);
866
867     FcSerializeDestroy (serialize);
868
869     FcCacheInsert (cache, NULL);
870
871     return cache;
872
873 bail2:
874     free (cache);
875 bail1:
876     FcSerializeDestroy (serialize);
877     return NULL;
878 }
879
880
881 #ifdef _WIN32
882 #include <direct.h>
883 #define mkdir(path,mode) _mkdir(path)
884 #endif
885
886 static FcBool
887 FcMakeDirectory (const FcChar8 *dir)
888 {
889     FcChar8 *parent;
890     FcBool  ret;
891
892     if (strlen ((char *) dir) == 0)
893         return FcFalse;
894
895     parent = FcStrDirname (dir);
896     if (!parent)
897         return FcFalse;
898     if (access ((char *) parent, F_OK) == 0)
899         ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
900     else if (access ((char *) parent, F_OK) == -1)
901         ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
902     else
903         ret = FcFalse;
904     FcStrFree (parent);
905     return ret;
906 }
907
908 /* write serialized state to the cache file */
909 FcBool
910 FcDirCacheWrite (FcCache *cache, FcConfig *config)
911 {
912     FcChar8         *dir = FcCacheDir (cache);
913     FcChar8         cache_base[CACHEBASE_LEN];
914     FcChar8         *cache_hashed;
915     int             fd;
916     FcAtomic        *atomic;
917     FcStrList       *list;
918     FcChar8         *cache_dir = NULL;
919     FcChar8         *test_dir;
920     FcCacheSkip     *skip;
921     struct stat     cache_stat;
922     unsigned int    magic;
923     int             written;
924
925     /*
926      * Write it to the first directory in the list which is writable
927      */
928
929     list = FcStrListCreate (config->cacheDirs);
930     if (!list)
931         return FcFalse;
932     while ((test_dir = FcStrListNext (list))) {
933         if (access ((char *) test_dir, W_OK) == 0)
934         {
935             cache_dir = test_dir;
936             break;
937         }
938         else
939         {
940             /*
941              * If the directory doesn't exist, try to create it
942              */
943             if (access ((char *) test_dir, F_OK) == -1) {
944                 if (FcMakeDirectory (test_dir))
945                 {
946                     cache_dir = test_dir;
947                     /* Create CACHEDIR.TAG */
948                     FcDirCacheCreateTagFile (cache_dir);
949                     break;
950                 }
951             }
952             /*
953              * Otherwise, try making it writable
954              */
955             else if (chmod ((char *) test_dir, 0755) == 0)
956             {
957                 cache_dir = test_dir;
958                 /* Try to create CACHEDIR.TAG too */
959                 FcDirCacheCreateTagFile (cache_dir);
960                 break;
961             }
962         }
963     }
964     FcStrListDone (list);
965     if (!cache_dir)
966         return FcFalse;
967
968     FcDirCacheBasename (dir, cache_base);
969     cache_hashed = FcStrPlus (cache_dir, cache_base);
970     if (!cache_hashed)
971         return FcFalse;
972
973     if (FcDebug () & FC_DBG_CACHE)
974         printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n",
975                 dir, cache_hashed);
976
977     atomic = FcAtomicCreate ((FcChar8 *)cache_hashed);
978     if (!atomic)
979         goto bail1;
980
981     if (!FcAtomicLock (atomic))
982         goto bail3;
983
984     fd = FcOpen((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT | O_BINARY, 0666);
985     if (fd == -1)
986         goto bail4;
987
988     /* Temporarily switch magic to MMAP while writing to file */
989     magic = cache->magic;
990     if (magic != FC_CACHE_MAGIC_MMAP)
991         cache->magic = FC_CACHE_MAGIC_MMAP;
992
993     /*
994      * Write cache contents to file
995      */
996     written = write (fd, cache, cache->size);
997
998     /* Switch magic back */
999     if (magic != FC_CACHE_MAGIC_MMAP)
1000         cache->magic = magic;
1001
1002     if (written != cache->size)
1003     {
1004         perror ("write cache");
1005         goto bail5;
1006     }
1007
1008     close(fd);
1009     if (!FcAtomicReplaceOrig(atomic))
1010         goto bail4;
1011
1012     /* If the file is small, update the cache chain entry such that the
1013      * new cache file is not read again.  If it's large, we don't do that
1014      * such that we reload it, using mmap, which is shared across processes.
1015      */
1016     if (cache->size < FC_CACHE_MIN_MMAP && FcStat (cache_hashed, &cache_stat))
1017     {
1018         lock_cache ();
1019         if ((skip = FcCacheFindByAddrUnlocked (cache)))
1020         {
1021             skip->cache_dev = cache_stat.st_dev;
1022             skip->cache_ino = cache_stat.st_ino;
1023             skip->cache_mtime = cache_stat.st_mtime;
1024         }
1025         unlock_cache ();
1026     }
1027
1028     FcStrFree (cache_hashed);
1029     FcAtomicUnlock (atomic);
1030     FcAtomicDestroy (atomic);
1031     return FcTrue;
1032
1033  bail5:
1034     close (fd);
1035  bail4:
1036     FcAtomicUnlock (atomic);
1037  bail3:
1038     FcAtomicDestroy (atomic);
1039  bail1:
1040     FcStrFree (cache_hashed);
1041     return FcFalse;
1042 }
1043
1044 FcBool
1045 FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose)
1046 {
1047     DIR         *d;
1048     struct dirent *ent;
1049     FcChar8     *dir_base;
1050     FcBool      ret = FcTrue;
1051     FcBool      remove;
1052     FcCache     *cache;
1053     struct stat target_stat;
1054
1055     dir_base = FcStrPlus (cache_dir, (FcChar8 *) FC_DIR_SEPARATOR_S);
1056     if (!dir_base)
1057     {
1058         fprintf (stderr, "Fontconfig error: %s: out of memory\n", cache_dir);
1059         return FcFalse;
1060     }
1061     if (access ((char *) cache_dir, W_OK) != 0)
1062     {
1063         if (verbose || FcDebug () & FC_DBG_CACHE)
1064             printf ("%s: not cleaning %s cache directory\n", cache_dir,
1065                     access ((char *) cache_dir, F_OK) == 0 ? "unwritable" : "non-existent");
1066         goto bail0;
1067     }
1068     if (verbose || FcDebug () & FC_DBG_CACHE)
1069         printf ("%s: cleaning cache directory\n", cache_dir);
1070     d = opendir ((char *) cache_dir);
1071     if (!d)
1072     {
1073         perror ((char *) cache_dir);
1074         ret = FcFalse;
1075         goto bail0;
1076     }
1077     while ((ent = readdir (d)))
1078     {
1079         FcChar8 *file_name;
1080         const FcChar8   *target_dir;
1081
1082         if (ent->d_name[0] == '.')
1083             continue;
1084         /* skip cache files for different architectures and */
1085         /* files which are not cache files at all */
1086         if (strlen(ent->d_name) != 32 + strlen ("-" FC_ARCHITECTURE FC_CACHE_SUFFIX) ||
1087             strcmp(ent->d_name + 32, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX))
1088             continue;
1089
1090         file_name = FcStrPlus (dir_base, (FcChar8 *) ent->d_name);
1091         if (!file_name)
1092         {
1093             fprintf (stderr, "Fontconfig error: %s: allocation failure\n", cache_dir);
1094             ret = FcFalse;
1095             break;
1096         }
1097         remove = FcFalse;
1098         cache = FcDirCacheLoadFile (file_name, NULL);
1099         if (!cache)
1100         {
1101             if (verbose || FcDebug () & FC_DBG_CACHE)
1102                 printf ("%s: invalid cache file: %s\n", cache_dir, ent->d_name);
1103             remove = FcTrue;
1104         }
1105         else
1106         {
1107             target_dir = FcCacheDir (cache);
1108             if (stat ((char *) target_dir, &target_stat) < 0)
1109             {
1110                 if (verbose || FcDebug () & FC_DBG_CACHE)
1111                     printf ("%s: %s: missing directory: %s \n",
1112                             cache_dir, ent->d_name, target_dir);
1113                 remove = FcTrue;
1114             }
1115             FcDirCacheUnload (cache);
1116         }
1117         if (remove)
1118         {
1119             if (unlink ((char *) file_name) < 0)
1120             {
1121                 perror ((char *) file_name);
1122                 ret = FcFalse;
1123             }
1124         }
1125         FcStrFree (file_name);
1126     }
1127
1128     closedir (d);
1129   bail0:
1130     FcStrFree (dir_base);
1131
1132     return ret;
1133 }
1134
1135 /*
1136  * Hokey little macro trick to permit the definitions of C functions
1137  * with the same name as CPP macros
1138  */
1139 #define args1(x)            (x)
1140 #define args2(x,y)          (x,y)
1141
1142 const FcChar8 *
1143 FcCacheDir args1(const FcCache *c)
1144 {
1145     return FcCacheDir (c);
1146 }
1147
1148 FcFontSet *
1149 FcCacheCopySet args1(const FcCache *c)
1150 {
1151     FcFontSet   *old = FcCacheSet (c);
1152     FcFontSet   *new = FcFontSetCreate ();
1153     int         i;
1154
1155     if (!new)
1156         return NULL;
1157     for (i = 0; i < old->nfont; i++)
1158     {
1159         FcPattern   *font = FcFontSetFont (old, i);
1160         
1161         FcPatternReference (font);
1162         if (!FcFontSetAdd (new, font))
1163         {
1164             FcFontSetDestroy (new);
1165             return NULL;
1166         }
1167     }
1168     return new;
1169 }
1170
1171 const FcChar8 *
1172 FcCacheSubdir args2(const FcCache *c, int i)
1173 {
1174     return FcCacheSubdir (c, i);
1175 }
1176
1177 int
1178 FcCacheNumSubdir args1(const FcCache *c)
1179 {
1180     return c->dirs_count;
1181 }
1182
1183 int
1184 FcCacheNumFont args1(const FcCache *c)
1185 {
1186     return FcCacheSet(c)->nfont;
1187 }
1188
1189 /*
1190  * This code implements the MD5 message-digest algorithm.
1191  * The algorithm is due to Ron Rivest.  This code was
1192  * written by Colin Plumb in 1993, no copyright is claimed.
1193  * This code is in the public domain; do with it what you wish.
1194  *
1195  * Equivalent code is available from RSA Data Security, Inc.
1196  * This code has been tested against that, and is equivalent,
1197  * except that you don't need to include two pages of legalese
1198  * with every copy.
1199  *
1200  * To compute the message digest of a chunk of bytes, declare an
1201  * MD5Context structure, pass it to MD5Init, call MD5Update as
1202  * needed on buffers full of bytes, and then call MD5Final, which
1203  * will fill a supplied 16-byte array with the digest.
1204  */
1205
1206 #ifndef HIGHFIRST
1207 #define byteReverse(buf, len)   /* Nothing */
1208 #else
1209 /*
1210  * Note: this code is harmless on little-endian machines.
1211  */
1212 void byteReverse(unsigned char *buf, unsigned longs)
1213 {
1214     FcChar32 t;
1215     do {
1216         t = (FcChar32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
1217             ((unsigned) buf[1] << 8 | buf[0]);
1218         *(FcChar32 *) buf = t;
1219         buf += 4;
1220     } while (--longs);
1221 }
1222 #endif
1223
1224 /*
1225  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
1226  * initialization constants.
1227  */
1228 static void MD5Init(struct MD5Context *ctx)
1229 {
1230     ctx->buf[0] = 0x67452301;
1231     ctx->buf[1] = 0xefcdab89;
1232     ctx->buf[2] = 0x98badcfe;
1233     ctx->buf[3] = 0x10325476;
1234
1235     ctx->bits[0] = 0;
1236     ctx->bits[1] = 0;
1237 }
1238
1239 /*
1240  * Update context to reflect the concatenation of another buffer full
1241  * of bytes.
1242  */
1243 static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len)
1244 {
1245     FcChar32 t;
1246
1247     /* Update bitcount */
1248
1249     t = ctx->bits[0];
1250     if ((ctx->bits[0] = t + ((FcChar32) len << 3)) < t)
1251         ctx->bits[1]++;         /* Carry from low to high */
1252     ctx->bits[1] += len >> 29;
1253
1254     t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
1255
1256     /* Handle any leading odd-sized chunks */
1257
1258     if (t) {
1259         unsigned char *p = (unsigned char *) ctx->in + t;
1260
1261         t = 64 - t;
1262         if (len < t) {
1263             memcpy(p, buf, len);
1264             return;
1265         }
1266         memcpy(p, buf, t);
1267         byteReverse(ctx->in, 16);
1268         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1269         buf += t;
1270         len -= t;
1271     }
1272     /* Process data in 64-byte chunks */
1273
1274     while (len >= 64) {
1275         memcpy(ctx->in, buf, 64);
1276         byteReverse(ctx->in, 16);
1277         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1278         buf += 64;
1279         len -= 64;
1280     }
1281
1282     /* Handle any remaining bytes of data. */
1283
1284     memcpy(ctx->in, buf, len);
1285 }
1286
1287 /*
1288  * Final wrapup - pad to 64-byte boundary with the bit pattern
1289  * 1 0* (64-bit count of bits processed, MSB-first)
1290  */
1291 static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
1292 {
1293     unsigned count;
1294     unsigned char *p;
1295
1296     /* Compute number of bytes mod 64 */
1297     count = (ctx->bits[0] >> 3) & 0x3F;
1298
1299     /* Set the first char of padding to 0x80.  This is safe since there is
1300        always at least one byte free */
1301     p = ctx->in + count;
1302     *p++ = 0x80;
1303
1304     /* Bytes of padding needed to make 64 bytes */
1305     count = 64 - 1 - count;
1306
1307     /* Pad out to 56 mod 64 */
1308     if (count < 8) {
1309         /* Two lots of padding:  Pad the first block to 64 bytes */
1310         memset(p, 0, count);
1311         byteReverse(ctx->in, 16);
1312         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1313
1314         /* Now fill the next block with 56 bytes */
1315         memset(ctx->in, 0, 56);
1316     } else {
1317         /* Pad block to 56 bytes */
1318         memset(p, 0, count - 8);
1319     }
1320     byteReverse(ctx->in, 14);
1321
1322     /* Append length in bits and transform */
1323     ((FcChar32 *) ctx->in)[14] = ctx->bits[0];
1324     ((FcChar32 *) ctx->in)[15] = ctx->bits[1];
1325
1326     MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1327     byteReverse((unsigned char *) ctx->buf, 4);
1328     memcpy(digest, ctx->buf, 16);
1329     memset(ctx, 0, sizeof(*ctx));        /* In case it's sensitive */
1330 }
1331
1332
1333 /* The four core functions - F1 is optimized somewhat */
1334
1335 /* #define F1(x, y, z) (x & y | ~x & z) */
1336 #define F1(x, y, z) (z ^ (x & (y ^ z)))
1337 #define F2(x, y, z) F1(z, x, y)
1338 #define F3(x, y, z) (x ^ y ^ z)
1339 #define F4(x, y, z) (y ^ (x | ~z))
1340
1341 /* This is the central step in the MD5 algorithm. */
1342 #define MD5STEP(f, w, x, y, z, data, s) \
1343         ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
1344
1345 /*
1346  * The core of the MD5 algorithm, this alters an existing MD5 hash to
1347  * reflect the addition of 16 longwords of new data.  MD5Update blocks
1348  * the data and converts bytes into longwords for this routine.
1349  */
1350 static void MD5Transform(FcChar32 buf[4], FcChar32 in[16])
1351 {
1352     register FcChar32 a, b, c, d;
1353
1354     a = buf[0];
1355     b = buf[1];
1356     c = buf[2];
1357     d = buf[3];
1358
1359     MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1360     MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1361     MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
1362     MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1363     MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1364     MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1365     MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
1366     MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
1367     MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
1368     MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1369     MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1370     MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1371     MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
1372     MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
1373     MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
1374     MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1375
1376     MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1377     MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
1378     MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1379     MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1380     MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1381     MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
1382     MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1383     MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1384     MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1385     MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1386     MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1387     MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1388     MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1389     MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1390     MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1391     MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1392
1393     MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1394     MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
1395     MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1396     MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1397     MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1398     MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1399     MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1400     MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1401     MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1402     MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1403     MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1404     MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
1405     MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1406     MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1407     MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1408     MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1409
1410     MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
1411     MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
1412     MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1413     MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1414     MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1415     MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1416     MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1417     MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1418     MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1419     MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1420     MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
1421     MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1422     MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1423     MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1424     MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1425     MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1426
1427     buf[0] += a;
1428     buf[1] += b;
1429     buf[2] += c;
1430     buf[3] += d;
1431 }
1432
1433 FcBool
1434 FcDirCacheCreateTagFile (const FcChar8 *cache_dir)
1435 {
1436     FcChar8             *cache_tag;
1437     int                  fd;
1438     FILE                *fp;
1439     FcAtomic            *atomic;
1440     static const FcChar8 cache_tag_contents[] =
1441         "Signature: 8a477f597d28d172789f06886806bc55\n"
1442         "# This file is a cache directory tag created by fontconfig.\n"
1443         "# For information about cache directory tags, see:\n"
1444         "#       http://www.brynosaurus.com/cachedir/\n";
1445     static size_t        cache_tag_contents_size = sizeof (cache_tag_contents) - 1;
1446     FcBool               ret = FcFalse;
1447
1448     if (!cache_dir)
1449         return FcFalse;
1450
1451     if (access ((char *) cache_dir, W_OK) == 0)
1452     {
1453         /* Create CACHEDIR.TAG */
1454         cache_tag = FcStrPlus (cache_dir, (const FcChar8 *) FC_DIR_SEPARATOR_S "CACHEDIR.TAG");
1455         if (!cache_tag)
1456             return FcFalse;
1457         atomic = FcAtomicCreate ((FcChar8 *)cache_tag);
1458         if (!atomic)
1459             goto bail1;
1460         if (!FcAtomicLock (atomic))
1461             goto bail2;
1462         fd = FcOpen((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT, 0644);
1463         if (fd == -1)
1464             goto bail3;
1465         fp = fdopen(fd, "wb");
1466         if (fp == NULL)
1467             goto bail3;
1468
1469         fwrite(cache_tag_contents, cache_tag_contents_size, sizeof (FcChar8), fp);
1470         fclose(fp);
1471
1472         if (!FcAtomicReplaceOrig(atomic))
1473             goto bail3;
1474
1475         ret = FcTrue;
1476       bail3:
1477         FcAtomicUnlock (atomic);
1478       bail2:
1479         FcAtomicDestroy (atomic);
1480       bail1:
1481         FcStrFree (cache_tag);
1482     }
1483
1484     if (FcDebug () & FC_DBG_CACHE)
1485     {
1486         if (ret)
1487             printf ("Created CACHEDIR.TAG at %s\n", cache_dir);
1488         else
1489             printf ("Unable to create CACHEDIR.TAG at %s\n", cache_dir);
1490     }
1491
1492     return ret;
1493 }
1494
1495 void
1496 FcCacheCreateTagFile (const FcConfig *config)
1497 {
1498     FcChar8   *cache_dir = NULL;
1499     FcStrList *list;
1500
1501     list = FcConfigGetCacheDirs (config);
1502     if (!list)
1503         return;
1504
1505     while ((cache_dir = FcStrListNext (list)))
1506     {
1507         if (FcDirCacheCreateTagFile (cache_dir))
1508             break;
1509     }
1510     FcStrListDone (list);
1511 }
1512
1513 #define __fccache__
1514 #include "fcaliastail.h"
1515 #undef __fccache__