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