Bug Summary

File:src/fccache.c
Location:line 406, column 15
Description:Dereference of undefined pointer value

Annotated Source Code

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