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