Imported Upstream version 2.12.1
[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
644             if ((char *) font < base ||
645                 (char *) font > end - sizeof (FcFontSet) ||
646                 font->elts_offset < 0 ||
647                 font->elts_offset > end - (char *) font ||
648                 font->num > (end - (char *) font - font->elts_offset) / sizeof (FcPatternElt))
649                 return FcFalse;
650
651
652             e = FcPatternElts(font);
653             if (e->values != 0 && !FcIsEncodedOffset(e->values))
654                 return FcFalse;
655
656             for (j = font->num, l = FcPatternEltValues(e); j >= 0 && l; j--, l = FcValueListNext(l))
657                 if (l->next != NULL && !FcIsEncodedOffset(l->next))
658                     break;
659             if (j < 0)
660                 return FcFalse;
661         }
662     }
663
664     return FcTrue;
665 }
666
667 /*
668  * Map a cache file into memory
669  */
670 static FcCache *
671 FcDirCacheMapFd (FcConfig *config, int fd, struct stat *fd_stat, struct stat *dir_stat)
672 {
673     FcCache     *cache;
674     FcBool      allocated = FcFalse;
675
676     if (fd_stat->st_size > INTPTR_MAX ||
677         fd_stat->st_size < (int) sizeof (FcCache))
678         return NULL;
679     cache = FcCacheFindByStat (fd_stat);
680     if (cache)
681     {
682         if (FcCacheTimeValid (config, cache, dir_stat))
683             return cache;
684         FcDirCacheUnload (cache);
685         cache = NULL;
686     }
687
688     /*
689      * Large cache files are mmap'ed, smaller cache files are read. This
690      * balances the system cost of mmap against per-process memory usage.
691      */
692     if (FcCacheIsMmapSafe (fd) && fd_stat->st_size >= FC_CACHE_MIN_MMAP)
693     {
694 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
695         cache = mmap (0, fd_stat->st_size, PROT_READ, MAP_SHARED, fd, 0);
696 #if (HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
697         posix_fadvise (fd, 0, fd_stat->st_size, POSIX_FADV_WILLNEED);
698 #endif
699         if (cache == MAP_FAILED)
700             cache = NULL;
701 #elif defined(_WIN32)
702         {
703             HANDLE hFileMap;
704
705             cache = NULL;
706             hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
707                                          PAGE_READONLY, 0, 0, NULL);
708             if (hFileMap != NULL)
709             {
710                 cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0,
711                                        fd_stat->st_size);
712                 CloseHandle (hFileMap);
713             }
714         }
715 #endif
716     }
717     if (!cache)
718     {
719         cache = malloc (fd_stat->st_size);
720         if (!cache)
721             return NULL;
722
723         if (read (fd, cache, fd_stat->st_size) != fd_stat->st_size)
724         {
725             free (cache);
726             return NULL;
727         }
728         allocated = FcTrue;
729     }
730     if (cache->magic != FC_CACHE_MAGIC_MMAP ||
731         cache->version < FC_CACHE_VERSION_NUMBER ||
732         cache->size != (intptr_t) fd_stat->st_size ||
733         !FcCacheOffsetsValid (cache) ||
734         !FcCacheTimeValid (config, cache, dir_stat) ||
735         !FcCacheInsert (cache, fd_stat))
736     {
737         if (allocated)
738             free (cache);
739         else
740         {
741 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
742             munmap (cache, fd_stat->st_size);
743 #elif defined(_WIN32)
744             UnmapViewOfFile (cache);
745 #endif
746         }
747         return NULL;
748     }
749
750     /* Mark allocated caches so they're freed rather than unmapped */
751     if (allocated)
752         cache->magic = FC_CACHE_MAGIC_ALLOC;
753         
754     return cache;
755 }
756
757 void
758 FcDirCacheReference (FcCache *cache, int nref)
759 {
760     FcCacheSkip *skip = FcCacheFindByAddr (cache);
761
762     if (skip)
763         FcRefAdd (&skip->ref, nref);
764 }
765
766 void
767 FcDirCacheUnload (FcCache *cache)
768 {
769     FcCacheObjectDereference (cache);
770 }
771
772 static FcBool
773 FcDirCacheMapHelper (FcConfig *config, int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure)
774 {
775     FcCache *cache = FcDirCacheMapFd (config, fd, fd_stat, dir_stat);
776
777     if (!cache)
778         return FcFalse;
779     *((FcCache **) closure) = cache;
780     return FcTrue;
781 }
782
783 FcCache *
784 FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
785 {
786     FcCache *cache = NULL;
787
788     if (!FcDirCacheProcess (config, dir,
789                             FcDirCacheMapHelper,
790                             &cache, cache_file))
791         return NULL;
792
793     return cache;
794 }
795
796 FcCache *
797 FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
798 {
799     int fd;
800     FcCache *cache;
801     struct stat my_file_stat;
802
803     if (!file_stat)
804         file_stat = &my_file_stat;
805     fd = FcDirCacheOpenFile (cache_file, file_stat);
806     if (fd < 0)
807         return NULL;
808     cache = FcDirCacheMapFd (FcConfigGetCurrent (), fd, file_stat, NULL);
809     close (fd);
810     return cache;
811 }
812
813 /*
814  * Validate a cache file by reading the header and checking
815  * the magic number and the size field
816  */
817 static FcBool
818 FcDirCacheValidateHelper (FcConfig *config, int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure FC_UNUSED)
819 {
820     FcBool  ret = FcTrue;
821     FcCache     c;
822
823     if (read (fd, &c, sizeof (FcCache)) != sizeof (FcCache))
824         ret = FcFalse;
825     else if (c.magic != FC_CACHE_MAGIC_MMAP)
826         ret = FcFalse;
827     else if (c.version < FC_CACHE_VERSION_NUMBER)
828         ret = FcFalse;
829     else if (fd_stat->st_size != c.size)
830         ret = FcFalse;
831     else if (c.checksum != (int) dir_stat->st_mtime)
832         ret = FcFalse;
833 #ifdef HAVE_STRUCT_STAT_ST_MTIM
834     else if (c.checksum_nano != dir_stat->st_mtim.tv_nsec)
835         ret = FcFalse;
836 #endif
837     return ret;
838 }
839
840 static FcBool
841 FcDirCacheValidConfig (const FcChar8 *dir, FcConfig *config)
842 {
843     return FcDirCacheProcess (config, dir,
844                               FcDirCacheValidateHelper,
845                               NULL, NULL);
846 }
847
848 FcBool
849 FcDirCacheValid (const FcChar8 *dir)
850 {
851     FcConfig    *config;
852
853     config = FcConfigGetCurrent ();
854     if (!config)
855         return FcFalse;
856
857     return FcDirCacheValidConfig (dir, config);
858 }
859
860 /*
861  * Build a cache structure from the given contents
862  */
863 FcCache *
864 FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs)
865 {
866     FcSerialize *serialize = FcSerializeCreate ();
867     FcCache *cache;
868     int i;
869     FcChar8     *dir_serialize;
870     intptr_t    *dirs_serialize;
871     FcFontSet   *set_serialize;
872
873     if (!serialize)
874         return NULL;
875     /*
876      * Space for cache structure
877      */
878     FcSerializeReserve (serialize, sizeof (FcCache));
879     /*
880      * Directory name
881      */
882     if (!FcStrSerializeAlloc (serialize, dir))
883         goto bail1;
884     /*
885      * Subdirs
886      */
887     FcSerializeAlloc (serialize, dirs, dirs->num * sizeof (FcChar8 *));
888     for (i = 0; i < dirs->num; i++)
889         if (!FcStrSerializeAlloc (serialize, dirs->strs[i]))
890             goto bail1;
891
892     /*
893      * Patterns
894      */
895     if (!FcFontSetSerializeAlloc (serialize, set))
896         goto bail1;
897
898     /* Serialize layout complete. Now allocate space and fill it */
899     cache = malloc (serialize->size);
900     if (!cache)
901         goto bail1;
902     /* shut up valgrind */
903     memset (cache, 0, serialize->size);
904
905     serialize->linear = cache;
906
907     cache->magic = FC_CACHE_MAGIC_ALLOC;
908     cache->version = FC_CACHE_VERSION_NUMBER;
909     cache->size = serialize->size;
910     cache->checksum = (int) dir_stat->st_mtime;
911 #ifdef HAVE_STRUCT_STAT_ST_MTIM
912     cache->checksum_nano = dir_stat->st_mtim.tv_nsec;
913 #endif
914
915     /*
916      * Serialize directory name
917      */
918     dir_serialize = FcStrSerialize (serialize, dir);
919     if (!dir_serialize)
920         goto bail2;
921     cache->dir = FcPtrToOffset (cache, dir_serialize);
922
923     /*
924      * Serialize sub dirs
925      */
926     dirs_serialize = FcSerializePtr (serialize, dirs);
927     if (!dirs_serialize)
928         goto bail2;
929     cache->dirs = FcPtrToOffset (cache, dirs_serialize);
930     cache->dirs_count = dirs->num;
931     for (i = 0; i < dirs->num; i++)
932     {
933         FcChar8 *d_serialize = FcStrSerialize (serialize, dirs->strs[i]);
934         if (!d_serialize)
935             goto bail2;
936         dirs_serialize[i] = FcPtrToOffset (dirs_serialize, d_serialize);
937     }
938
939     /*
940      * Serialize font set
941      */
942     set_serialize = FcFontSetSerialize (serialize, set);
943     if (!set_serialize)
944         goto bail2;
945     cache->set = FcPtrToOffset (cache, set_serialize);
946
947     FcSerializeDestroy (serialize);
948
949     FcCacheInsert (cache, NULL);
950
951     return cache;
952
953 bail2:
954     free (cache);
955 bail1:
956     FcSerializeDestroy (serialize);
957     return NULL;
958 }
959
960 FcCache *
961 FcDirCacheRebuild (FcCache *cache, struct stat *dir_stat, FcStrSet *dirs)
962 {
963     FcCache *new;
964     FcFontSet *set = FcFontSetDeserialize (FcCacheSet (cache));
965     const FcChar8 *dir = FcCacheDir (cache);
966
967     new = FcDirCacheBuild (set, dir, dir_stat, dirs);
968     FcFontSetDestroy (set);
969
970     return new;
971 }
972
973 /* write serialized state to the cache file */
974 FcBool
975 FcDirCacheWrite (FcCache *cache, FcConfig *config)
976 {
977     FcChar8         *dir = FcCacheDir (cache);
978     FcChar8         cache_base[CACHEBASE_LEN];
979     FcChar8         *cache_hashed;
980     int             fd;
981     FcAtomic        *atomic;
982     FcStrList       *list;
983     FcChar8         *cache_dir = NULL;
984     FcChar8         *test_dir, *d = NULL;
985     FcCacheSkip     *skip;
986     struct stat     cache_stat;
987     unsigned int    magic;
988     int             written;
989     const FcChar8   *sysroot = FcConfigGetSysRoot (config);
990
991     /*
992      * Write it to the first directory in the list which is writable
993      */
994
995     list = FcStrListCreate (config->cacheDirs);
996     if (!list)
997         return FcFalse;
998     while ((test_dir = FcStrListNext (list)))
999     {
1000         if (d)
1001             FcStrFree (d);
1002         if (sysroot)
1003             d = FcStrBuildFilename (sysroot, test_dir, NULL);
1004         else
1005             d = FcStrCopyFilename (test_dir);
1006
1007         if (access ((char *) d, W_OK) == 0)
1008         {
1009             cache_dir = FcStrCopyFilename (d);
1010             break;
1011         }
1012         else
1013         {
1014             /*
1015              * If the directory doesn't exist, try to create it
1016              */
1017             if (access ((char *) d, F_OK) == -1) {
1018                 if (FcMakeDirectory (d))
1019                 {
1020                     cache_dir = FcStrCopyFilename (d);
1021                     /* Create CACHEDIR.TAG */
1022                     FcDirCacheCreateTagFile (d);
1023                     break;
1024                 }
1025             }
1026             /*
1027              * Otherwise, try making it writable
1028              */
1029             else if (chmod ((char *) d, 0755) == 0)
1030             {
1031                 cache_dir = FcStrCopyFilename (d);
1032                 /* Try to create CACHEDIR.TAG too */
1033                 FcDirCacheCreateTagFile (d);
1034                 break;
1035             }
1036         }
1037     }
1038     if (d)
1039         FcStrFree (d);
1040     FcStrListDone (list);
1041     if (!cache_dir)
1042         return FcFalse;
1043
1044     FcDirCacheBasename (dir, cache_base);
1045     cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL);
1046     if (!cache_hashed)
1047         return FcFalse;
1048     FcStrFree (cache_dir);
1049
1050     if (FcDebug () & FC_DBG_CACHE)
1051         printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n",
1052                 dir, cache_hashed);
1053
1054     atomic = FcAtomicCreate ((FcChar8 *)cache_hashed);
1055     if (!atomic)
1056         goto bail1;
1057
1058     if (!FcAtomicLock (atomic))
1059         goto bail3;
1060
1061     fd = FcOpen((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT | O_BINARY, 0666);
1062     if (fd == -1)
1063         goto bail4;
1064
1065     /* Temporarily switch magic to MMAP while writing to file */
1066     magic = cache->magic;
1067     if (magic != FC_CACHE_MAGIC_MMAP)
1068         cache->magic = FC_CACHE_MAGIC_MMAP;
1069
1070     /*
1071      * Write cache contents to file
1072      */
1073     written = write (fd, cache, cache->size);
1074
1075     /* Switch magic back */
1076     if (magic != FC_CACHE_MAGIC_MMAP)
1077         cache->magic = magic;
1078
1079     if (written != cache->size)
1080     {
1081         perror ("write cache");
1082         goto bail5;
1083     }
1084
1085     close(fd);
1086     if (!FcAtomicReplaceOrig(atomic))
1087         goto bail4;
1088
1089     /* If the file is small, update the cache chain entry such that the
1090      * new cache file is not read again.  If it's large, we don't do that
1091      * such that we reload it, using mmap, which is shared across processes.
1092      */
1093     if (cache->size < FC_CACHE_MIN_MMAP && FcStat (cache_hashed, &cache_stat))
1094     {
1095         lock_cache ();
1096         if ((skip = FcCacheFindByAddrUnlocked (cache)))
1097         {
1098             skip->cache_dev = cache_stat.st_dev;
1099             skip->cache_ino = cache_stat.st_ino;
1100             skip->cache_mtime = cache_stat.st_mtime;
1101 #ifdef HAVE_STRUCT_STAT_ST_MTIM
1102             skip->cache_mtime_nano = cache_stat.st_mtim.tv_nsec;
1103 #else
1104             skip->cache_mtime_nano = 0;
1105 #endif
1106         }
1107         unlock_cache ();
1108     }
1109
1110     FcStrFree (cache_hashed);
1111     FcAtomicUnlock (atomic);
1112     FcAtomicDestroy (atomic);
1113     return FcTrue;
1114
1115  bail5:
1116     close (fd);
1117  bail4:
1118     FcAtomicUnlock (atomic);
1119  bail3:
1120     FcAtomicDestroy (atomic);
1121  bail1:
1122     FcStrFree (cache_hashed);
1123     return FcFalse;
1124 }
1125
1126 FcBool
1127 FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose)
1128 {
1129     DIR         *d;
1130     struct dirent *ent;
1131     FcChar8     *dir;
1132     FcBool      ret = FcTrue;
1133     FcBool      remove;
1134     FcCache     *cache;
1135     struct stat target_stat;
1136     const FcChar8 *sysroot;
1137
1138     /* FIXME: this API needs to support non-current FcConfig */
1139     sysroot = FcConfigGetSysRoot (NULL);
1140     if (sysroot)
1141         dir = FcStrBuildFilename (sysroot, cache_dir, NULL);
1142     else
1143         dir = FcStrCopyFilename (cache_dir);
1144     if (!dir)
1145     {
1146         fprintf (stderr, "Fontconfig error: %s: out of memory\n", cache_dir);
1147         return FcFalse;
1148     }
1149     if (access ((char *) dir, W_OK) != 0)
1150     {
1151         if (verbose || FcDebug () & FC_DBG_CACHE)
1152             printf ("%s: not cleaning %s cache directory\n", dir,
1153                     access ((char *) dir, F_OK) == 0 ? "unwritable" : "non-existent");
1154         goto bail0;
1155     }
1156     if (verbose || FcDebug () & FC_DBG_CACHE)
1157         printf ("%s: cleaning cache directory\n", dir);
1158     d = opendir ((char *) dir);
1159     if (!d)
1160     {
1161         perror ((char *) dir);
1162         ret = FcFalse;
1163         goto bail0;
1164     }
1165     while ((ent = readdir (d)))
1166     {
1167         FcChar8 *file_name;
1168         const FcChar8   *target_dir;
1169
1170         if (ent->d_name[0] == '.')
1171             continue;
1172         /* skip cache files for different architectures and */
1173         /* files which are not cache files at all */
1174         if (strlen(ent->d_name) != 32 + strlen ("-" FC_ARCHITECTURE FC_CACHE_SUFFIX) ||
1175             strcmp(ent->d_name + 32, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX))
1176             continue;
1177
1178         file_name = FcStrBuildFilename (dir, (FcChar8 *)ent->d_name, NULL);
1179         if (!file_name)
1180         {
1181             fprintf (stderr, "Fontconfig error: %s: allocation failure\n", dir);
1182             ret = FcFalse;
1183             break;
1184         }
1185         remove = FcFalse;
1186         cache = FcDirCacheLoadFile (file_name, NULL);
1187         if (!cache)
1188         {
1189             if (verbose || FcDebug () & FC_DBG_CACHE)
1190                 printf ("%s: invalid cache file: %s\n", dir, ent->d_name);
1191             remove = FcTrue;
1192         }
1193         else
1194         {
1195             FcChar8 *s;
1196
1197             target_dir = FcCacheDir (cache);
1198             if (sysroot)
1199                 s = FcStrBuildFilename (sysroot, target_dir, NULL);
1200             else
1201                 s = FcStrdup (target_dir);
1202             if (stat ((char *) s, &target_stat) < 0)
1203             {
1204                 if (verbose || FcDebug () & FC_DBG_CACHE)
1205                     printf ("%s: %s: missing directory: %s \n",
1206                             dir, ent->d_name, s);
1207                 remove = FcTrue;
1208             }
1209             FcDirCacheUnload (cache);
1210             FcStrFree (s);
1211         }
1212         if (remove)
1213         {
1214             if (unlink ((char *) file_name) < 0)
1215             {
1216                 perror ((char *) file_name);
1217                 ret = FcFalse;
1218             }
1219         }
1220         FcStrFree (file_name);
1221     }
1222
1223     closedir (d);
1224   bail0:
1225     FcStrFree (dir);
1226
1227     return ret;
1228 }
1229
1230 int
1231 FcDirCacheLock (const FcChar8 *dir,
1232                 FcConfig      *config)
1233 {
1234     FcChar8 *cache_hashed = NULL;
1235     FcChar8 cache_base[CACHEBASE_LEN];
1236     FcStrList *list;
1237     FcChar8 *cache_dir;
1238     const FcChar8 *sysroot = FcConfigGetSysRoot (config);
1239     int fd = -1;
1240
1241     FcDirCacheBasename (dir, cache_base);
1242     list = FcStrListCreate (config->cacheDirs);
1243     if (!list)
1244         return -1;
1245
1246     while ((cache_dir = FcStrListNext (list)))
1247     {
1248         if (sysroot)
1249             cache_hashed = FcStrBuildFilename (sysroot, cache_dir, cache_base, NULL);
1250         else
1251             cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL);
1252         if (!cache_hashed)
1253             break;
1254         fd = FcOpen ((const char *)cache_hashed, O_RDWR);
1255         FcStrFree (cache_hashed);
1256         /* No caches in that directory. simply retry with another one */
1257         if (fd != -1)
1258         {
1259 #if defined(_WIN32)
1260             if (_locking (fd, _LK_LOCK, 1) == -1)
1261                 goto bail;
1262 #else
1263             struct flock fl;
1264
1265             fl.l_type = F_WRLCK;
1266             fl.l_whence = SEEK_SET;
1267             fl.l_start = 0;
1268             fl.l_len = 0;
1269             fl.l_pid = getpid ();
1270             if (fcntl (fd, F_SETLKW, &fl) == -1)
1271                 goto bail;
1272 #endif
1273             break;
1274         }
1275     }
1276     FcStrListDone (list);
1277     return fd;
1278 bail:
1279     FcStrListDone (list);
1280     if (fd != -1)
1281         close (fd);
1282     return -1;
1283 }
1284
1285 void
1286 FcDirCacheUnlock (int fd)
1287 {
1288     if (fd != -1)
1289     {
1290 #if defined(_WIN32)
1291         _locking (fd, _LK_UNLCK, 1);
1292 #else
1293         struct flock fl;
1294
1295         fl.l_type = F_UNLCK;
1296         fl.l_whence = SEEK_SET;
1297         fl.l_start = 0;
1298         fl.l_len = 0;
1299         fl.l_pid = getpid ();
1300         fcntl (fd, F_SETLK, &fl);
1301 #endif
1302         close (fd);
1303     }
1304 }
1305
1306 /*
1307  * Hokey little macro trick to permit the definitions of C functions
1308  * with the same name as CPP macros
1309  */
1310 #define args1(x)            (x)
1311 #define args2(x,y)          (x,y)
1312
1313 const FcChar8 *
1314 FcCacheDir args1(const FcCache *c)
1315 {
1316     return FcCacheDir (c);
1317 }
1318
1319 FcFontSet *
1320 FcCacheCopySet args1(const FcCache *c)
1321 {
1322     FcFontSet   *old = FcCacheSet (c);
1323     FcFontSet   *new = FcFontSetCreate ();
1324     int         i;
1325
1326     if (!new)
1327         return NULL;
1328     for (i = 0; i < old->nfont; i++)
1329     {
1330         FcPattern   *font = FcFontSetFont (old, i);
1331         
1332         FcPatternReference (font);
1333         if (!FcFontSetAdd (new, font))
1334         {
1335             FcFontSetDestroy (new);
1336             return NULL;
1337         }
1338     }
1339     return new;
1340 }
1341
1342 const FcChar8 *
1343 FcCacheSubdir args2(const FcCache *c, int i)
1344 {
1345     return FcCacheSubdir (c, i);
1346 }
1347
1348 int
1349 FcCacheNumSubdir args1(const FcCache *c)
1350 {
1351     return c->dirs_count;
1352 }
1353
1354 int
1355 FcCacheNumFont args1(const FcCache *c)
1356 {
1357     return FcCacheSet(c)->nfont;
1358 }
1359
1360 /*
1361  * This code implements the MD5 message-digest algorithm.
1362  * The algorithm is due to Ron Rivest.  This code was
1363  * written by Colin Plumb in 1993, no copyright is claimed.
1364  * This code is in the public domain; do with it what you wish.
1365  *
1366  * Equivalent code is available from RSA Data Security, Inc.
1367  * This code has been tested against that, and is equivalent,
1368  * except that you don't need to include two pages of legalese
1369  * with every copy.
1370  *
1371  * To compute the message digest of a chunk of bytes, declare an
1372  * MD5Context structure, pass it to MD5Init, call MD5Update as
1373  * needed on buffers full of bytes, and then call MD5Final, which
1374  * will fill a supplied 16-byte array with the digest.
1375  */
1376
1377 #ifndef HIGHFIRST
1378 #define byteReverse(buf, len)   /* Nothing */
1379 #else
1380 /*
1381  * Note: this code is harmless on little-endian machines.
1382  */
1383 void byteReverse(unsigned char *buf, unsigned longs)
1384 {
1385     FcChar32 t;
1386     do {
1387         t = (FcChar32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
1388             ((unsigned) buf[1] << 8 | buf[0]);
1389         *(FcChar32 *) buf = t;
1390         buf += 4;
1391     } while (--longs);
1392 }
1393 #endif
1394
1395 /*
1396  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
1397  * initialization constants.
1398  */
1399 static void MD5Init(struct MD5Context *ctx)
1400 {
1401     ctx->buf[0] = 0x67452301;
1402     ctx->buf[1] = 0xefcdab89;
1403     ctx->buf[2] = 0x98badcfe;
1404     ctx->buf[3] = 0x10325476;
1405
1406     ctx->bits[0] = 0;
1407     ctx->bits[1] = 0;
1408 }
1409
1410 /*
1411  * Update context to reflect the concatenation of another buffer full
1412  * of bytes.
1413  */
1414 static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len)
1415 {
1416     FcChar32 t;
1417
1418     /* Update bitcount */
1419
1420     t = ctx->bits[0];
1421     if ((ctx->bits[0] = t + ((FcChar32) len << 3)) < t)
1422         ctx->bits[1]++;         /* Carry from low to high */
1423     ctx->bits[1] += len >> 29;
1424
1425     t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
1426
1427     /* Handle any leading odd-sized chunks */
1428
1429     if (t) {
1430         unsigned char *p = (unsigned char *) ctx->in + t;
1431
1432         t = 64 - t;
1433         if (len < t) {
1434             memcpy(p, buf, len);
1435             return;
1436         }
1437         memcpy(p, buf, t);
1438         byteReverse(ctx->in, 16);
1439         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1440         buf += t;
1441         len -= t;
1442     }
1443     /* Process data in 64-byte chunks */
1444
1445     while (len >= 64) {
1446         memcpy(ctx->in, buf, 64);
1447         byteReverse(ctx->in, 16);
1448         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1449         buf += 64;
1450         len -= 64;
1451     }
1452
1453     /* Handle any remaining bytes of data. */
1454
1455     memcpy(ctx->in, buf, len);
1456 }
1457
1458 /*
1459  * Final wrapup - pad to 64-byte boundary with the bit pattern
1460  * 1 0* (64-bit count of bits processed, MSB-first)
1461  */
1462 static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
1463 {
1464     unsigned count;
1465     unsigned char *p;
1466
1467     /* Compute number of bytes mod 64 */
1468     count = (ctx->bits[0] >> 3) & 0x3F;
1469
1470     /* Set the first char of padding to 0x80.  This is safe since there is
1471        always at least one byte free */
1472     p = ctx->in + count;
1473     *p++ = 0x80;
1474
1475     /* Bytes of padding needed to make 64 bytes */
1476     count = 64 - 1 - count;
1477
1478     /* Pad out to 56 mod 64 */
1479     if (count < 8) {
1480         /* Two lots of padding:  Pad the first block to 64 bytes */
1481         memset(p, 0, count);
1482         byteReverse(ctx->in, 16);
1483         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1484
1485         /* Now fill the next block with 56 bytes */
1486         memset(ctx->in, 0, 56);
1487     } else {
1488         /* Pad block to 56 bytes */
1489         memset(p, 0, count - 8);
1490     }
1491     byteReverse(ctx->in, 14);
1492
1493     /* Append length in bits and transform */
1494     ((FcChar32 *) ctx->in)[14] = ctx->bits[0];
1495     ((FcChar32 *) ctx->in)[15] = ctx->bits[1];
1496
1497     MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1498     byteReverse((unsigned char *) ctx->buf, 4);
1499     memcpy(digest, ctx->buf, 16);
1500     memset(ctx, 0, sizeof(*ctx));        /* In case it's sensitive */
1501 }
1502
1503
1504 /* The four core functions - F1 is optimized somewhat */
1505
1506 /* #define F1(x, y, z) (x & y | ~x & z) */
1507 #define F1(x, y, z) (z ^ (x & (y ^ z)))
1508 #define F2(x, y, z) F1(z, x, y)
1509 #define F3(x, y, z) (x ^ y ^ z)
1510 #define F4(x, y, z) (y ^ (x | ~z))
1511
1512 /* This is the central step in the MD5 algorithm. */
1513 #define MD5STEP(f, w, x, y, z, data, s) \
1514         ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
1515
1516 /*
1517  * The core of the MD5 algorithm, this alters an existing MD5 hash to
1518  * reflect the addition of 16 longwords of new data.  MD5Update blocks
1519  * the data and converts bytes into longwords for this routine.
1520  */
1521 static void MD5Transform(FcChar32 buf[4], FcChar32 in[16])
1522 {
1523     register FcChar32 a, b, c, d;
1524
1525     a = buf[0];
1526     b = buf[1];
1527     c = buf[2];
1528     d = buf[3];
1529
1530     MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1531     MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1532     MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
1533     MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1534     MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1535     MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1536     MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
1537     MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
1538     MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
1539     MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1540     MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1541     MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1542     MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
1543     MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
1544     MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
1545     MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1546
1547     MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1548     MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
1549     MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1550     MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1551     MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1552     MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
1553     MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1554     MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1555     MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1556     MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1557     MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1558     MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1559     MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1560     MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1561     MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1562     MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1563
1564     MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1565     MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
1566     MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1567     MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1568     MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1569     MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1570     MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1571     MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1572     MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1573     MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1574     MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1575     MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
1576     MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1577     MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1578     MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1579     MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1580
1581     MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
1582     MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
1583     MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1584     MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1585     MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1586     MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1587     MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1588     MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1589     MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1590     MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1591     MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
1592     MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1593     MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1594     MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1595     MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1596     MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1597
1598     buf[0] += a;
1599     buf[1] += b;
1600     buf[2] += c;
1601     buf[3] += d;
1602 }
1603
1604 FcBool
1605 FcDirCacheCreateTagFile (const FcChar8 *cache_dir)
1606 {
1607     FcChar8             *cache_tag;
1608     int                  fd;
1609     FILE                *fp;
1610     FcAtomic            *atomic;
1611     static const FcChar8 cache_tag_contents[] =
1612         "Signature: 8a477f597d28d172789f06886806bc55\n"
1613         "# This file is a cache directory tag created by fontconfig.\n"
1614         "# For information about cache directory tags, see:\n"
1615         "#       http://www.brynosaurus.com/cachedir/\n";
1616     static size_t        cache_tag_contents_size = sizeof (cache_tag_contents) - 1;
1617     FcBool               ret = FcFalse;
1618
1619     if (!cache_dir)
1620         return FcFalse;
1621
1622     if (access ((char *) cache_dir, W_OK) == 0)
1623     {
1624         /* Create CACHEDIR.TAG */
1625         cache_tag = FcStrBuildFilename (cache_dir, "CACHEDIR.TAG", NULL);
1626         if (!cache_tag)
1627             return FcFalse;
1628         atomic = FcAtomicCreate ((FcChar8 *)cache_tag);
1629         if (!atomic)
1630             goto bail1;
1631         if (!FcAtomicLock (atomic))
1632             goto bail2;
1633         fd = FcOpen((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT, 0644);
1634         if (fd == -1)
1635             goto bail3;
1636         fp = fdopen(fd, "wb");
1637         if (fp == NULL)
1638             goto bail3;
1639
1640         fwrite(cache_tag_contents, cache_tag_contents_size, sizeof (FcChar8), fp);
1641         fclose(fp);
1642
1643         if (!FcAtomicReplaceOrig(atomic))
1644             goto bail3;
1645
1646         ret = FcTrue;
1647       bail3:
1648         FcAtomicUnlock (atomic);
1649       bail2:
1650         FcAtomicDestroy (atomic);
1651       bail1:
1652         FcStrFree (cache_tag);
1653     }
1654
1655     if (FcDebug () & FC_DBG_CACHE)
1656     {
1657         if (ret)
1658             printf ("Created CACHEDIR.TAG at %s\n", cache_dir);
1659         else
1660             printf ("Unable to create CACHEDIR.TAG at %s\n", cache_dir);
1661     }
1662
1663     return ret;
1664 }
1665
1666 void
1667 FcCacheCreateTagFile (const FcConfig *config)
1668 {
1669     FcChar8   *cache_dir = NULL, *d = NULL;
1670     FcStrList *list;
1671     const FcChar8 *sysroot = FcConfigGetSysRoot (config);
1672
1673     list = FcConfigGetCacheDirs (config);
1674     if (!list)
1675         return;
1676
1677     while ((cache_dir = FcStrListNext (list)))
1678     {
1679         if (d)
1680             FcStrFree (d);
1681         if (sysroot)
1682             d = FcStrBuildFilename (sysroot, cache_dir, NULL);
1683         else
1684             d = FcStrCopyFilename (cache_dir);
1685         if (FcDirCacheCreateTagFile (d))
1686             break;
1687     }
1688     if (d)
1689         FcStrFree (d);
1690     FcStrListDone (list);
1691 }
1692
1693 #define __fccache__
1694 #include "fcaliastail.h"
1695 #undef __fccache__