1*593dc095SDavid du Colombier /* Copyright (C) 2003-2004 artofcode LLC. All rights reserved.
2*593dc095SDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
5*593dc095SDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
9*593dc095SDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15*593dc095SDavid du Colombier */
16*593dc095SDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gp_unix_cache.c,v 1.3 2004/07/14 15:34:25 giles Exp $ */
18*593dc095SDavid du Colombier /* Generic POSIX persistent-cache implementation for Ghostscript */
19*593dc095SDavid du Colombier
20*593dc095SDavid du Colombier #include "stdio_.h"
21*593dc095SDavid du Colombier #include "string_.h"
22*593dc095SDavid du Colombier #include "time_.h"
23*593dc095SDavid du Colombier #include <stdlib.h> /* should use gs_malloc() instead */
24*593dc095SDavid du Colombier #include "gconfigd.h"
25*593dc095SDavid du Colombier #include "gp.h"
26*593dc095SDavid du Colombier #include "md5.h"
27*593dc095SDavid du Colombier
28*593dc095SDavid du Colombier /* ------ Persistent data cache types ------*/
29*593dc095SDavid du Colombier
30*593dc095SDavid du Colombier #define GP_CACHE_VERSION 0
31*593dc095SDavid du Colombier
32*593dc095SDavid du Colombier /* cache entry type */
33*593dc095SDavid du Colombier typedef struct gp_cache_entry_s {
34*593dc095SDavid du Colombier int type;
35*593dc095SDavid du Colombier int keylen;
36*593dc095SDavid du Colombier byte *key;
37*593dc095SDavid du Colombier md5_byte_t hash[16];
38*593dc095SDavid du Colombier char *filename;
39*593dc095SDavid du Colombier int len;
40*593dc095SDavid du Colombier void *buffer;
41*593dc095SDavid du Colombier int dirty;
42*593dc095SDavid du Colombier time_t last_used;
43*593dc095SDavid du Colombier } gp_cache_entry;
44*593dc095SDavid du Colombier
45*593dc095SDavid du Colombier /* initialize a new gp_cache_entry struct */
gp_cache_clear_entry(gp_cache_entry * item)46*593dc095SDavid du Colombier private void gp_cache_clear_entry(gp_cache_entry *item)
47*593dc095SDavid du Colombier {
48*593dc095SDavid du Colombier item->type = -1;
49*593dc095SDavid du Colombier item->key = NULL;
50*593dc095SDavid du Colombier item->keylen = 0;
51*593dc095SDavid du Colombier item->filename = NULL;
52*593dc095SDavid du Colombier item->buffer = NULL;
53*593dc095SDavid du Colombier item->len = 0;
54*593dc095SDavid du Colombier item->dirty = 0;
55*593dc095SDavid du Colombier item->last_used = 0;
56*593dc095SDavid du Colombier }
57*593dc095SDavid du Colombier
58*593dc095SDavid du Colombier /* get the cache directory's path */
gp_cache_prefix(void)59*593dc095SDavid du Colombier private char *gp_cache_prefix(void)
60*593dc095SDavid du Colombier {
61*593dc095SDavid du Colombier char *prefix = NULL;
62*593dc095SDavid du Colombier int plen = 0;
63*593dc095SDavid du Colombier
64*593dc095SDavid du Colombier /* get the cache directory path */
65*593dc095SDavid du Colombier if (gp_getenv("GS_CACHE_DIR", (char *)NULL, &plen) < 0) {
66*593dc095SDavid du Colombier prefix = malloc(plen);
67*593dc095SDavid du Colombier gp_getenv("GS_CACHE_DIR", prefix, &plen);
68*593dc095SDavid du Colombier plen--;
69*593dc095SDavid du Colombier } else {
70*593dc095SDavid du Colombier #ifdef GS_CACHE_DIR
71*593dc095SDavid du Colombier prefix = strdup(GS_CACHE_DIR);
72*593dc095SDavid du Colombier #else
73*593dc095SDavid du Colombier prefix = strdup(".cache");
74*593dc095SDavid du Colombier #endif
75*593dc095SDavid du Colombier plen = strlen(prefix);
76*593dc095SDavid du Colombier }
77*593dc095SDavid du Colombier
78*593dc095SDavid du Colombier /* substitute $HOME for '~' */
79*593dc095SDavid du Colombier if (plen > 1 && prefix[0] == '~') {
80*593dc095SDavid du Colombier char *home, *path;
81*593dc095SDavid du Colombier int hlen = 0;
82*593dc095SDavid du Colombier unsigned int pathlen = 0;
83*593dc095SDavid du Colombier gp_file_name_combine_result result;
84*593dc095SDavid du Colombier
85*593dc095SDavid du Colombier if (gp_getenv("HOME", (char *)NULL, &hlen) < 0) {
86*593dc095SDavid du Colombier home = malloc(hlen);
87*593dc095SDavid du Colombier if (home == NULL) return prefix;
88*593dc095SDavid du Colombier gp_getenv("HOME", home, &hlen);
89*593dc095SDavid du Colombier hlen--;
90*593dc095SDavid du Colombier if (plen == 1) {
91*593dc095SDavid du Colombier /* only "~" */
92*593dc095SDavid du Colombier free(prefix);
93*593dc095SDavid du Colombier return home;
94*593dc095SDavid du Colombier }
95*593dc095SDavid du Colombier /* substitue for the initial '~' */
96*593dc095SDavid du Colombier pathlen = hlen + plen + 1;
97*593dc095SDavid du Colombier path = malloc(pathlen);
98*593dc095SDavid du Colombier if (path == NULL) { free(home); return prefix; }
99*593dc095SDavid du Colombier result = gp_file_name_combine(home, hlen, prefix+2, plen-2, false, path, &pathlen);
100*593dc095SDavid du Colombier if (result == gp_combine_success) {
101*593dc095SDavid du Colombier free(prefix);
102*593dc095SDavid du Colombier prefix = path;
103*593dc095SDavid du Colombier } else {
104*593dc095SDavid du Colombier dlprintf1("file_name_combine failed with code %d\n", result);
105*593dc095SDavid du Colombier }
106*593dc095SDavid du Colombier free(home);
107*593dc095SDavid du Colombier }
108*593dc095SDavid du Colombier }
109*593dc095SDavid du Colombier #ifdef DEBUG_CACHE
110*593dc095SDavid du Colombier dlprintf1("cache dir read as '%s'\n", prefix);
111*593dc095SDavid du Colombier #endif
112*593dc095SDavid du Colombier return prefix;
113*593dc095SDavid du Colombier }
114*593dc095SDavid du Colombier
115*593dc095SDavid du Colombier /* compute the cache index file's path */
116*593dc095SDavid du Colombier private char *
gp_cache_indexfilename(const char * prefix)117*593dc095SDavid du Colombier gp_cache_indexfilename(const char *prefix)
118*593dc095SDavid du Colombier {
119*593dc095SDavid du Colombier const char *fn = "gs_cache";
120*593dc095SDavid du Colombier char *path;
121*593dc095SDavid du Colombier unsigned int len;
122*593dc095SDavid du Colombier gp_file_name_combine_result result;
123*593dc095SDavid du Colombier
124*593dc095SDavid du Colombier len = strlen(prefix) + strlen(fn) + 2;
125*593dc095SDavid du Colombier path = malloc(len);
126*593dc095SDavid du Colombier
127*593dc095SDavid du Colombier result = gp_file_name_combine(prefix, strlen(prefix), fn, strlen(fn), true, path, &len);
128*593dc095SDavid du Colombier if (result == gp_combine_small_buffer) {
129*593dc095SDavid du Colombier /* handle the case when the combination requires more than one extra character */
130*593dc095SDavid du Colombier free(path);
131*593dc095SDavid du Colombier path = malloc(++len);
132*593dc095SDavid du Colombier result = gp_file_name_combine(prefix, strlen(prefix), fn, strlen(fn), true, path, &len);
133*593dc095SDavid du Colombier }
134*593dc095SDavid du Colombier if (result != gp_combine_success) {
135*593dc095SDavid du Colombier dlprintf1("pcache: file_name_combine for indexfilename failed with code %d\n", result);
136*593dc095SDavid du Colombier free(path);
137*593dc095SDavid du Colombier return NULL;
138*593dc095SDavid du Colombier }
139*593dc095SDavid du Colombier return path;
140*593dc095SDavid du Colombier }
141*593dc095SDavid du Colombier
142*593dc095SDavid du Colombier /* compute and set a cache key's hash */
gp_cache_hash(gp_cache_entry * entry)143*593dc095SDavid du Colombier private void gp_cache_hash(gp_cache_entry *entry)
144*593dc095SDavid du Colombier {
145*593dc095SDavid du Colombier md5_state_t md5;
146*593dc095SDavid du Colombier
147*593dc095SDavid du Colombier /* we use md5 hashes of the key */
148*593dc095SDavid du Colombier md5_init(&md5);
149*593dc095SDavid du Colombier md5_append(&md5, entry->key, entry->keylen);
150*593dc095SDavid du Colombier md5_finish(&md5, entry->hash);
151*593dc095SDavid du Colombier }
152*593dc095SDavid du Colombier
153*593dc095SDavid du Colombier /* compute and set cache item's filename */
gp_cache_filename(const char * prefix,gp_cache_entry * item)154*593dc095SDavid du Colombier private void gp_cache_filename(const char *prefix, gp_cache_entry *item)
155*593dc095SDavid du Colombier {
156*593dc095SDavid du Colombier const char hexmap[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
157*593dc095SDavid du Colombier char *fn = malloc(gp_file_name_sizeof), *fni;
158*593dc095SDavid du Colombier int i;
159*593dc095SDavid du Colombier
160*593dc095SDavid du Colombier fni = fn;
161*593dc095SDavid du Colombier *fni++ = hexmap[item->type>>4 & 0x0F];
162*593dc095SDavid du Colombier *fni++ = hexmap[item->type & 0x0F];
163*593dc095SDavid du Colombier *fni++ = '.';
164*593dc095SDavid du Colombier for (i = 0; i < 16; i++) {
165*593dc095SDavid du Colombier *fni++ = hexmap[(item->hash[i]>>4 & 0x0F)];
166*593dc095SDavid du Colombier *fni++ = hexmap[(item->hash[i] & 0x0F)];
167*593dc095SDavid du Colombier }
168*593dc095SDavid du Colombier *fni = '\0';
169*593dc095SDavid du Colombier
170*593dc095SDavid du Colombier if (item->filename) free(item->filename);
171*593dc095SDavid du Colombier item->filename = fn;
172*593dc095SDavid du Colombier }
173*593dc095SDavid du Colombier
174*593dc095SDavid du Colombier /* generate an access path for a cache item */
gp_cache_itempath(const char * prefix,gp_cache_entry * item)175*593dc095SDavid du Colombier private char *gp_cache_itempath(const char *prefix, gp_cache_entry *item)
176*593dc095SDavid du Colombier {
177*593dc095SDavid du Colombier const char *fn = item->filename;
178*593dc095SDavid du Colombier gp_file_name_combine_result result;
179*593dc095SDavid du Colombier char *path;
180*593dc095SDavid du Colombier unsigned int len;
181*593dc095SDavid du Colombier
182*593dc095SDavid du Colombier len = strlen(prefix) + strlen(fn) + 2;
183*593dc095SDavid du Colombier path = malloc(len);
184*593dc095SDavid du Colombier result = gp_file_name_combine(prefix, strlen(prefix),
185*593dc095SDavid du Colombier fn, strlen(fn), false, path, &len);
186*593dc095SDavid du Colombier
187*593dc095SDavid du Colombier if (result != gp_combine_success) {
188*593dc095SDavid du Colombier dlprintf1("pcache: file_name_combine failed on cache item filename with code %d\n", result);
189*593dc095SDavid du Colombier }
190*593dc095SDavid du Colombier
191*593dc095SDavid du Colombier return path;
192*593dc095SDavid du Colombier }
193*593dc095SDavid du Colombier
gp_cache_saveitem(FILE * file,gp_cache_entry * item)194*593dc095SDavid du Colombier private int gp_cache_saveitem(FILE *file, gp_cache_entry* item)
195*593dc095SDavid du Colombier {
196*593dc095SDavid du Colombier unsigned char version = 0;
197*593dc095SDavid du Colombier int ret;
198*593dc095SDavid du Colombier
199*593dc095SDavid du Colombier #ifdef DEBUG_CACHE
200*593dc095SDavid du Colombier dlprintf2("pcache: saving key with version %d, data length %d\n", version, item->len);
201*593dc095SDavid du Colombier #endif
202*593dc095SDavid du Colombier ret = fwrite(&version, 1, 1, file);
203*593dc095SDavid du Colombier ret = fwrite(&(item->keylen), 1, sizeof(item->keylen), file);
204*593dc095SDavid du Colombier ret = fwrite(item->key, 1, item->keylen, file);
205*593dc095SDavid du Colombier ret = fwrite(&(item->len), 1, sizeof(item->len), file);
206*593dc095SDavid du Colombier ret = fwrite(item->buffer, 1, item->len, file);
207*593dc095SDavid du Colombier item->dirty = 0;
208*593dc095SDavid du Colombier return ret;
209*593dc095SDavid du Colombier }
210*593dc095SDavid du Colombier
gp_cache_loaditem(FILE * file,gp_cache_entry * item,gp_cache_alloc alloc,void * userdata)211*593dc095SDavid du Colombier private int gp_cache_loaditem(FILE *file, gp_cache_entry *item, gp_cache_alloc alloc, void *userdata)
212*593dc095SDavid du Colombier {
213*593dc095SDavid du Colombier unsigned char version;
214*593dc095SDavid du Colombier unsigned char *filekey = NULL;
215*593dc095SDavid du Colombier int len, keylen;
216*593dc095SDavid du Colombier
217*593dc095SDavid du Colombier fread(&version, 1, 1, file);
218*593dc095SDavid du Colombier if (version != GP_CACHE_VERSION) {
219*593dc095SDavid du Colombier #ifdef DEBUG_CACHE
220*593dc095SDavid du Colombier dlprintf2("pcache file version mismatch (%d vs expected %d)\n", version, GP_CACHE_VERSION);
221*593dc095SDavid du Colombier #endif
222*593dc095SDavid du Colombier return -1;
223*593dc095SDavid du Colombier }
224*593dc095SDavid du Colombier fread(&keylen, 1, sizeof(keylen), file);
225*593dc095SDavid du Colombier if (keylen != item->keylen) {
226*593dc095SDavid du Colombier #ifdef DEBUG_CACHE
227*593dc095SDavid du Colombier dlprintf2("pcache file has correct hash but wrong key length (%d vs %d)\n",
228*593dc095SDavid du Colombier keylen, item->keylen);
229*593dc095SDavid du Colombier #endif
230*593dc095SDavid du Colombier return -1;
231*593dc095SDavid du Colombier }
232*593dc095SDavid du Colombier filekey = malloc(keylen);
233*593dc095SDavid du Colombier if (filekey != NULL)
234*593dc095SDavid du Colombier fread(filekey, 1, keylen, file);
235*593dc095SDavid du Colombier if (memcmp(filekey, item->key, keylen)) {
236*593dc095SDavid du Colombier #ifdef DEBUG_CACHE
237*593dc095SDavid du Colombier dlprintf("pcache file has correct hash but doesn't match the full key\n");
238*593dc095SDavid du Colombier #endif
239*593dc095SDavid du Colombier free(filekey);
240*593dc095SDavid du Colombier item->buffer = NULL;
241*593dc095SDavid du Colombier item->len = 0;
242*593dc095SDavid du Colombier return -1;
243*593dc095SDavid du Colombier }
244*593dc095SDavid du Colombier free(filekey);
245*593dc095SDavid du Colombier
246*593dc095SDavid du Colombier fread(&len, 1, sizeof(len), file);
247*593dc095SDavid du Colombier #ifdef DEBUG_CACHE
248*593dc095SDavid du Colombier dlprintf2("key matches file with version %d, data length %d\n", version, len);
249*593dc095SDavid du Colombier #endif
250*593dc095SDavid du Colombier item->buffer = alloc(userdata, len);
251*593dc095SDavid du Colombier if (item->buffer == NULL) {
252*593dc095SDavid du Colombier dlprintf("pcache: unable to allocate buffer for file data!\n");
253*593dc095SDavid du Colombier return -1;
254*593dc095SDavid du Colombier }
255*593dc095SDavid du Colombier
256*593dc095SDavid du Colombier item->len = fread(item->buffer, 1, len, file);
257*593dc095SDavid du Colombier item->dirty = 1;
258*593dc095SDavid du Colombier item->last_used = time(NULL);
259*593dc095SDavid du Colombier
260*593dc095SDavid du Colombier return 0;
261*593dc095SDavid du Colombier }
262*593dc095SDavid du Colombier
263*593dc095SDavid du Colombier /* convert a two-character hex string to an integer */
readhexbyte(const char * s)264*593dc095SDavid du Colombier private int readhexbyte(const char *s)
265*593dc095SDavid du Colombier {
266*593dc095SDavid du Colombier const char hexmap[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
267*593dc095SDavid du Colombier int i,r;
268*593dc095SDavid du Colombier
269*593dc095SDavid du Colombier for (i = 0; i < 16; i++)
270*593dc095SDavid du Colombier if (hexmap[i] == *s) break;
271*593dc095SDavid du Colombier if (i == 16) return -1;
272*593dc095SDavid du Colombier r = i;
273*593dc095SDavid du Colombier s++;
274*593dc095SDavid du Colombier for (i = 0; i < 16; i++)
275*593dc095SDavid du Colombier if (hexmap[i] == *s) break;
276*593dc095SDavid du Colombier if (i == 16) return -1;
277*593dc095SDavid du Colombier r = r<<4 | i;
278*593dc095SDavid du Colombier return r;
279*593dc095SDavid du Colombier }
280*593dc095SDavid du Colombier
281*593dc095SDavid du Colombier private int
gp_cache_read_entry(FILE * file,gp_cache_entry * item)282*593dc095SDavid du Colombier gp_cache_read_entry(FILE *file, gp_cache_entry *item)
283*593dc095SDavid du Colombier {
284*593dc095SDavid du Colombier char line[256];
285*593dc095SDavid du Colombier char fn[32];
286*593dc095SDavid du Colombier int i;
287*593dc095SDavid du Colombier
288*593dc095SDavid du Colombier if (!fgets(line, 256, file)) return -1;
289*593dc095SDavid du Colombier
290*593dc095SDavid du Colombier /* skip comments */
291*593dc095SDavid du Colombier if (line[0] == '#') return 1;
292*593dc095SDavid du Colombier
293*593dc095SDavid du Colombier /* otherwise, parse the line */
294*593dc095SDavid du Colombier sscanf(line, "%s %ld\n", fn, &item->last_used);
295*593dc095SDavid du Colombier /* unpack the type from the filename */
296*593dc095SDavid du Colombier item->type = readhexbyte(fn);
297*593dc095SDavid du Colombier /* unpack the md5 hash from the filename */
298*593dc095SDavid du Colombier for (i = 0; i < 16; i++)
299*593dc095SDavid du Colombier item->hash[i] = readhexbyte(fn + 3 + 2*i);
300*593dc095SDavid du Colombier /* remember the filename */
301*593dc095SDavid du Colombier if (item->filename) free(item->filename);
302*593dc095SDavid du Colombier item->filename = malloc(strlen(fn) + 1);
303*593dc095SDavid du Colombier memcpy(item->filename, fn, strlen(fn));
304*593dc095SDavid du Colombier /* null other fields */
305*593dc095SDavid du Colombier item->key = NULL;
306*593dc095SDavid du Colombier item->keylen = 0;
307*593dc095SDavid du Colombier item->len = 0;
308*593dc095SDavid du Colombier item->buffer = NULL;
309*593dc095SDavid du Colombier
310*593dc095SDavid du Colombier return 0;
311*593dc095SDavid du Colombier }
312*593dc095SDavid du Colombier
313*593dc095SDavid du Colombier private int
gp_cache_write_entry(FILE * file,gp_cache_entry * item)314*593dc095SDavid du Colombier gp_cache_write_entry(FILE *file, gp_cache_entry *item)
315*593dc095SDavid du Colombier {
316*593dc095SDavid du Colombier fprintf(file, "%s %ld\n", item->filename, item->last_used);
317*593dc095SDavid du Colombier return 0;
318*593dc095SDavid du Colombier }
319*593dc095SDavid du Colombier
320*593dc095SDavid du Colombier
321*593dc095SDavid du Colombier /* insert a buffer under a (type, key) pair */
gp_cache_insert(int type,byte * key,int keylen,void * buffer,int buflen)322*593dc095SDavid du Colombier int gp_cache_insert(int type, byte *key, int keylen, void *buffer, int buflen)
323*593dc095SDavid du Colombier {
324*593dc095SDavid du Colombier char *prefix, *path;
325*593dc095SDavid du Colombier char *infn,*outfn;
326*593dc095SDavid du Colombier FILE *file, *in, *out;
327*593dc095SDavid du Colombier gp_cache_entry item, item2;
328*593dc095SDavid du Colombier int code, hit = 0;
329*593dc095SDavid du Colombier
330*593dc095SDavid du Colombier prefix = gp_cache_prefix();
331*593dc095SDavid du Colombier infn = gp_cache_indexfilename(prefix);
332*593dc095SDavid du Colombier {
333*593dc095SDavid du Colombier int len = strlen(infn) + 2;
334*593dc095SDavid du Colombier outfn = malloc(len);
335*593dc095SDavid du Colombier memcpy(outfn, infn, len - 2);
336*593dc095SDavid du Colombier outfn[len-2] = '+';
337*593dc095SDavid du Colombier outfn[len-1] = '\0';
338*593dc095SDavid du Colombier }
339*593dc095SDavid du Colombier
340*593dc095SDavid du Colombier in = fopen(infn, "r");
341*593dc095SDavid du Colombier if (in == NULL) {
342*593dc095SDavid du Colombier dlprintf1("pcache: unable to open '%s'\n", infn);
343*593dc095SDavid du Colombier return -1;
344*593dc095SDavid du Colombier }
345*593dc095SDavid du Colombier out = fopen(outfn, "w");
346*593dc095SDavid du Colombier if (out == NULL) {
347*593dc095SDavid du Colombier dlprintf1("pcache: unable to open '%s'\n", outfn);
348*593dc095SDavid du Colombier return -1;
349*593dc095SDavid du Colombier }
350*593dc095SDavid du Colombier
351*593dc095SDavid du Colombier fprintf(out, "# Ghostscript persistent cache index table\n");
352*593dc095SDavid du Colombier
353*593dc095SDavid du Colombier /* construct our cache item */
354*593dc095SDavid du Colombier gp_cache_clear_entry(&item);
355*593dc095SDavid du Colombier item.type = type;
356*593dc095SDavid du Colombier item.key = key;
357*593dc095SDavid du Colombier item.keylen = keylen;
358*593dc095SDavid du Colombier item.buffer = buffer;
359*593dc095SDavid du Colombier item.len = buflen;
360*593dc095SDavid du Colombier item.dirty = 1;
361*593dc095SDavid du Colombier item.last_used = time(NULL);
362*593dc095SDavid du Colombier gp_cache_hash(&item);
363*593dc095SDavid du Colombier gp_cache_filename(prefix, &item);
364*593dc095SDavid du Colombier
365*593dc095SDavid du Colombier /* save it to disk */
366*593dc095SDavid du Colombier path = gp_cache_itempath(prefix, &item);
367*593dc095SDavid du Colombier file = fopen(path, "wb");
368*593dc095SDavid du Colombier if (file != NULL) {
369*593dc095SDavid du Colombier gp_cache_saveitem(file, &item);
370*593dc095SDavid du Colombier fclose(file);
371*593dc095SDavid du Colombier }
372*593dc095SDavid du Colombier
373*593dc095SDavid du Colombier /* now loop through the index to update or insert the entry */
374*593dc095SDavid du Colombier gp_cache_clear_entry(&item2);
375*593dc095SDavid du Colombier while ((code = gp_cache_read_entry(in, &item2)) >= 0) {
376*593dc095SDavid du Colombier if (code == 1) continue;
377*593dc095SDavid du Colombier if (!memcmp(item.hash, item2.hash, 16)) {
378*593dc095SDavid du Colombier /* replace the matching line */
379*593dc095SDavid du Colombier gp_cache_write_entry(out, &item);
380*593dc095SDavid du Colombier hit = 1;
381*593dc095SDavid du Colombier } else {
382*593dc095SDavid du Colombier /* copy out the previous line */
383*593dc095SDavid du Colombier gp_cache_write_entry(out, &item2);
384*593dc095SDavid du Colombier }
385*593dc095SDavid du Colombier }
386*593dc095SDavid du Colombier if (!hit) {
387*593dc095SDavid du Colombier /* there was no matching line */
388*593dc095SDavid du Colombier gp_cache_write_entry(out, &item);
389*593dc095SDavid du Colombier }
390*593dc095SDavid du Colombier free(item.filename);
391*593dc095SDavid du Colombier fclose(out);
392*593dc095SDavid du Colombier fclose(in);
393*593dc095SDavid du Colombier
394*593dc095SDavid du Colombier /* replace the cache index with our new version */
395*593dc095SDavid du Colombier unlink(infn);
396*593dc095SDavid du Colombier rename(outfn,infn);
397*593dc095SDavid du Colombier
398*593dc095SDavid du Colombier free(prefix);
399*593dc095SDavid du Colombier free(infn);
400*593dc095SDavid du Colombier free(outfn);
401*593dc095SDavid du Colombier
402*593dc095SDavid du Colombier return 0;
403*593dc095SDavid du Colombier }
404*593dc095SDavid du Colombier
gp_cache_query(int type,byte * key,int keylen,void ** buffer,gp_cache_alloc alloc,void * userdata)405*593dc095SDavid du Colombier int gp_cache_query(int type, byte* key, int keylen, void **buffer,
406*593dc095SDavid du Colombier gp_cache_alloc alloc, void *userdata)
407*593dc095SDavid du Colombier {
408*593dc095SDavid du Colombier char *prefix, *path;
409*593dc095SDavid du Colombier char *infn,*outfn;
410*593dc095SDavid du Colombier FILE *file, *in, *out;
411*593dc095SDavid du Colombier gp_cache_entry item, item2;
412*593dc095SDavid du Colombier int code, hit = 0;
413*593dc095SDavid du Colombier
414*593dc095SDavid du Colombier prefix = gp_cache_prefix();
415*593dc095SDavid du Colombier infn = gp_cache_indexfilename(prefix);
416*593dc095SDavid du Colombier {
417*593dc095SDavid du Colombier int len = strlen(infn) + 2;
418*593dc095SDavid du Colombier outfn = malloc(len);
419*593dc095SDavid du Colombier memcpy(outfn, infn, len - 2);
420*593dc095SDavid du Colombier outfn[len-2] = '+';
421*593dc095SDavid du Colombier outfn[len-1] = '\0';
422*593dc095SDavid du Colombier }
423*593dc095SDavid du Colombier
424*593dc095SDavid du Colombier in = fopen(infn, "r");
425*593dc095SDavid du Colombier if (in == NULL) {
426*593dc095SDavid du Colombier dlprintf1("pcache: unable to open '%s'\n", infn);
427*593dc095SDavid du Colombier return -1;
428*593dc095SDavid du Colombier }
429*593dc095SDavid du Colombier out = fopen(outfn, "w");
430*593dc095SDavid du Colombier if (out == NULL) {
431*593dc095SDavid du Colombier dlprintf1("pcache: unable to open '%s'\n", outfn);
432*593dc095SDavid du Colombier return -1;
433*593dc095SDavid du Colombier }
434*593dc095SDavid du Colombier
435*593dc095SDavid du Colombier fprintf(out, "# Ghostscript persistent cache index table\n");
436*593dc095SDavid du Colombier
437*593dc095SDavid du Colombier /* construct our query */
438*593dc095SDavid du Colombier gp_cache_clear_entry(&item);
439*593dc095SDavid du Colombier item.type = type;
440*593dc095SDavid du Colombier item.key = key;
441*593dc095SDavid du Colombier item.keylen = keylen;
442*593dc095SDavid du Colombier item.last_used = time(NULL);
443*593dc095SDavid du Colombier gp_cache_hash(&item);
444*593dc095SDavid du Colombier gp_cache_filename(prefix, &item);
445*593dc095SDavid du Colombier
446*593dc095SDavid du Colombier /* look for it on the disk */
447*593dc095SDavid du Colombier path = gp_cache_itempath(prefix, &item);
448*593dc095SDavid du Colombier file = fopen(path, "rb");
449*593dc095SDavid du Colombier if (file != NULL) {
450*593dc095SDavid du Colombier hit = gp_cache_loaditem(file, &item, alloc, userdata);
451*593dc095SDavid du Colombier fclose(file);
452*593dc095SDavid du Colombier } else {
453*593dc095SDavid du Colombier hit = -1;
454*593dc095SDavid du Colombier }
455*593dc095SDavid du Colombier
456*593dc095SDavid du Colombier gp_cache_clear_entry(&item2);
457*593dc095SDavid du Colombier while ((code = gp_cache_read_entry(in, &item2)) >= 0) {
458*593dc095SDavid du Colombier if (code == 1) continue;
459*593dc095SDavid du Colombier if (!hit && !memcmp(item.hash, item2.hash, 16)) {
460*593dc095SDavid du Colombier /* replace the matching line */
461*593dc095SDavid du Colombier gp_cache_write_entry(out, &item);
462*593dc095SDavid du Colombier item.dirty = 0;
463*593dc095SDavid du Colombier } else {
464*593dc095SDavid du Colombier /* copy out the previous line */
465*593dc095SDavid du Colombier gp_cache_write_entry(out, &item2);
466*593dc095SDavid du Colombier }
467*593dc095SDavid du Colombier }
468*593dc095SDavid du Colombier if (item.dirty) {
469*593dc095SDavid du Colombier /* there was no matching line -- shouldn't happen */
470*593dc095SDavid du Colombier gp_cache_write_entry(out, &item);
471*593dc095SDavid du Colombier }
472*593dc095SDavid du Colombier free(item.filename);
473*593dc095SDavid du Colombier fclose(out);
474*593dc095SDavid du Colombier fclose(in);
475*593dc095SDavid du Colombier
476*593dc095SDavid du Colombier /* replace the cache index with our new version */
477*593dc095SDavid du Colombier unlink(infn);
478*593dc095SDavid du Colombier rename(outfn,infn);
479*593dc095SDavid du Colombier
480*593dc095SDavid du Colombier free(prefix);
481*593dc095SDavid du Colombier free(infn);
482*593dc095SDavid du Colombier free(outfn);
483*593dc095SDavid du Colombier
484*593dc095SDavid du Colombier if (!hit) {
485*593dc095SDavid du Colombier *buffer = item.buffer;
486*593dc095SDavid du Colombier return item.len;
487*593dc095SDavid du Colombier } else {
488*593dc095SDavid du Colombier *buffer = NULL;
489*593dc095SDavid du Colombier return -1;
490*593dc095SDavid du Colombier }
491*593dc095SDavid du Colombier }
492