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