]>
Commit | Line | Data |
---|---|---|
24330d27 | 1 | /* |
4bd4418a | 2 | * $RCSId: xc/lib/fontconfig/src/fccache.c,v 1.12 2002/08/22 07:36:44 keithp Exp $ |
24330d27 | 3 | * |
46b51147 | 4 | * Copyright © 2000 Keith Packard |
24330d27 KP |
5 | * |
6 | * Permission to use, copy, modify, distribute, and sell this software and its | |
7 | * documentation for any purpose is hereby granted without fee, provided that | |
8 | * the above copyright notice appear in all copies and that both that | |
9 | * copyright notice and this permission notice appear in supporting | |
10 | * documentation, and that the name of Keith Packard not be used in | |
11 | * advertising or publicity pertaining to distribution of the software without | |
12 | * specific, written prior permission. Keith Packard makes no | |
13 | * representations about the suitability of this software for any purpose. It | |
14 | * is provided "as is" without express or implied warranty. | |
15 | * | |
16 | * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
17 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |
18 | * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
19 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |
20 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |
21 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
22 | * PERFORMANCE OF THIS SOFTWARE. | |
23 | */ | |
24 | ||
212c9f43 PL |
25 | #include <fcntl.h> |
26 | #include <sys/mman.h> | |
27 | #include <sys/utsname.h> | |
24330d27 KP |
28 | #include "fcint.h" |
29 | ||
212c9f43 | 30 | #define PAGESIZE 8192 |
fa244f3d | 31 | |
212c9f43 | 32 | static FcBool force; |
24330d27 | 33 | |
ccb3e93b | 34 | static FcChar8 * |
212c9f43 | 35 | FcCacheReadString (int fd, FcChar8 *dest, int len) |
24330d27 | 36 | { |
212c9f43 | 37 | FcChar8 c; |
ccb3e93b | 38 | FcBool escape; |
ccb3e93b KP |
39 | int size; |
40 | int i; | |
24330d27 | 41 | |
24330d27 KP |
42 | if (len == 0) |
43 | return FcFalse; | |
44 | ||
ccb3e93b KP |
45 | size = len; |
46 | i = 0; | |
24330d27 | 47 | escape = FcFalse; |
212c9f43 | 48 | while (read (fd, &c, 1) == 1) |
24330d27 KP |
49 | { |
50 | if (!escape) | |
51 | { | |
52 | switch (c) { | |
53 | case '"': | |
ccb3e93b KP |
54 | c = '\0'; |
55 | break; | |
24330d27 KP |
56 | case '\\': |
57 | escape = FcTrue; | |
58 | continue; | |
59 | } | |
60 | } | |
ccb3e93b KP |
61 | if (i == size) |
62 | { | |
212c9f43 PL |
63 | dest[i++] = 0; |
64 | return dest; | |
ccb3e93b | 65 | } |
212c9f43 | 66 | dest[i++] = c; |
ccb3e93b | 67 | if (c == '\0') |
212c9f43 | 68 | return dest; |
24330d27 KP |
69 | escape = FcFalse; |
70 | } | |
ccb3e93b | 71 | return 0; |
24330d27 KP |
72 | } |
73 | ||
74 | static FcBool | |
212c9f43 | 75 | FcCacheWriteString (int fd, const FcChar8 *chars) |
327a7fd4 | 76 | { |
212c9f43 | 77 | if (write (fd, chars, strlen(chars)+1) != strlen(chars)+1) |
327a7fd4 | 78 | return FcFalse; |
327a7fd4 KP |
79 | return FcTrue; |
80 | } | |
81 | ||
212c9f43 | 82 | #if 0 |
327a7fd4 KP |
83 | /* |
84 | * Verify the saved timestamp for a file | |
85 | */ | |
86 | FcBool | |
a8386abc | 87 | FcGlobalCacheCheckTime (const FcChar8 *file, FcGlobalCacheInfo *info) |
327a7fd4 KP |
88 | { |
89 | struct stat statb; | |
90 | ||
a8386abc | 91 | if (stat ((char *) file, &statb) < 0) |
327a7fd4 KP |
92 | { |
93 | if (FcDebug () & FC_DBG_CACHE) | |
a8386abc | 94 | printf (" file %s missing\n", file); |
327a7fd4 KP |
95 | return FcFalse; |
96 | } | |
97 | if (statb.st_mtime != info->time) | |
98 | { | |
99 | if (FcDebug () & FC_DBG_CACHE) | |
100 | printf (" timestamp mismatch (was %d is %d)\n", | |
101 | (int) info->time, (int) statb.st_mtime); | |
102 | return FcFalse; | |
103 | } | |
104 | return FcTrue; | |
105 | } | |
106 | ||
107 | void | |
108 | FcGlobalCacheReferenced (FcGlobalCache *cache, | |
109 | FcGlobalCacheInfo *info) | |
110 | { | |
111 | if (!info->referenced) | |
112 | { | |
113 | info->referenced = FcTrue; | |
114 | cache->referenced++; | |
115 | if (FcDebug () & FC_DBG_CACHE_REF) | |
116 | printf ("Reference %d %s\n", cache->referenced, info->file); | |
117 | } | |
118 | } | |
119 | ||
120 | /* | |
121 | * Break a path into dir/base elements and compute the base hash | |
122 | * and the dir length. This is shared between the functions | |
123 | * which walk the file caches | |
124 | */ | |
125 | ||
126 | typedef struct _FcFilePathInfo { | |
127 | const FcChar8 *dir; | |
128 | int dir_len; | |
129 | const FcChar8 *base; | |
130 | unsigned int base_hash; | |
131 | } FcFilePathInfo; | |
132 | ||
133 | static FcFilePathInfo | |
134 | FcFilePathInfoGet (const FcChar8 *path) | |
135 | { | |
136 | FcFilePathInfo i; | |
137 | FcChar8 *slash; | |
138 | ||
daeed6e0 | 139 | slash = FcStrLastSlash (path); |
327a7fd4 KP |
140 | if (slash) |
141 | { | |
142 | i.dir = path; | |
143 | i.dir_len = slash - path; | |
144 | if (!i.dir_len) | |
145 | i.dir_len = 1; | |
146 | i.base = slash + 1; | |
147 | } | |
148 | else | |
149 | { | |
150 | i.dir = (const FcChar8 *) "."; | |
151 | i.dir_len = 1; | |
152 | i.base = path; | |
153 | } | |
c8d5753c | 154 | i.base_hash = FcCacheHash (i.base, -1); |
327a7fd4 KP |
155 | return i; |
156 | } | |
157 | ||
327a7fd4 KP |
158 | FcGlobalCache * |
159 | FcGlobalCacheCreate (void) | |
24330d27 | 160 | { |
327a7fd4 KP |
161 | FcGlobalCache *cache; |
162 | int h; | |
24330d27 | 163 | |
327a7fd4 | 164 | cache = malloc (sizeof (FcGlobalCache)); |
24330d27 KP |
165 | if (!cache) |
166 | return 0; | |
9dac3c59 | 167 | FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCache)); |
327a7fd4 | 168 | for (h = 0; h < FC_GLOBAL_CACHE_DIR_HASH_SIZE; h++) |
24330d27 KP |
169 | cache->ents[h] = 0; |
170 | cache->entries = 0; | |
171 | cache->referenced = 0; | |
172 | cache->updated = FcFalse; | |
bb356b68 | 173 | cache->broken = FcFalse; |
24330d27 KP |
174 | return cache; |
175 | } | |
176 | ||
177 | void | |
327a7fd4 | 178 | FcGlobalCacheDestroy (FcGlobalCache *cache) |
24330d27 | 179 | { |
327a7fd4 KP |
180 | FcGlobalCacheDir *d, *next; |
181 | int h; | |
24330d27 | 182 | |
327a7fd4 | 183 | for (h = 0; h < FC_GLOBAL_CACHE_DIR_HASH_SIZE; h++) |
24330d27 | 184 | { |
327a7fd4 | 185 | for (d = cache->ents[h]; d; d = next) |
24330d27 | 186 | { |
327a7fd4 KP |
187 | next = d->next; |
188 | FcGlobalCacheDirDestroy (d); | |
24330d27 KP |
189 | } |
190 | } | |
9dac3c59 | 191 | FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCache)); |
24330d27 KP |
192 | free (cache); |
193 | } | |
194 | ||
327a7fd4 KP |
195 | /* |
196 | * Cache file syntax is quite simple: | |
197 | * | |
198 | * "file_name" id time "font_name" \n | |
199 | */ | |
200 | ||
24330d27 | 201 | void |
327a7fd4 KP |
202 | FcGlobalCacheLoad (FcGlobalCache *cache, |
203 | const FcChar8 *cache_file) | |
24330d27 | 204 | { |
327a7fd4 KP |
205 | FILE *f; |
206 | FcChar8 file_buf[8192], *file; | |
207 | int id; | |
208 | time_t time; | |
209 | FcChar8 name_buf[8192], *name; | |
210 | FcGlobalCacheInfo *info; | |
24330d27 | 211 | |
ccb3e93b | 212 | f = fopen ((char *) cache_file, "r"); |
24330d27 KP |
213 | if (!f) |
214 | return; | |
215 | ||
216 | cache->updated = FcFalse; | |
ccb3e93b KP |
217 | file = 0; |
218 | name = 0; | |
327a7fd4 KP |
219 | while ((file = FcCacheReadString (f, file_buf, sizeof (file_buf))) && |
220 | FcCacheReadInt (f, &id) && | |
221 | FcCacheReadTime (f, &time) && | |
222 | (name = FcCacheReadString (f, name_buf, sizeof (name_buf)))) | |
24330d27 | 223 | { |
327a7fd4 KP |
224 | if (FcDebug () & FC_DBG_CACHEV) |
225 | printf ("FcGlobalCacheLoad \"%s\" \"%20.20s\"\n", file, name); | |
226 | if (!FcStrCmp (name, FC_FONT_FILE_DIR)) | |
c4ab52dc | 227 | info = FcGlobalCacheDirAdd (cache, file, time, FcFalse, FcTrue); |
327a7fd4 KP |
228 | else |
229 | info = FcGlobalCacheFileAdd (cache, file, id, time, name, FcFalse); | |
230 | if (!info) | |
231 | cache->broken = FcTrue; | |
232 | else | |
233 | cache->entries++; | |
234 | if (FcDebug () & FC_DBG_CACHE_REF) | |
235 | printf ("FcGlobalCacheLoad entry %d %s\n", | |
236 | cache->entries, file); | |
ccb3e93b KP |
237 | if (file != file_buf) |
238 | free (file); | |
239 | if (name != name_buf) | |
240 | free (name); | |
241 | file = 0; | |
242 | name = 0; | |
24330d27 | 243 | } |
ccb3e93b KP |
244 | if (file && file != file_buf) |
245 | free (file); | |
246 | if (name && name != name_buf) | |
247 | free (name); | |
24330d27 KP |
248 | fclose (f); |
249 | } | |
250 | ||
251 | FcBool | |
327a7fd4 KP |
252 | FcGlobalCacheUpdate (FcGlobalCache *cache, |
253 | const FcChar8 *file, | |
254 | int id, | |
255 | const FcChar8 *name) | |
24330d27 | 256 | { |
327a7fd4 KP |
257 | const FcChar8 *match; |
258 | struct stat statb; | |
259 | FcGlobalCacheInfo *info; | |
24330d27 KP |
260 | |
261 | match = file; | |
262 | ||
ccb3e93b | 263 | if (stat ((char *) file, &statb) < 0) |
24330d27 | 264 | return FcFalse; |
327a7fd4 KP |
265 | if (S_ISDIR (statb.st_mode)) |
266 | info = FcGlobalCacheDirAdd (cache, file, statb.st_mtime, | |
c4ab52dc | 267 | FcTrue, FcTrue); |
327a7fd4 KP |
268 | else |
269 | info = FcGlobalCacheFileAdd (cache, file, id, statb.st_mtime, | |
270 | name, FcTrue); | |
271 | if (info) | |
24330d27 | 272 | { |
327a7fd4 KP |
273 | FcGlobalCacheReferenced (cache, info); |
274 | cache->updated = FcTrue; | |
24330d27 | 275 | } |
327a7fd4 KP |
276 | else |
277 | cache->broken = FcTrue; | |
278 | return info != 0; | |
24330d27 KP |
279 | } |
280 | ||
281 | FcBool | |
327a7fd4 KP |
282 | FcGlobalCacheSave (FcGlobalCache *cache, |
283 | const FcChar8 *cache_file) | |
24330d27 | 284 | { |
327a7fd4 KP |
285 | FILE *f; |
286 | int dir_hash, file_hash; | |
287 | FcGlobalCacheDir *dir; | |
288 | FcGlobalCacheFile *file; | |
289 | FcAtomic *atomic; | |
24330d27 KP |
290 | |
291 | if (!cache->updated && cache->referenced == cache->entries) | |
292 | return FcTrue; | |
293 | ||
327a7fd4 KP |
294 | if (cache->broken) |
295 | return FcFalse; | |
296 | ||
daeed6e0 | 297 | #if defined (HAVE_GETUID) && defined (HAVE_GETEUID) |
a391da8f KP |
298 | /* Set-UID programs can't safely update the cache */ |
299 | if (getuid () != geteuid ()) | |
300 | return FcFalse; | |
daeed6e0 | 301 | #endif |
a391da8f | 302 | |
134f6011 KP |
303 | atomic = FcAtomicCreate (cache_file); |
304 | if (!atomic) | |
24330d27 | 305 | goto bail0; |
134f6011 | 306 | if (!FcAtomicLock (atomic)) |
24330d27 | 307 | goto bail1; |
134f6011 | 308 | f = fopen ((char *) FcAtomicNewFile(atomic), "w"); |
24330d27 KP |
309 | if (!f) |
310 | goto bail2; | |
311 | ||
327a7fd4 | 312 | for (dir_hash = 0; dir_hash < FC_GLOBAL_CACHE_DIR_HASH_SIZE; dir_hash++) |
24330d27 | 313 | { |
327a7fd4 | 314 | for (dir = cache->ents[dir_hash]; dir; dir = dir->next) |
24330d27 | 315 | { |
327a7fd4 | 316 | if (!dir->info.referenced) |
24330d27 | 317 | continue; |
327a7fd4 | 318 | if (!FcCacheWriteString (f, dir->info.file)) |
24330d27 | 319 | goto bail4; |
fa244f3d | 320 | if (PUTC (' ', f) == EOF) |
24330d27 | 321 | goto bail4; |
327a7fd4 | 322 | if (!FcCacheWriteInt (f, 0)) |
24330d27 | 323 | goto bail4; |
fa244f3d | 324 | if (PUTC (' ', f) == EOF) |
24330d27 | 325 | goto bail4; |
327a7fd4 | 326 | if (!FcCacheWriteTime (f, dir->info.time)) |
24330d27 | 327 | goto bail4; |
fa244f3d | 328 | if (PUTC (' ', f) == EOF) |
24330d27 | 329 | goto bail4; |
327a7fd4 | 330 | if (!FcCacheWriteString (f, (FcChar8 *) FC_FONT_FILE_DIR)) |
24330d27 | 331 | goto bail4; |
fa244f3d | 332 | if (PUTC ('\n', f) == EOF) |
24330d27 | 333 | goto bail4; |
327a7fd4 KP |
334 | |
335 | for (file_hash = 0; file_hash < FC_GLOBAL_CACHE_FILE_HASH_SIZE; file_hash++) | |
336 | { | |
337 | for (file = dir->ents[file_hash]; file; file = file->next) | |
338 | { | |
339 | if (!file->info.referenced) | |
340 | continue; | |
341 | if (!FcCacheWritePath (f, dir->info.file, file->info.file)) | |
342 | goto bail4; | |
fa244f3d | 343 | if (PUTC (' ', f) == EOF) |
327a7fd4 KP |
344 | goto bail4; |
345 | if (!FcCacheWriteInt (f, file->id < 0 ? 0 : file->id)) | |
346 | goto bail4; | |
fa244f3d | 347 | if (PUTC (' ', f) == EOF) |
327a7fd4 KP |
348 | goto bail4; |
349 | if (!FcCacheWriteTime (f, file->info.time)) | |
350 | goto bail4; | |
fa244f3d | 351 | if (PUTC (' ', f) == EOF) |
327a7fd4 KP |
352 | goto bail4; |
353 | if (!FcCacheWriteString (f, file->name)) | |
354 | goto bail4; | |
fa244f3d | 355 | if (PUTC ('\n', f) == EOF) |
327a7fd4 KP |
356 | goto bail4; |
357 | } | |
358 | } | |
24330d27 KP |
359 | } |
360 | } | |
361 | ||
362 | if (fclose (f) == EOF) | |
363 | goto bail3; | |
364 | ||
134f6011 | 365 | if (!FcAtomicReplaceOrig (atomic)) |
24330d27 KP |
366 | goto bail3; |
367 | ||
134f6011 KP |
368 | FcAtomicUnlock (atomic); |
369 | FcAtomicDestroy (atomic); | |
370 | ||
24330d27 KP |
371 | cache->updated = FcFalse; |
372 | return FcTrue; | |
373 | ||
374 | bail4: | |
375 | fclose (f); | |
376 | bail3: | |
134f6011 | 377 | FcAtomicDeleteNew (atomic); |
24330d27 | 378 | bail2: |
134f6011 | 379 | FcAtomicUnlock (atomic); |
24330d27 | 380 | bail1: |
134f6011 | 381 | FcAtomicDestroy (atomic); |
24330d27 KP |
382 | bail0: |
383 | return FcFalse; | |
384 | } | |
212c9f43 | 385 | #endif |
24330d27 | 386 | |
212c9f43 PL |
387 | /* |
388 | * Find the next presumably-mmapable offset after the current file | |
389 | * pointer. | |
390 | */ | |
391 | int | |
392 | FcCacheNextOffset(int fd) | |
179c3995 | 393 | { |
212c9f43 PL |
394 | off_t w; |
395 | w = lseek(fd, 0, SEEK_END); | |
179c3995 | 396 | |
212c9f43 PL |
397 | if (w % PAGESIZE == 0) |
398 | return w; | |
399 | else | |
400 | return ((w / PAGESIZE)+1)*PAGESIZE; | |
179c3995 KP |
401 | } |
402 | ||
212c9f43 PL |
403 | /* will go away once we use config->cache */ |
404 | #define CACHE_DEFAULT_TMPDIR "/tmp" | |
405 | #define CACHE_DEFAULT_NAME "/fontconfig-mmap" | |
406 | static char * | |
407 | FcCacheFilename(void) | |
24330d27 | 408 | { |
212c9f43 PL |
409 | struct utsname b; |
410 | static char * name = 0; | |
24330d27 | 411 | |
212c9f43 PL |
412 | if (name) |
413 | return name; | |
24330d27 | 414 | |
212c9f43 PL |
415 | if (uname(&b) == -1) |
416 | name = CACHE_DEFAULT_NAME; | |
417 | else | |
24330d27 | 418 | { |
212c9f43 PL |
419 | char * tmpname = getenv("TMPDIR"); |
420 | char * logname = getenv("LOGNAME"); | |
421 | if (!tmpname) | |
422 | tmpname = CACHE_DEFAULT_TMPDIR; | |
24330d27 | 423 | |
212c9f43 PL |
424 | name = malloc(strlen(CACHE_DEFAULT_NAME) + |
425 | strlen(tmpname) + | |
426 | (logname ? strlen(logname) : 0) + 5); | |
427 | strcpy(name, tmpname); | |
428 | strcat(name, CACHE_DEFAULT_NAME); | |
429 | strcat(name, "-"); | |
430 | strcat(name, logname ? logname : ""); | |
179c3995 | 431 | } |
212c9f43 | 432 | return name; |
24330d27 | 433 | } |
cd2ec1a9 | 434 | |
212c9f43 PL |
435 | /* |
436 | * Wipe out static state. | |
437 | */ | |
cd2ec1a9 PL |
438 | void |
439 | FcCacheClearStatic() | |
440 | { | |
441 | FcFontSetClearStatic(); | |
442 | FcPatternClearStatic(); | |
443 | FcValueListClearStatic(); | |
444 | FcObjectClearStatic(); | |
445 | FcMatrixClearStatic(); | |
446 | FcCharSetClearStatic(); | |
447 | FcLangSetClearStatic(); | |
448 | } | |
449 | ||
212c9f43 PL |
450 | /* |
451 | * Trigger the counting phase: this tells us how much to allocate. | |
452 | */ | |
cd2ec1a9 PL |
453 | FcBool |
454 | FcCachePrepareSerialize (FcConfig * config) | |
455 | { | |
456 | int i; | |
457 | for (i = FcSetSystem; i <= FcSetApplication; i++) | |
458 | if (config->fonts[i] && !FcFontSetPrepareSerialize(config->fonts[i])) | |
459 | return FcFalse; | |
460 | return FcTrue; | |
461 | } | |
462 | ||
212c9f43 | 463 | /* allocate and populate static structures */ |
cd2ec1a9 PL |
464 | FcBool |
465 | FcCacheSerialize (FcConfig * config) | |
466 | { | |
467 | int i; | |
468 | for (i = FcSetSystem; i <= FcSetApplication; i++) | |
469 | if (config->fonts[i] && !FcFontSetSerialize(config->fonts[i])) | |
470 | return FcFalse; | |
471 | return FcTrue; | |
472 | } | |
212c9f43 PL |
473 | |
474 | /* get the current arch name */ | |
475 | /* caller is responsible for freeing returned pointer */ | |
476 | static char * | |
477 | FcCacheGetCurrentArch (void) | |
478 | { | |
479 | struct utsname b; | |
480 | char * current_arch_machine_name; | |
481 | ||
482 | if (uname(&b) == -1) | |
483 | return FcFalse; | |
484 | current_arch_machine_name = strdup(b.machine); | |
485 | /* if (getenv ("FAKE_ARCH")) // testing purposes | |
486 | current_arch_machine_name = strdup(getenv("FAKE_ARCH")); */ | |
487 | return current_arch_machine_name; | |
488 | } | |
489 | ||
490 | /* return the address of the segment for the provided arch, | |
491 | * or -1 if arch not found */ | |
492 | static off_t | |
493 | FcCacheSkipToArch (int fd, const char * arch) | |
494 | { | |
495 | char candidate_arch_machine_name[64], bytes_to_skip[7]; | |
496 | off_t current_arch_start = 0; | |
497 | ||
498 | /* skip arches that are not the current arch */ | |
499 | while (1) | |
500 | { | |
501 | long bs; | |
502 | ||
503 | lseek (fd, current_arch_start, SEEK_SET); | |
504 | if (FcCacheReadString (fd, candidate_arch_machine_name, | |
505 | sizeof (candidate_arch_machine_name)) == 0) | |
506 | break; | |
507 | if (FcCacheReadString (fd, bytes_to_skip, 7) == 0) | |
508 | break; | |
509 | bs = a64l(bytes_to_skip); | |
510 | if (bs == 0) | |
511 | break; | |
512 | ||
513 | if (strcmp (candidate_arch_machine_name, arch)==0) | |
514 | break; | |
515 | current_arch_start += bs; | |
516 | } | |
517 | ||
518 | if (strcmp (candidate_arch_machine_name, arch)!=0) | |
519 | return -1; | |
520 | ||
521 | return current_arch_start; | |
522 | } | |
523 | ||
524 | /* Cuts out the segment at the file pointer (moves everything else | |
525 | * down to cover it), and leaves the file pointer at the end of the | |
526 | * file. */ | |
527 | #define BUF_SIZE 8192 | |
528 | ||
529 | static FcBool | |
530 | FcCacheMoveDown (int fd, off_t start) | |
531 | { | |
532 | char * buf = malloc (BUF_SIZE); | |
533 | char candidate_arch_machine_name[64], bytes_to_skip[7]; | |
534 | long bs; off_t pos; | |
535 | int c, bytes_skipped; | |
536 | ||
537 | if (!buf) | |
538 | return FcFalse; | |
539 | ||
540 | lseek (fd, start, SEEK_SET); | |
541 | if (FcCacheReadString (fd, candidate_arch_machine_name, | |
542 | sizeof (candidate_arch_machine_name)) == 0) | |
543 | goto done; | |
544 | if (FcCacheReadString (fd, bytes_to_skip, 7) == 0) | |
545 | goto done; | |
546 | ||
547 | bs = a64l(bytes_to_skip); | |
548 | if (bs == 0) | |
549 | goto done; | |
550 | ||
551 | bytes_skipped = 0; | |
552 | do | |
553 | { | |
554 | lseek (fd, start+bs+bytes_skipped, SEEK_SET); | |
555 | if ((c = read (fd, buf, BUF_SIZE)) <= 0) | |
556 | break; | |
557 | lseek (fd, start+bytes_skipped, SEEK_SET); | |
558 | if (write (fd, buf, c) < 0) | |
559 | goto bail; | |
560 | bytes_skipped += c; | |
561 | } | |
562 | while (c > 0); | |
563 | lseek (fd, start+bytes_skipped, SEEK_SET); | |
564 | ||
565 | done: | |
566 | free (buf); | |
567 | return FcTrue; | |
568 | ||
569 | bail: | |
570 | free (buf); | |
571 | return FcFalse; | |
572 | } | |
573 | ||
574 | /* read serialized state from the cache file */ | |
575 | FcBool | |
576 | FcCacheRead (FcConfig *config) | |
577 | { | |
578 | int fd, i; | |
579 | FcCache metadata; | |
580 | char * current_arch_machine_name; | |
581 | char candidate_arch_machine_name[64], bytes_in_block[7]; | |
582 | off_t current_arch_start = 0; | |
583 | ||
584 | if (force) | |
585 | return FcFalse; | |
586 | ||
587 | fd = open(FcCacheFilename(), O_RDONLY); | |
588 | if (fd == -1) | |
589 | return FcFalse; | |
590 | ||
591 | current_arch_machine_name = FcCacheGetCurrentArch(); | |
592 | current_arch_start = FcCacheSkipToArch(fd, current_arch_machine_name); | |
593 | if (current_arch_start < 0) | |
594 | goto bail; | |
595 | ||
596 | lseek (fd, current_arch_start, SEEK_SET); | |
597 | if (FcCacheReadString (fd, candidate_arch_machine_name, | |
598 | sizeof (candidate_arch_machine_name)) == 0) | |
599 | goto bail; | |
600 | if (FcCacheReadString (fd, bytes_in_block, 7) == 0) | |
601 | goto bail; | |
602 | ||
603 | // sanity check for endianness issues | |
604 | read(fd, &metadata, sizeof(FcCache)); | |
605 | if (metadata.magic != FC_CACHE_MAGIC) | |
606 | goto bail; | |
607 | ||
608 | if (!FcObjectRead(fd, metadata)) goto bail1; | |
609 | if (!FcStrSetRead(fd, metadata)) goto bail1; | |
610 | if (!FcCharSetRead(fd, metadata)) goto bail1; | |
611 | if (!FcMatrixRead(fd, metadata)) goto bail1; | |
612 | if (!FcLangSetRead(fd, metadata)) goto bail1; | |
613 | if (!FcValueListRead(fd, metadata)) goto bail1; | |
614 | if (!FcPatternEltRead(fd, metadata)) goto bail1; | |
615 | if (!FcPatternRead(fd, metadata)) goto bail1; | |
616 | if (!FcFontSetRead(fd, config, metadata)) goto bail1; | |
617 | close(fd); | |
618 | free (current_arch_machine_name); | |
619 | return FcTrue; | |
620 | ||
621 | bail1: | |
622 | for (i = FcSetSystem; i <= FcSetApplication; i++) | |
623 | config->fonts[i] = 0; | |
624 | close(fd); | |
625 | bail: | |
626 | free (current_arch_machine_name); | |
627 | return FcFalse; | |
628 | } | |
629 | ||
630 | /* write serialized state to the cache file */ | |
631 | FcBool | |
632 | FcCacheWrite (FcConfig * config) | |
633 | { | |
634 | int fd; | |
635 | FcCache metadata; | |
636 | off_t current_arch_start = 0, truncate_to; | |
637 | char * current_arch_machine_name, bytes_written[7] = "dedbef"; | |
638 | ||
639 | if (!FcCachePrepareSerialize (config)) | |
640 | return FcFalse; | |
641 | ||
642 | if (!FcCacheSerialize (config)) | |
643 | return FcFalse; | |
644 | ||
645 | fd = open(FcCacheFilename(), O_RDWR | O_CREAT, 0666); | |
646 | if (fd == -1) | |
647 | return FcFalse; | |
648 | ||
649 | current_arch_machine_name = FcCacheGetCurrentArch(); | |
650 | current_arch_start = FcCacheSkipToArch(fd, current_arch_machine_name); | |
651 | if (current_arch_start < 0) | |
652 | current_arch_start = FcCacheNextOffset (fd); | |
653 | ||
654 | if (!FcCacheMoveDown(fd, current_arch_start)) | |
655 | goto bail; | |
656 | ||
657 | current_arch_start = lseek(fd, 0, SEEK_CUR); | |
658 | if (ftruncate (fd, current_arch_start) == -1) | |
659 | goto bail; | |
660 | ||
661 | /* reserve space for arch, count & metadata */ | |
662 | if (!FcCacheWriteString (fd, current_arch_machine_name)) | |
663 | goto bail; | |
664 | if (!FcCacheWriteString (fd, bytes_written)) | |
665 | goto bail; | |
666 | memset (&metadata, 0, sizeof(FcCache)); | |
667 | metadata.magic = FC_CACHE_MAGIC; | |
668 | write(fd, &metadata, sizeof(FcCache)); | |
669 | ||
670 | if (!FcFontSetWrite(fd, config, &metadata)) goto bail; | |
671 | if (!FcPatternWrite(fd, &metadata)) goto bail; | |
672 | if (!FcPatternEltWrite(fd, &metadata)) goto bail; | |
673 | if (!FcValueListWrite(fd, &metadata)) goto bail; | |
674 | if (!FcLangSetWrite(fd, &metadata)) goto bail; | |
675 | if (!FcCharSetWrite(fd, &metadata)) goto bail; | |
676 | if (!FcMatrixWrite(fd, &metadata)) goto bail; | |
677 | if (!FcStrSetWrite(fd, &metadata)) goto bail; | |
678 | if (!FcObjectWrite(fd, &metadata)) goto bail; | |
679 | ||
680 | /* now write the address of the next offset */ | |
681 | truncate_to = FcCacheNextOffset(fd) - current_arch_start; | |
682 | lseek(fd, current_arch_start + strlen(current_arch_machine_name)+1, | |
683 | SEEK_SET); | |
684 | strcpy (bytes_written, l64a(truncate_to)); | |
685 | if (!FcCacheWriteString (fd, bytes_written)) | |
686 | goto bail; | |
687 | ||
688 | /* now rewrite metadata & truncate file */ | |
689 | if (write(fd, &metadata, sizeof(FcCache)) != sizeof (FcCache)) | |
690 | goto bail; | |
691 | if (ftruncate (fd, current_arch_start + truncate_to) == -1) | |
692 | goto bail; | |
693 | ||
694 | close(fd); | |
695 | return FcTrue; | |
696 | ||
697 | bail: | |
698 | free (current_arch_machine_name); | |
699 | return FcFalse; | |
700 | } | |
701 | ||
702 | /* if true, ignore the cache file */ | |
703 | void | |
704 | FcCacheForce (FcBool f) | |
705 | { | |
706 | force = f; | |
707 | } |