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