Imported Upstream version 2.10.91
[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     /*
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 #include <direct.h>
880 #define mkdir(path,mode) _mkdir(path)
881 #endif
882
883 static FcBool
884 FcMakeDirectory (const FcChar8 *dir)
885 {
886     FcChar8 *parent;
887     FcBool  ret;
888
889     if (strlen ((char *) dir) == 0)
890         return FcFalse;
891
892     parent = FcStrDirname (dir);
893     if (!parent)
894         return FcFalse;
895     if (access ((char *) parent, F_OK) == 0)
896         ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
897     else if (access ((char *) parent, F_OK) == -1)
898         ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
899     else
900         ret = FcFalse;
901     FcStrFree (parent);
902     return ret;
903 }
904
905 /* write serialized state to the cache file */
906 FcBool
907 FcDirCacheWrite (FcCache *cache, FcConfig *config)
908 {
909     FcChar8         *dir = FcCacheDir (cache);
910     FcChar8         cache_base[CACHEBASE_LEN];
911     FcChar8         *cache_hashed;
912     int             fd;
913     FcAtomic        *atomic;
914     FcStrList       *list;
915     FcChar8         *cache_dir = NULL;
916     FcChar8         *test_dir;
917     FcCacheSkip     *skip;
918     struct stat     cache_stat;
919     unsigned int    magic;
920     int             written;
921
922     /*
923      * Write it to the first directory in the list which is writable
924      */
925
926     list = FcStrListCreate (config->cacheDirs);
927     if (!list)
928         return FcFalse;
929     while ((test_dir = FcStrListNext (list))) {
930         if (access ((char *) test_dir, W_OK) == 0)
931         {
932             cache_dir = test_dir;
933             break;
934         }
935         else
936         {
937             /*
938              * If the directory doesn't exist, try to create it
939              */
940             if (access ((char *) test_dir, F_OK) == -1) {
941                 if (FcMakeDirectory (test_dir))
942                 {
943                     cache_dir = test_dir;
944                     /* Create CACHEDIR.TAG */
945                     FcDirCacheCreateTagFile (cache_dir);
946                     break;
947                 }
948             }
949             /*
950              * Otherwise, try making it writable
951              */
952             else if (chmod ((char *) test_dir, 0755) == 0)
953             {
954                 cache_dir = test_dir;
955                 /* Try to create CACHEDIR.TAG too */
956                 FcDirCacheCreateTagFile (cache_dir);
957                 break;
958             }
959         }
960     }
961     FcStrListDone (list);
962     if (!cache_dir)
963         return FcFalse;
964
965     FcDirCacheBasename (dir, cache_base);
966     cache_hashed = FcStrPlus (cache_dir, cache_base);
967     if (!cache_hashed)
968         return FcFalse;
969
970     if (FcDebug () & FC_DBG_CACHE)
971         printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n",
972                 dir, cache_hashed);
973
974     atomic = FcAtomicCreate ((FcChar8 *)cache_hashed);
975     if (!atomic)
976         goto bail1;
977
978     if (!FcAtomicLock (atomic))
979         goto bail3;
980
981     fd = FcOpen((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT | O_BINARY, 0666);
982     if (fd == -1)
983         goto bail4;
984
985     /* Temporarily switch magic to MMAP while writing to file */
986     magic = cache->magic;
987     if (magic != FC_CACHE_MAGIC_MMAP)
988         cache->magic = FC_CACHE_MAGIC_MMAP;
989
990     /*
991      * Write cache contents to file
992      */
993     written = write (fd, cache, cache->size);
994
995     /* Switch magic back */
996     if (magic != FC_CACHE_MAGIC_MMAP)
997         cache->magic = magic;
998
999     if (written != cache->size)
1000     {
1001         perror ("write cache");
1002         goto bail5;
1003     }
1004
1005     close(fd);
1006     if (!FcAtomicReplaceOrig(atomic))
1007         goto bail4;
1008
1009     /* If the file is small, update the cache chain entry such that the
1010      * new cache file is not read again.  If it's large, we don't do that
1011      * such that we reload it, using mmap, which is shared across processes.
1012      */
1013     if (cache->size < FC_CACHE_MIN_MMAP && FcStat (cache_hashed, &cache_stat))
1014     {
1015         lock_cache ();
1016         if ((skip = FcCacheFindByAddrUnlocked (cache)))
1017         {
1018             skip->cache_dev = cache_stat.st_dev;
1019             skip->cache_ino = cache_stat.st_ino;
1020             skip->cache_mtime = cache_stat.st_mtime;
1021         }
1022         unlock_cache ();
1023     }
1024
1025     FcStrFree (cache_hashed);
1026     FcAtomicUnlock (atomic);
1027     FcAtomicDestroy (atomic);
1028     return FcTrue;
1029
1030  bail5:
1031     close (fd);
1032  bail4:
1033     FcAtomicUnlock (atomic);
1034  bail3:
1035     FcAtomicDestroy (atomic);
1036  bail1:
1037     FcStrFree (cache_hashed);
1038     return FcFalse;
1039 }
1040
1041 FcBool
1042 FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose)
1043 {
1044     DIR         *d;
1045     struct dirent *ent;
1046     FcChar8     *dir_base;
1047     FcBool      ret = FcTrue;
1048     FcBool      remove;
1049     FcCache     *cache;
1050     struct stat target_stat;
1051
1052     dir_base = FcStrPlus (cache_dir, (FcChar8 *) FC_DIR_SEPARATOR_S);
1053     if (!dir_base)
1054     {
1055         fprintf (stderr, "Fontconfig error: %s: out of memory\n", cache_dir);
1056         return FcFalse;
1057     }
1058     if (access ((char *) cache_dir, W_OK) != 0)
1059     {
1060         if (verbose || FcDebug () & FC_DBG_CACHE)
1061             printf ("%s: not cleaning %s cache directory\n", cache_dir,
1062                     access ((char *) cache_dir, F_OK) == 0 ? "unwritable" : "non-existent");
1063         goto bail0;
1064     }
1065     if (verbose || FcDebug () & FC_DBG_CACHE)
1066         printf ("%s: cleaning cache directory\n", cache_dir);
1067     d = opendir ((char *) cache_dir);
1068     if (!d)
1069     {
1070         perror ((char *) cache_dir);
1071         ret = FcFalse;
1072         goto bail0;
1073     }
1074     while ((ent = readdir (d)))
1075     {
1076         FcChar8 *file_name;
1077         const FcChar8   *target_dir;
1078
1079         if (ent->d_name[0] == '.')
1080             continue;
1081         /* skip cache files for different architectures and */
1082         /* files which are not cache files at all */
1083         if (strlen(ent->d_name) != 32 + strlen ("-" FC_ARCHITECTURE FC_CACHE_SUFFIX) ||
1084             strcmp(ent->d_name + 32, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX))
1085             continue;
1086
1087         file_name = FcStrPlus (dir_base, (FcChar8 *) ent->d_name);
1088         if (!file_name)
1089         {
1090             fprintf (stderr, "Fontconfig error: %s: allocation failure\n", cache_dir);
1091             ret = FcFalse;
1092             break;
1093         }
1094         remove = FcFalse;
1095         cache = FcDirCacheLoadFile (file_name, NULL);
1096         if (!cache)
1097         {
1098             if (verbose || FcDebug () & FC_DBG_CACHE)
1099                 printf ("%s: invalid cache file: %s\n", cache_dir, ent->d_name);
1100             remove = FcTrue;
1101         }
1102         else
1103         {
1104             target_dir = FcCacheDir (cache);
1105             if (stat ((char *) target_dir, &target_stat) < 0)
1106             {
1107                 if (verbose || FcDebug () & FC_DBG_CACHE)
1108                     printf ("%s: %s: missing directory: %s \n",
1109                             cache_dir, ent->d_name, target_dir);
1110                 remove = FcTrue;
1111             }
1112         }
1113         if (remove)
1114         {
1115             if (unlink ((char *) file_name) < 0)
1116             {
1117                 perror ((char *) file_name);
1118                 ret = FcFalse;
1119             }
1120         }
1121         FcDirCacheUnload (cache);
1122         FcStrFree (file_name);
1123     }
1124
1125     closedir (d);
1126   bail0:
1127     FcStrFree (dir_base);
1128
1129     return ret;
1130 }
1131
1132 /*
1133  * Hokey little macro trick to permit the definitions of C functions
1134  * with the same name as CPP macros
1135  */
1136 #define args1(x)            (x)
1137 #define args2(x,y)          (x,y)
1138
1139 const FcChar8 *
1140 FcCacheDir args1(const FcCache *c)
1141 {
1142     return FcCacheDir (c);
1143 }
1144
1145 FcFontSet *
1146 FcCacheCopySet args1(const FcCache *c)
1147 {
1148     FcFontSet   *old = FcCacheSet (c);
1149     FcFontSet   *new = FcFontSetCreate ();
1150     int         i;
1151
1152     if (!new)
1153         return NULL;
1154     for (i = 0; i < old->nfont; i++)
1155     {
1156         FcPattern   *font = FcFontSetFont (old, i);
1157         
1158         FcPatternReference (font);
1159         if (!FcFontSetAdd (new, font))
1160         {
1161             FcFontSetDestroy (new);
1162             return NULL;
1163         }
1164     }
1165     return new;
1166 }
1167
1168 const FcChar8 *
1169 FcCacheSubdir args2(const FcCache *c, int i)
1170 {
1171     return FcCacheSubdir (c, i);
1172 }
1173
1174 int
1175 FcCacheNumSubdir args1(const FcCache *c)
1176 {
1177     return c->dirs_count;
1178 }
1179
1180 int
1181 FcCacheNumFont args1(const FcCache *c)
1182 {
1183     return FcCacheSet(c)->nfont;
1184 }
1185
1186 /*
1187  * This code implements the MD5 message-digest algorithm.
1188  * The algorithm is due to Ron Rivest.  This code was
1189  * written by Colin Plumb in 1993, no copyright is claimed.
1190  * This code is in the public domain; do with it what you wish.
1191  *
1192  * Equivalent code is available from RSA Data Security, Inc.
1193  * This code has been tested against that, and is equivalent,
1194  * except that you don't need to include two pages of legalese
1195  * with every copy.
1196  *
1197  * To compute the message digest of a chunk of bytes, declare an
1198  * MD5Context structure, pass it to MD5Init, call MD5Update as
1199  * needed on buffers full of bytes, and then call MD5Final, which
1200  * will fill a supplied 16-byte array with the digest.
1201  */
1202
1203 #ifndef HIGHFIRST
1204 #define byteReverse(buf, len)   /* Nothing */
1205 #else
1206 /*
1207  * Note: this code is harmless on little-endian machines.
1208  */
1209 void byteReverse(unsigned char *buf, unsigned longs)
1210 {
1211     FcChar32 t;
1212     do {
1213         t = (FcChar32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
1214             ((unsigned) buf[1] << 8 | buf[0]);
1215         *(FcChar32 *) buf = t;
1216         buf += 4;
1217     } while (--longs);
1218 }
1219 #endif
1220
1221 /*
1222  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
1223  * initialization constants.
1224  */
1225 static void MD5Init(struct MD5Context *ctx)
1226 {
1227     ctx->buf[0] = 0x67452301;
1228     ctx->buf[1] = 0xefcdab89;
1229     ctx->buf[2] = 0x98badcfe;
1230     ctx->buf[3] = 0x10325476;
1231
1232     ctx->bits[0] = 0;
1233     ctx->bits[1] = 0;
1234 }
1235
1236 /*
1237  * Update context to reflect the concatenation of another buffer full
1238  * of bytes.
1239  */
1240 static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len)
1241 {
1242     FcChar32 t;
1243
1244     /* Update bitcount */
1245
1246     t = ctx->bits[0];
1247     if ((ctx->bits[0] = t + ((FcChar32) len << 3)) < t)
1248         ctx->bits[1]++;         /* Carry from low to high */
1249     ctx->bits[1] += len >> 29;
1250
1251     t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
1252
1253     /* Handle any leading odd-sized chunks */
1254
1255     if (t) {
1256         unsigned char *p = (unsigned char *) ctx->in + t;
1257
1258         t = 64 - t;
1259         if (len < t) {
1260             memcpy(p, buf, len);
1261             return;
1262         }
1263         memcpy(p, buf, t);
1264         byteReverse(ctx->in, 16);
1265         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1266         buf += t;
1267         len -= t;
1268     }
1269     /* Process data in 64-byte chunks */
1270
1271     while (len >= 64) {
1272         memcpy(ctx->in, buf, 64);
1273         byteReverse(ctx->in, 16);
1274         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1275         buf += 64;
1276         len -= 64;
1277     }
1278
1279     /* Handle any remaining bytes of data. */
1280
1281     memcpy(ctx->in, buf, len);
1282 }
1283
1284 /*
1285  * Final wrapup - pad to 64-byte boundary with the bit pattern
1286  * 1 0* (64-bit count of bits processed, MSB-first)
1287  */
1288 static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
1289 {
1290     unsigned count;
1291     unsigned char *p;
1292
1293     /* Compute number of bytes mod 64 */
1294     count = (ctx->bits[0] >> 3) & 0x3F;
1295
1296     /* Set the first char of padding to 0x80.  This is safe since there is
1297        always at least one byte free */
1298     p = ctx->in + count;
1299     *p++ = 0x80;
1300
1301     /* Bytes of padding needed to make 64 bytes */
1302     count = 64 - 1 - count;
1303
1304     /* Pad out to 56 mod 64 */
1305     if (count < 8) {
1306         /* Two lots of padding:  Pad the first block to 64 bytes */
1307         memset(p, 0, count);
1308         byteReverse(ctx->in, 16);
1309         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1310
1311         /* Now fill the next block with 56 bytes */
1312         memset(ctx->in, 0, 56);
1313     } else {
1314         /* Pad block to 56 bytes */
1315         memset(p, 0, count - 8);
1316     }
1317     byteReverse(ctx->in, 14);
1318
1319     /* Append length in bits and transform */
1320     ((FcChar32 *) ctx->in)[14] = ctx->bits[0];
1321     ((FcChar32 *) ctx->in)[15] = ctx->bits[1];
1322
1323     MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1324     byteReverse((unsigned char *) ctx->buf, 4);
1325     memcpy(digest, ctx->buf, 16);
1326     memset(ctx, 0, sizeof(*ctx));        /* In case it's sensitive */
1327 }
1328
1329
1330 /* The four core functions - F1 is optimized somewhat */
1331
1332 /* #define F1(x, y, z) (x & y | ~x & z) */
1333 #define F1(x, y, z) (z ^ (x & (y ^ z)))
1334 #define F2(x, y, z) F1(z, x, y)
1335 #define F3(x, y, z) (x ^ y ^ z)
1336 #define F4(x, y, z) (y ^ (x | ~z))
1337
1338 /* This is the central step in the MD5 algorithm. */
1339 #define MD5STEP(f, w, x, y, z, data, s) \
1340         ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
1341
1342 /*
1343  * The core of the MD5 algorithm, this alters an existing MD5 hash to
1344  * reflect the addition of 16 longwords of new data.  MD5Update blocks
1345  * the data and converts bytes into longwords for this routine.
1346  */
1347 static void MD5Transform(FcChar32 buf[4], FcChar32 in[16])
1348 {
1349     register FcChar32 a, b, c, d;
1350
1351     a = buf[0];
1352     b = buf[1];
1353     c = buf[2];
1354     d = buf[3];
1355
1356     MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1357     MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1358     MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
1359     MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1360     MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1361     MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1362     MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
1363     MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
1364     MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
1365     MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1366     MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1367     MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1368     MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
1369     MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
1370     MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
1371     MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1372
1373     MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1374     MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
1375     MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1376     MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1377     MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1378     MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
1379     MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1380     MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1381     MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1382     MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1383     MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1384     MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1385     MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1386     MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1387     MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1388     MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1389
1390     MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1391     MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
1392     MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1393     MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1394     MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1395     MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1396     MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1397     MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1398     MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1399     MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1400     MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1401     MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
1402     MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1403     MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1404     MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1405     MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1406
1407     MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
1408     MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
1409     MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1410     MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1411     MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1412     MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1413     MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1414     MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1415     MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1416     MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1417     MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
1418     MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1419     MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1420     MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1421     MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1422     MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1423
1424     buf[0] += a;
1425     buf[1] += b;
1426     buf[2] += c;
1427     buf[3] += d;
1428 }
1429
1430 FcBool
1431 FcDirCacheCreateTagFile (const FcChar8 *cache_dir)
1432 {
1433     FcChar8             *cache_tag;
1434     int                  fd;
1435     FILE                *fp;
1436     FcAtomic            *atomic;
1437     static const FcChar8 cache_tag_contents[] =
1438         "Signature: 8a477f597d28d172789f06886806bc55\n"
1439         "# This file is a cache directory tag created by fontconfig.\n"
1440         "# For information about cache directory tags, see:\n"
1441         "#       http://www.brynosaurus.com/cachedir/\n";
1442     static size_t        cache_tag_contents_size = sizeof (cache_tag_contents) - 1;
1443     FcBool               ret = FcFalse;
1444
1445     if (!cache_dir)
1446         return FcFalse;
1447
1448     if (access ((char *) cache_dir, W_OK) == 0)
1449     {
1450         /* Create CACHEDIR.TAG */
1451         cache_tag = FcStrPlus (cache_dir, (const FcChar8 *) FC_DIR_SEPARATOR_S "CACHEDIR.TAG");
1452         if (!cache_tag)
1453             return FcFalse;
1454         atomic = FcAtomicCreate ((FcChar8 *)cache_tag);
1455         if (!atomic)
1456             goto bail1;
1457         if (!FcAtomicLock (atomic))
1458             goto bail2;
1459         fd = FcOpen((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT, 0644);
1460         if (fd == -1)
1461             goto bail3;
1462         fp = fdopen(fd, "wb");
1463         if (fp == NULL)
1464             goto bail3;
1465
1466         fwrite(cache_tag_contents, cache_tag_contents_size, sizeof (FcChar8), fp);
1467         fclose(fp);
1468
1469         if (!FcAtomicReplaceOrig(atomic))
1470             goto bail3;
1471
1472         ret = FcTrue;
1473       bail3:
1474         FcAtomicUnlock (atomic);
1475       bail2:
1476         FcAtomicDestroy (atomic);
1477       bail1:
1478         FcStrFree (cache_tag);
1479     }
1480
1481     if (FcDebug () & FC_DBG_CACHE)
1482     {
1483         if (ret)
1484             printf ("Created CACHEDIR.TAG at %s\n", cache_dir);
1485         else
1486             printf ("Unable to create CACHEDIR.TAG at %s\n", cache_dir);
1487     }
1488
1489     return ret;
1490 }
1491
1492 void
1493 FcCacheCreateTagFile (const FcConfig *config)
1494 {
1495     FcChar8   *cache_dir = NULL;
1496     FcStrList *list;
1497
1498     list = FcConfigGetCacheDirs (config);
1499     if (!list)
1500         return;
1501
1502     while ((cache_dir = FcStrListNext (list)))
1503     {
1504         if (FcDirCacheCreateTagFile (cache_dir))
1505             break;
1506     }
1507     FcStrListDone (list);
1508 }
1509
1510 #define __fccache__
1511 #include "fcaliastail.h"
1512 #undef __fccache__