Minor
[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         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 = open((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     /*
453      * Walk chain pointers one level at a time
454      */
455     for (i = fcCacheMaxLevel; --i >= 0;)
456         while (next[i] && (char *) object >= ((char *) next[i]->cache + next[i]->size))
457             next = next[i]->next;
458     /*
459      * Here we are
460      */
461     s = next[0];
462     if (s && (char *) object < ((char *) s->cache + s->size))
463         return s;
464     return NULL;
465 }
466
467 static FcCacheSkip *
468 FcCacheFindByAddr (void *object)
469 {
470     FcCacheSkip *ret;
471     lock_cache ();
472     ret = FcCacheFindByAddrUnlocked (object);
473     unlock_cache ();
474     return ret;
475 }
476
477 static void
478 FcCacheRemoveUnlocked (FcCache *cache)
479 {
480     FcCacheSkip     **update[FC_CACHE_MAX_LEVEL];
481     FcCacheSkip     *s, **next;
482     int             i;
483
484     /*
485      * Find links along each chain
486      */
487     next = fcCacheChains;
488     for (i = fcCacheMaxLevel; --i >= 0; )
489     {
490         for (; (s = next[i]); next = s->next)
491             if (s->cache >= cache)
492                 break;
493         update[i] = &next[i];
494     }
495     s = next[0];
496     for (i = 0; i < fcCacheMaxLevel && *update[i] == s; i++)
497         *update[i] = s->next[i];
498     while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL)
499         fcCacheMaxLevel--;
500     free (s);
501 }
502
503 static FcCache *
504 FcCacheFindByStat (struct stat *cache_stat)
505 {
506     FcCacheSkip     *s;
507
508     lock_cache ();
509     for (s = fcCacheChains[0]; s; s = s->next[0])
510         if (s->cache_dev == cache_stat->st_dev &&
511             s->cache_ino == cache_stat->st_ino &&
512             s->cache_mtime == cache_stat->st_mtime)
513         {
514             FcRefInc (&s->ref);
515             unlock_cache ();
516             return s->cache;
517         }
518     unlock_cache ();
519     return NULL;
520 }
521
522 static void
523 FcDirCacheDisposeUnlocked (FcCache *cache)
524 {
525     FcCacheRemoveUnlocked (cache);
526
527     switch (cache->magic) {
528     case FC_CACHE_MAGIC_ALLOC:
529         free (cache);
530         break;
531     case FC_CACHE_MAGIC_MMAP:
532 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
533         munmap (cache, cache->size);
534 #elif defined(_WIN32)
535         UnmapViewOfFile (cache);
536 #endif
537         break;
538     }
539 }
540
541 void
542 FcCacheObjectReference (void *object)
543 {
544     FcCacheSkip *skip = FcCacheFindByAddr (object);
545
546     if (skip)
547         FcRefInc (&skip->ref);
548 }
549
550 void
551 FcCacheObjectDereference (void *object)
552 {
553     FcCacheSkip *skip;
554
555     lock_cache ();
556     skip = FcCacheFindByAddrUnlocked (object);
557     if (skip)
558     {
559         if (FcRefDec (&skip->ref) <= 1)
560             FcDirCacheDisposeUnlocked (skip->cache);
561     }
562     unlock_cache ();
563 }
564
565 void
566 FcCacheFini (void)
567 {
568     int             i;
569
570     for (i = 0; i < FC_CACHE_MAX_LEVEL; i++)
571         assert (fcCacheChains[i] == NULL);
572     assert (fcCacheMaxLevel == 0);
573
574     free_lock ();
575 }
576
577 static FcBool
578 FcCacheTimeValid (FcCache *cache, struct stat *dir_stat)
579 {
580     struct stat dir_static;
581
582     if (!dir_stat)
583     {
584         if (FcStatChecksum (FcCacheDir (cache), &dir_static) < 0)
585             return FcFalse;
586         dir_stat = &dir_static;
587     }
588     if (FcDebug () & FC_DBG_CACHE)
589         printf ("FcCacheTimeValid dir \"%s\" cache checksum %d dir checksum %d\n",
590                 FcCacheDir (cache), cache->checksum, (int) dir_stat->st_mtime);
591     return cache->checksum == (int) dir_stat->st_mtime;
592 }
593
594 /*
595  * Map a cache file into memory
596  */
597 static FcCache *
598 FcDirCacheMapFd (int fd, struct stat *fd_stat, struct stat *dir_stat)
599 {
600     FcCache     *cache;
601     FcBool      allocated = FcFalse;
602
603     if (fd_stat->st_size < (int) sizeof (FcCache))
604         return NULL;
605     cache = FcCacheFindByStat (fd_stat);
606     if (cache)
607     {
608         if (FcCacheTimeValid (cache, dir_stat))
609             return cache;
610         FcDirCacheUnload (cache);
611         cache = NULL;
612     }
613
614     /*
615      * Large cache files are mmap'ed, smaller cache files are read. This
616      * balances the system cost of mmap against per-process memory usage.
617      */
618     if (FcCacheIsMmapSafe (fd) && fd_stat->st_size >= FC_CACHE_MIN_MMAP)
619     {
620 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
621         cache = mmap (0, fd_stat->st_size, PROT_READ, MAP_SHARED, fd, 0);
622 #ifdef HAVE_POSIX_FADVISE
623         posix_fadvise (fd, 0, fd_stat->st_size, POSIX_FADV_WILLNEED);
624 #endif
625         if (cache == MAP_FAILED)
626             cache = NULL;
627 #elif defined(_WIN32)
628         {
629             HANDLE hFileMap;
630
631             cache = NULL;
632             hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
633                                          PAGE_READONLY, 0, 0, NULL);
634             if (hFileMap != NULL)
635             {
636                 cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0,
637                                        fd_stat->st_size);
638                 CloseHandle (hFileMap);
639             }
640         }
641 #endif
642     }
643     if (!cache)
644     {
645         cache = malloc (fd_stat->st_size);
646         if (!cache)
647             return NULL;
648
649         if (read (fd, cache, fd_stat->st_size) != fd_stat->st_size)
650         {
651             free (cache);
652             return NULL;
653         }
654         allocated = FcTrue;
655     }
656     if (cache->magic != FC_CACHE_MAGIC_MMAP ||
657         cache->version < FC_CACHE_CONTENT_VERSION ||
658         cache->size != (intptr_t) fd_stat->st_size ||
659         !FcCacheTimeValid (cache, dir_stat) ||
660         !FcCacheInsert (cache, fd_stat))
661     {
662         if (allocated)
663             free (cache);
664         else
665         {
666 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
667             munmap (cache, fd_stat->st_size);
668 #elif defined(_WIN32)
669             UnmapViewOfFile (cache);
670 #endif
671         }
672         return NULL;
673     }
674
675     /* Mark allocated caches so they're freed rather than unmapped */
676     if (allocated)
677         cache->magic = FC_CACHE_MAGIC_ALLOC;
678         
679     return cache;
680 }
681
682 void
683 FcDirCacheReference (FcCache *cache, int nref)
684 {
685     FcCacheSkip *skip = FcCacheFindByAddr (cache);
686
687     if (skip)
688         FcRefAdd (&skip->ref, nref);
689 }
690
691 void
692 FcDirCacheUnload (FcCache *cache)
693 {
694     FcCacheObjectDereference (cache);
695 }
696
697 static FcBool
698 FcDirCacheMapHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure)
699 {
700     FcCache *cache = FcDirCacheMapFd (fd, fd_stat, dir_stat);
701
702     if (!cache)
703         return FcFalse;
704     *((FcCache **) closure) = cache;
705     return FcTrue;
706 }
707
708 FcCache *
709 FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
710 {
711     FcCache *cache = NULL;
712
713     if (!FcDirCacheProcess (config, dir,
714                             FcDirCacheMapHelper,
715                             &cache, cache_file))
716         return NULL;
717     return cache;
718 }
719
720 FcCache *
721 FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
722 {
723     int fd;
724     FcCache *cache;
725     struct stat my_file_stat;
726
727     if (!file_stat)
728         file_stat = &my_file_stat;
729     fd = FcDirCacheOpenFile (cache_file, file_stat);
730     if (fd < 0)
731         return NULL;
732     cache = FcDirCacheMapFd (fd, file_stat, NULL);
733     close (fd);
734     return cache;
735 }
736
737 /*
738  * Validate a cache file by reading the header and checking
739  * the magic number and the size field
740  */
741 static FcBool
742 FcDirCacheValidateHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure FC_UNUSED)
743 {
744     FcBool  ret = FcTrue;
745     FcCache     c;
746
747     if (read (fd, &c, sizeof (FcCache)) != sizeof (FcCache))
748         ret = FcFalse;
749     else if (c.magic != FC_CACHE_MAGIC_MMAP)
750         ret = FcFalse;
751     else if (c.version < FC_CACHE_CONTENT_VERSION)
752         ret = FcFalse;
753     else if (fd_stat->st_size != c.size)
754         ret = FcFalse;
755     else if (c.checksum != (int) dir_stat->st_mtime)
756         ret = FcFalse;
757     return ret;
758 }
759
760 static FcBool
761 FcDirCacheValidConfig (const FcChar8 *dir, FcConfig *config)
762 {
763     return FcDirCacheProcess (config, dir,
764                               FcDirCacheValidateHelper,
765                               NULL, NULL);
766 }
767
768 FcBool
769 FcDirCacheValid (const FcChar8 *dir)
770 {
771     FcConfig    *config;
772
773     config = FcConfigGetCurrent ();
774     if (!config)
775         return FcFalse;
776
777     return FcDirCacheValidConfig (dir, config);
778 }
779
780 /*
781  * Build a cache structure from the given contents
782  */
783 FcCache *
784 FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs)
785 {
786     FcSerialize *serialize = FcSerializeCreate ();
787     FcCache *cache;
788     int i;
789     FcChar8     *dir_serialize;
790     intptr_t    *dirs_serialize;
791     FcFontSet   *set_serialize;
792
793     if (!serialize)
794         return NULL;
795     /*
796      * Space for cache structure
797      */
798     FcSerializeReserve (serialize, sizeof (FcCache));
799     /*
800      * Directory name
801      */
802     if (!FcStrSerializeAlloc (serialize, dir))
803         goto bail1;
804     /*
805      * Subdirs
806      */
807     FcSerializeAlloc (serialize, dirs, dirs->num * sizeof (FcChar8 *));
808     for (i = 0; i < dirs->num; i++)
809         if (!FcStrSerializeAlloc (serialize, dirs->strs[i]))
810             goto bail1;
811
812     /*
813      * Patterns
814      */
815     if (!FcFontSetSerializeAlloc (serialize, set))
816         goto bail1;
817
818     /* Serialize layout complete. Now allocate space and fill it */
819     cache = malloc (serialize->size);
820     if (!cache)
821         goto bail1;
822     /* shut up valgrind */
823     memset (cache, 0, serialize->size);
824
825     serialize->linear = cache;
826
827     cache->magic = FC_CACHE_MAGIC_ALLOC;
828     cache->version = FC_CACHE_CONTENT_VERSION;
829     cache->size = serialize->size;
830     cache->checksum = (int) dir_stat->st_mtime;
831
832     /*
833      * Serialize directory name
834      */
835     dir_serialize = FcStrSerialize (serialize, dir);
836     if (!dir_serialize)
837         goto bail2;
838     cache->dir = FcPtrToOffset (cache, dir_serialize);
839
840     /*
841      * Serialize sub dirs
842      */
843     dirs_serialize = FcSerializePtr (serialize, dirs);
844     if (!dirs_serialize)
845         goto bail2;
846     cache->dirs = FcPtrToOffset (cache, dirs_serialize);
847     cache->dirs_count = dirs->num;
848     for (i = 0; i < dirs->num; i++)
849     {
850         FcChar8 *d_serialize = FcStrSerialize (serialize, dirs->strs[i]);
851         if (!d_serialize)
852             goto bail2;
853         dirs_serialize[i] = FcPtrToOffset (dirs_serialize, d_serialize);
854     }
855
856     /*
857      * Serialize font set
858      */
859     set_serialize = FcFontSetSerialize (serialize, set);
860     if (!set_serialize)
861         goto bail2;
862     cache->set = FcPtrToOffset (cache, set_serialize);
863
864     FcSerializeDestroy (serialize);
865
866     FcCacheInsert (cache, NULL);
867
868     return cache;
869
870 bail2:
871     free (cache);
872 bail1:
873     FcSerializeDestroy (serialize);
874     return NULL;
875 }
876
877
878 #ifdef _WIN32
879 #define mkdir(path,mode) _mkdir(path)
880 #endif
881
882 static FcBool
883 FcMakeDirectory (const FcChar8 *dir)
884 {
885     FcChar8 *parent;
886     FcBool  ret;
887
888     if (strlen ((char *) dir) == 0)
889         return FcFalse;
890
891     parent = FcStrDirname (dir);
892     if (!parent)
893         return FcFalse;
894     if (access ((char *) parent, F_OK) == 0)
895         ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
896     else if (access ((char *) parent, F_OK) == -1)
897         ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
898     else
899         ret = FcFalse;
900     FcStrFree (parent);
901     return ret;
902 }
903
904 /* write serialized state to the cache file */
905 FcBool
906 FcDirCacheWrite (FcCache *cache, FcConfig *config)
907 {
908     FcChar8         *dir = FcCacheDir (cache);
909     FcChar8         cache_base[CACHEBASE_LEN];
910     FcChar8         *cache_hashed;
911     int             fd;
912     FcAtomic        *atomic;
913     FcStrList       *list;
914     FcChar8         *cache_dir = NULL;
915     FcChar8         *test_dir;
916     FcCacheSkip     *skip;
917     struct stat     cache_stat;
918     unsigned int    magic;
919     int             written;
920
921     /*
922      * Write it to the first directory in the list which is writable
923      */
924
925     list = FcStrListCreate (config->cacheDirs);
926     if (!list)
927         return FcFalse;
928     while ((test_dir = FcStrListNext (list))) {
929         if (access ((char *) test_dir, W_OK) == 0)
930         {
931             cache_dir = test_dir;
932             break;
933         }
934         else
935         {
936             /*
937              * If the directory doesn't exist, try to create it
938              */
939             if (access ((char *) test_dir, F_OK) == -1) {
940                 if (FcMakeDirectory (test_dir))
941                 {
942                     cache_dir = test_dir;
943                     /* Create CACHEDIR.TAG */
944                     FcDirCacheCreateTagFile (cache_dir);
945                     break;
946                 }
947             }
948             /*
949              * Otherwise, try making it writable
950              */
951             else if (chmod ((char *) test_dir, 0755) == 0)
952             {
953                 cache_dir = test_dir;
954                 /* Try to create CACHEDIR.TAG too */
955                 FcDirCacheCreateTagFile (cache_dir);
956                 break;
957             }
958         }
959     }
960     FcStrListDone (list);
961     if (!cache_dir)
962         return FcFalse;
963
964     FcDirCacheBasename (dir, cache_base);
965     cache_hashed = FcStrPlus (cache_dir, cache_base);
966     if (!cache_hashed)
967         return FcFalse;
968
969     if (FcDebug () & FC_DBG_CACHE)
970         printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n",
971                 dir, cache_hashed);
972
973     atomic = FcAtomicCreate ((FcChar8 *)cache_hashed);
974     if (!atomic)
975         goto bail1;
976
977     if (!FcAtomicLock (atomic))
978         goto bail3;
979
980     fd = open((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT | O_BINARY, 0666);
981     if (fd == -1)
982         goto bail4;
983
984     /* Temporarily switch magic to MMAP while writing to file */
985     magic = cache->magic;
986     if (magic != FC_CACHE_MAGIC_MMAP)
987         cache->magic = FC_CACHE_MAGIC_MMAP;
988
989     /*
990      * Write cache contents to file
991      */
992     written = write (fd, cache, cache->size);
993
994     /* Switch magic back */
995     if (magic != FC_CACHE_MAGIC_MMAP)
996         cache->magic = magic;
997
998     if (written != cache->size)
999     {
1000         perror ("write cache");
1001         goto bail5;
1002     }
1003
1004     close(fd);
1005     if (!FcAtomicReplaceOrig(atomic))
1006         goto bail4;
1007
1008     /* If the file is small, update the cache chain entry such that the
1009      * new cache file is not read again.  If it's large, we don't do that
1010      * such that we reload it, using mmap, which is shared across processes.
1011      */
1012     if (cache->size < FC_CACHE_MIN_MMAP && FcStat (cache_hashed, &cache_stat))
1013     {
1014         lock_cache ();
1015         if ((skip = FcCacheFindByAddrUnlocked (cache)))
1016         {
1017             skip->cache_dev = cache_stat.st_dev;
1018             skip->cache_ino = cache_stat.st_ino;
1019             skip->cache_mtime = cache_stat.st_mtime;
1020         }
1021         unlock_cache ();
1022     }
1023
1024     FcStrFree (cache_hashed);
1025     FcAtomicUnlock (atomic);
1026     FcAtomicDestroy (atomic);
1027     return FcTrue;
1028
1029  bail5:
1030     close (fd);
1031  bail4:
1032     FcAtomicUnlock (atomic);
1033  bail3:
1034     FcAtomicDestroy (atomic);
1035  bail1:
1036     FcStrFree (cache_hashed);
1037     return FcFalse;
1038 }
1039
1040 FcBool
1041 FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose)
1042 {
1043     DIR         *d;
1044     struct dirent *ent;
1045     FcChar8     *dir_base;
1046     FcBool      ret = FcTrue;
1047     FcBool      remove;
1048     FcCache     *cache;
1049     struct stat target_stat;
1050
1051     dir_base = FcStrPlus (cache_dir, (FcChar8 *) FC_DIR_SEPARATOR_S);
1052     if (!dir_base)
1053     {
1054         fprintf (stderr, "Fontconfig error: %s: out of memory\n", cache_dir);
1055         return FcFalse;
1056     }
1057     if (access ((char *) cache_dir, W_OK) != 0)
1058     {
1059         if (verbose || FcDebug () & FC_DBG_CACHE)
1060             printf ("%s: not cleaning %s cache directory\n", cache_dir,
1061                     access ((char *) cache_dir, F_OK) == 0 ? "unwritable" : "non-existent");
1062         goto bail0;
1063     }
1064     if (verbose || FcDebug () & FC_DBG_CACHE)
1065         printf ("%s: cleaning cache directory\n", cache_dir);
1066     d = opendir ((char *) cache_dir);
1067     if (!d)
1068     {
1069         perror ((char *) cache_dir);
1070         ret = FcFalse;
1071         goto bail0;
1072     }
1073     while ((ent = readdir (d)))
1074     {
1075         FcChar8 *file_name;
1076         const FcChar8   *target_dir;
1077
1078         if (ent->d_name[0] == '.')
1079             continue;
1080         /* skip cache files for different architectures and */
1081         /* files which are not cache files at all */
1082         if (strlen(ent->d_name) != 32 + strlen ("-" FC_ARCHITECTURE FC_CACHE_SUFFIX) ||
1083             strcmp(ent->d_name + 32, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX))
1084             continue;
1085
1086         file_name = FcStrPlus (dir_base, (FcChar8 *) ent->d_name);
1087         if (!file_name)
1088         {
1089             fprintf (stderr, "Fontconfig error: %s: allocation failure\n", cache_dir);
1090             ret = FcFalse;
1091             break;
1092         }
1093         remove = FcFalse;
1094         cache = FcDirCacheLoadFile (file_name, NULL);
1095         if (!cache)
1096         {
1097             if (verbose || FcDebug () & FC_DBG_CACHE)
1098                 printf ("%s: invalid cache file: %s\n", cache_dir, ent->d_name);
1099             remove = FcTrue;
1100         }
1101         else
1102         {
1103             target_dir = FcCacheDir (cache);
1104             if (stat ((char *) target_dir, &target_stat) < 0)
1105             {
1106                 if (verbose || FcDebug () & FC_DBG_CACHE)
1107                     printf ("%s: %s: missing directory: %s \n",
1108                             cache_dir, ent->d_name, target_dir);
1109                 remove = FcTrue;
1110             }
1111         }
1112         if (remove)
1113         {
1114             if (unlink ((char *) file_name) < 0)
1115             {
1116                 perror ((char *) file_name);
1117                 ret = FcFalse;
1118             }
1119         }
1120         FcDirCacheUnload (cache);
1121         FcStrFree (file_name);
1122     }
1123
1124     closedir (d);
1125   bail0:
1126     FcStrFree (dir_base);
1127
1128     return ret;
1129 }
1130
1131 /*
1132  * Hokey little macro trick to permit the definitions of C functions
1133  * with the same name as CPP macros
1134  */
1135 #define args1(x)            (x)
1136 #define args2(x,y)          (x,y)
1137
1138 const FcChar8 *
1139 FcCacheDir args1(const FcCache *c)
1140 {
1141     return FcCacheDir (c);
1142 }
1143
1144 FcFontSet *
1145 FcCacheCopySet args1(const FcCache *c)
1146 {
1147     FcFontSet   *old = FcCacheSet (c);
1148     FcFontSet   *new = FcFontSetCreate ();
1149     int         i;
1150
1151     if (!new)
1152         return NULL;
1153     for (i = 0; i < old->nfont; i++)
1154     {
1155         FcPattern   *font = FcFontSetFont (old, i);
1156         
1157         FcPatternReference (font);
1158         if (!FcFontSetAdd (new, font))
1159         {
1160             FcFontSetDestroy (new);
1161             return NULL;
1162         }
1163     }
1164     return new;
1165 }
1166
1167 const FcChar8 *
1168 FcCacheSubdir args2(const FcCache *c, int i)
1169 {
1170     return FcCacheSubdir (c, i);
1171 }
1172
1173 int
1174 FcCacheNumSubdir args1(const FcCache *c)
1175 {
1176     return c->dirs_count;
1177 }
1178
1179 int
1180 FcCacheNumFont args1(const FcCache *c)
1181 {
1182     return FcCacheSet(c)->nfont;
1183 }
1184
1185 /*
1186  * This code implements the MD5 message-digest algorithm.
1187  * The algorithm is due to Ron Rivest.  This code was
1188  * written by Colin Plumb in 1993, no copyright is claimed.
1189  * This code is in the public domain; do with it what you wish.
1190  *
1191  * Equivalent code is available from RSA Data Security, Inc.
1192  * This code has been tested against that, and is equivalent,
1193  * except that you don't need to include two pages of legalese
1194  * with every copy.
1195  *
1196  * To compute the message digest of a chunk of bytes, declare an
1197  * MD5Context structure, pass it to MD5Init, call MD5Update as
1198  * needed on buffers full of bytes, and then call MD5Final, which
1199  * will fill a supplied 16-byte array with the digest.
1200  */
1201
1202 #ifndef HIGHFIRST
1203 #define byteReverse(buf, len)   /* Nothing */
1204 #else
1205 /*
1206  * Note: this code is harmless on little-endian machines.
1207  */
1208 void byteReverse(unsigned char *buf, unsigned longs)
1209 {
1210     FcChar32 t;
1211     do {
1212         t = (FcChar32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
1213             ((unsigned) buf[1] << 8 | buf[0]);
1214         *(FcChar32 *) buf = t;
1215         buf += 4;
1216     } while (--longs);
1217 }
1218 #endif
1219
1220 /*
1221  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
1222  * initialization constants.
1223  */
1224 static void MD5Init(struct MD5Context *ctx)
1225 {
1226     ctx->buf[0] = 0x67452301;
1227     ctx->buf[1] = 0xefcdab89;
1228     ctx->buf[2] = 0x98badcfe;
1229     ctx->buf[3] = 0x10325476;
1230
1231     ctx->bits[0] = 0;
1232     ctx->bits[1] = 0;
1233 }
1234
1235 /*
1236  * Update context to reflect the concatenation of another buffer full
1237  * of bytes.
1238  */
1239 static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len)
1240 {
1241     FcChar32 t;
1242
1243     /* Update bitcount */
1244
1245     t = ctx->bits[0];
1246     if ((ctx->bits[0] = t + ((FcChar32) len << 3)) < t)
1247         ctx->bits[1]++;         /* Carry from low to high */
1248     ctx->bits[1] += len >> 29;
1249
1250     t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
1251
1252     /* Handle any leading odd-sized chunks */
1253
1254     if (t) {
1255         unsigned char *p = (unsigned char *) ctx->in + t;
1256
1257         t = 64 - t;
1258         if (len < t) {
1259             memcpy(p, buf, len);
1260             return;
1261         }
1262         memcpy(p, buf, t);
1263         byteReverse(ctx->in, 16);
1264         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1265         buf += t;
1266         len -= t;
1267     }
1268     /* Process data in 64-byte chunks */
1269
1270     while (len >= 64) {
1271         memcpy(ctx->in, buf, 64);
1272         byteReverse(ctx->in, 16);
1273         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1274         buf += 64;
1275         len -= 64;
1276     }
1277
1278     /* Handle any remaining bytes of data. */
1279
1280     memcpy(ctx->in, buf, len);
1281 }
1282
1283 /*
1284  * Final wrapup - pad to 64-byte boundary with the bit pattern
1285  * 1 0* (64-bit count of bits processed, MSB-first)
1286  */
1287 static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
1288 {
1289     unsigned count;
1290     unsigned char *p;
1291
1292     /* Compute number of bytes mod 64 */
1293     count = (ctx->bits[0] >> 3) & 0x3F;
1294
1295     /* Set the first char of padding to 0x80.  This is safe since there is
1296        always at least one byte free */
1297     p = ctx->in + count;
1298     *p++ = 0x80;
1299
1300     /* Bytes of padding needed to make 64 bytes */
1301     count = 64 - 1 - count;
1302
1303     /* Pad out to 56 mod 64 */
1304     if (count < 8) {
1305         /* Two lots of padding:  Pad the first block to 64 bytes */
1306         memset(p, 0, count);
1307         byteReverse(ctx->in, 16);
1308         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1309
1310         /* Now fill the next block with 56 bytes */
1311         memset(ctx->in, 0, 56);
1312     } else {
1313         /* Pad block to 56 bytes */
1314         memset(p, 0, count - 8);
1315     }
1316     byteReverse(ctx->in, 14);
1317
1318     /* Append length in bits and transform */
1319     ((FcChar32 *) ctx->in)[14] = ctx->bits[0];
1320     ((FcChar32 *) ctx->in)[15] = ctx->bits[1];
1321
1322     MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1323     byteReverse((unsigned char *) ctx->buf, 4);
1324     memcpy(digest, ctx->buf, 16);
1325     memset(ctx, 0, sizeof(*ctx));        /* In case it's sensitive */
1326 }
1327
1328
1329 /* The four core functions - F1 is optimized somewhat */
1330
1331 /* #define F1(x, y, z) (x & y | ~x & z) */
1332 #define F1(x, y, z) (z ^ (x & (y ^ z)))
1333 #define F2(x, y, z) F1(z, x, y)
1334 #define F3(x, y, z) (x ^ y ^ z)
1335 #define F4(x, y, z) (y ^ (x | ~z))
1336
1337 /* This is the central step in the MD5 algorithm. */
1338 #define MD5STEP(f, w, x, y, z, data, s) \
1339         ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
1340
1341 /*
1342  * The core of the MD5 algorithm, this alters an existing MD5 hash to
1343  * reflect the addition of 16 longwords of new data.  MD5Update blocks
1344  * the data and converts bytes into longwords for this routine.
1345  */
1346 static void MD5Transform(FcChar32 buf[4], FcChar32 in[16])
1347 {
1348     register FcChar32 a, b, c, d;
1349
1350     a = buf[0];
1351     b = buf[1];
1352     c = buf[2];
1353     d = buf[3];
1354
1355     MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1356     MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1357     MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
1358     MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1359     MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1360     MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1361     MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
1362     MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
1363     MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
1364     MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1365     MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1366     MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1367     MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
1368     MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
1369     MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
1370     MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1371
1372     MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1373     MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
1374     MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1375     MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1376     MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1377     MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
1378     MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1379     MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1380     MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1381     MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1382     MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1383     MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1384     MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1385     MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1386     MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1387     MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1388
1389     MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1390     MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
1391     MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1392     MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1393     MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1394     MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1395     MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1396     MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1397     MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1398     MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1399     MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1400     MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
1401     MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1402     MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1403     MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1404     MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1405
1406     MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
1407     MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
1408     MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1409     MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1410     MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1411     MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1412     MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1413     MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1414     MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1415     MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1416     MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
1417     MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1418     MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1419     MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1420     MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1421     MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1422
1423     buf[0] += a;
1424     buf[1] += b;
1425     buf[2] += c;
1426     buf[3] += d;
1427 }
1428
1429 FcBool
1430 FcDirCacheCreateTagFile (const FcChar8 *cache_dir)
1431 {
1432     FcChar8             *cache_tag;
1433     int                  fd;
1434     FILE                *fp;
1435     FcAtomic            *atomic;
1436     static const FcChar8 cache_tag_contents[] =
1437         "Signature: 8a477f597d28d172789f06886806bc55\n"
1438         "# This file is a cache directory tag created by fontconfig.\n"
1439         "# For information about cache directory tags, see:\n"
1440         "#       http://www.brynosaurus.com/cachedir/\n";
1441     static size_t        cache_tag_contents_size = sizeof (cache_tag_contents) - 1;
1442     FcBool               ret = FcFalse;
1443
1444     if (!cache_dir)
1445         return FcFalse;
1446
1447     if (access ((char *) cache_dir, W_OK) == 0)
1448     {
1449         /* Create CACHEDIR.TAG */
1450         cache_tag = FcStrPlus (cache_dir, (const FcChar8 *) FC_DIR_SEPARATOR_S "CACHEDIR.TAG");
1451         if (!cache_tag)
1452             return FcFalse;
1453         atomic = FcAtomicCreate ((FcChar8 *)cache_tag);
1454         if (!atomic)
1455             goto bail1;
1456         if (!FcAtomicLock (atomic))
1457             goto bail2;
1458         fd = open((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT, 0644);
1459         if (fd == -1)
1460             goto bail3;
1461         fp = fdopen(fd, "wb");
1462         if (fp == NULL)
1463             goto bail3;
1464
1465         fwrite(cache_tag_contents, cache_tag_contents_size, sizeof (FcChar8), fp);
1466         fclose(fp);
1467
1468         if (!FcAtomicReplaceOrig(atomic))
1469             goto bail3;
1470
1471         ret = FcTrue;
1472       bail3:
1473         FcAtomicUnlock (atomic);
1474       bail2:
1475         FcAtomicDestroy (atomic);
1476       bail1:
1477         FcStrFree (cache_tag);
1478     }
1479
1480     if (FcDebug () & FC_DBG_CACHE)
1481     {
1482         if (ret)
1483             printf ("Created CACHEDIR.TAG at %s\n", cache_dir);
1484         else
1485             printf ("Unable to create CACHEDIR.TAG at %s\n", cache_dir);
1486     }
1487
1488     return ret;
1489 }
1490
1491 void
1492 FcCacheCreateTagFile (const FcConfig *config)
1493 {
1494     FcChar8   *cache_dir = NULL;
1495     FcStrList *list;
1496
1497     list = FcConfigGetCacheDirs (config);
1498     if (!list)
1499         return;
1500
1501     while ((cache_dir = FcStrListNext (list)))
1502     {
1503         if (FcDirCacheCreateTagFile (cache_dir))
1504             break;
1505     }
1506     FcStrListDone (list);
1507 }
1508
1509 #define __fccache__
1510 #include "fcaliastail.h"
1511 #undef __fccache__