1 /*
2  * The AFFLIB page abstraction.
3  * Distributed under the Berkeley 4-part license
4  */
5 
6 #include "affconfig.h"
7 #include "afflib.h"
8 #include "afflib_i.h"
9 
10 
11 /* af_read_sizes:
12  * Get the page sizes if they are set in the file.
13  */
af_read_sizes(AFFILE * af)14 void af_read_sizes(AFFILE *af)
15 {
16     af_get_seg(af,AF_SECTORSIZE,&af->image_sectorsize,0,0);
17     if(af->image_sectorsize==0) af->image_sectorsize = 512; // reasonable default
18 
19     if(af_get_seg(af,AF_PAGESIZE,&af->image_pagesize,0,0)){
20 	af_get_seg(af,AF_SEGSIZE_D,&af->image_pagesize,0,0); // try old name
21     }
22 
23     /* Read the badflag if it is present.
24      * Be sure to adjust badflag size to current sector size (which may have changed).
25      */
26     if(af->badflag!=0) free(af->badflag);
27     af->badflag = (unsigned char *)malloc(af->image_sectorsize);
28     size_t sectorsize = af->image_sectorsize;
29     if(af_get_seg(af,AF_BADFLAG,0,af->badflag,(size_t *)&sectorsize)==0){
30 	af->badflag_set = 1;
31     }
32 
33     /* Read the image file segment if it is present.
34      * If it isn't, scan through the disk image to figure out the size of the disk image.
35      */
36 
37     if(af_get_segq(af,AF_IMAGESIZE,(int64_t *)&af->image_size)){
38 
39 	/* Calculate the imagesize by scanning all of the pages that are in
40 	 * the disk image and finding the highest page number.
41 	 * Then read that page to find the last allocated byte.
42 	 */
43 	char segname[AF_MAX_NAME_LEN];
44 	size_t datalen = 0;
45 	af_rewind_seg(af);		//  start at the beginning
46 	int64_t highest_page_number = 0;
47 	while(af_get_next_seg(af,segname,sizeof(segname),0,0,&datalen)==0){
48 	    if(segname[0]==0) continue;	// ignore sector
49 	    int64_t pagenum = af_segname_page_number(segname);
50 	    if(pagenum > highest_page_number) highest_page_number = pagenum;
51 	}
52 	size_t highest_page_len = 0;
53 	if(af_get_page(af,highest_page_number,0,&highest_page_len)==0){
54 	    af->image_size = af->image_pagesize * highest_page_number + highest_page_len;
55 	}
56     }
57     af->image_size_in_file = af->image_size;
58 }
59 
60 
af_page_size(AFFILE * af)61 int af_page_size(AFFILE *af)
62 {
63     return af->image_pagesize;
64 }
65 
af_get_pagesize(AFFILE * af)66 int af_get_pagesize(AFFILE *af)
67 {
68     return af->image_pagesize;
69 }
70 
71 /* af_set_sectorsize:
72  * Sets the sectorsize.
73  * Fails with -1 if imagesize >=0 unless these changes permitted
74  */
af_set_sectorsize(AFFILE * af,int sectorsize)75 int af_set_sectorsize(AFFILE *af,int sectorsize)
76 {
77     struct af_vnode_info vni;
78     af_vstat(af,&vni);
79     if(vni.changable_pagesize==0 && af->image_size>0){
80 	errno = EINVAL;
81 	return -1;
82     }
83     af->image_sectorsize =sectorsize;
84     if(af->badflag==0) af->badflag = (unsigned char *)malloc(sectorsize);
85     else af->badflag = (unsigned char *)realloc(af->badflag,sectorsize);
86     af->badflag_set = 0;
87 
88     if(af_update_seg(af,AF_SECTORSIZE,sectorsize,0,0)){
89 	if(errno != ENOTSUP) return -1;
90     }
91     return 0;
92 }
93 
af_get_sectorsize(AFFILE * af)94 int	af_get_sectorsize(AFFILE *af)	// returns sector size
95 {
96     return af->image_sectorsize;
97 }
98 
99 /*
100  * af_set_pagesize:
101  * Sets the pagesize. Fails with -1 if it can't be changed.
102  */
af_set_pagesize(AFFILE * af,uint32_t pagesize)103 int af_set_pagesize(AFFILE *af,uint32_t pagesize)
104 {
105     /* Allow the pagesize to be changed if it hasn't been set yet
106      * and if this format doesn't support metadata updating (which is the raw formats)
107      */
108     struct af_vnode_info vni;
109 
110     af_vstat(af,&vni);
111 
112     if(vni.changable_pagesize==0 && af->image_size>0){
113 	if(pagesize==af->image_pagesize) return 0; // it's already set to this, so let it pass
114 	errno = EINVAL;
115 	return -1;
116     }
117     if(pagesize % af->image_sectorsize != 0){
118 	(*af->error_reporter)("Cannot set pagesize to %d (sectorsize=%d)\n",
119 			      pagesize,af->image_sectorsize);
120 	errno = EINVAL;
121 	return -1;
122     }
123 
124     af->image_pagesize = pagesize;
125     if(af_update_seg(af,AF_PAGESIZE,pagesize,0,0)){
126 	if(errno != ENOTSUP) return -1;	// error updating (don't report ENOTSUP);
127     }
128     return 0;
129 }
130 
131 
132 /****************************************************************
133  *** page-level interface
134  ****************************************************************/
135 
af_get_page_raw(AFFILE * af,int64_t pagenum,uint32_t * arg,unsigned char * data,size_t * bytes)136 int af_get_page_raw(AFFILE *af,int64_t pagenum,uint32_t *arg,
137 		    unsigned char *data,size_t *bytes)
138 {
139     char segname[AF_MAX_NAME_LEN];
140 
141     memset(segname,0,sizeof(segname));
142     sprintf(segname,AF_PAGE,pagenum);
143     int r = af_get_seg(af,segname,arg,data,bytes);
144     if(r < 0 && errno == ENOENT)
145     {
146 	/* Couldn't read with AF_PAGE; try AF_SEG_D.
147 	 * This is legacy for the old AFF files. Perhaps we should delete it.
148 	 */
149 	sprintf(segname,AF_SEG_D,pagenum);
150 	r = af_get_seg(af,segname,arg,data,bytes);
151     }
152     /* Update the counters */
153     if(r==0 && bytes && *bytes>0) af->pages_read++; // note that we read a page
154     return r;
155 }
156 
157 /* af_get_page:
158  * Get a page from its named segment.
159  * If the page is compressed, uncompress it.
160  * data points to a segmenet of at least *bytes;
161  * *bytes is then modified to indicate the actual amount of bytes read.
162  * Return 0 if success, -1 if fail.
163  */
164 
af_get_page(AFFILE * af,int64_t pagenum,unsigned char * data,size_t * bytes)165 int af_get_page(AFFILE *af,int64_t pagenum,unsigned char *data,size_t *bytes)
166 {
167     uint32_t arg=0;
168     size_t page_len=0;
169 
170     if (af_trace){
171 	fprintf(af_trace,"af_get_page(%p,pagenum=%" I64d ",buf=%p,bytes=%u)\n",af,pagenum,data,(int)*bytes);
172     }
173 
174     /* Find out the size of the segment and if it is compressed or not.
175      * If we can't find it with new nomenclature, try the old one...
176      */
177     int r = af_get_page_raw(af,pagenum,&arg,0,&page_len);
178     if(r){
179 	/* Segment doesn't exist.
180 	 * If we have been provided with a buffer,
181 	 * fill buffer with the 'bad segment' flag and return.
182 	 */
183 	if(data && (af->openmode & AF_BADBLOCK_FILL) && errno == ENOENT)
184 	{
185 	    for(size_t i = 0;i <= af->image_pagesize - af->image_sectorsize;
186 		i+= af->image_sectorsize){
187 		memcpy(data+i,af->badflag,af->image_sectorsize);
188 		af->bytes_memcpy += af->image_sectorsize;
189 	    }
190 
191 	    r = 0;
192 	}
193 	return r;		// segment doesn't exist
194     }
195 
196 
197     /* If the segment isn't compressed, just get it*/
198     uint32_t pageflag = 0;
199     if((arg & AF_PAGE_COMPRESSED)==0){
200 	if(data==0){			// if no data provided, just return size of the segment if requested
201 	    if(bytes) *bytes = page_len;	// set the number of bytes in the page if requested
202 	    return 0;
203 	}
204 	int ret = af_get_page_raw(af,pagenum,&pageflag,data,bytes);
205 	if(*bytes > page_len) *bytes = page_len; // we only read this much
206 	if(ret!=0) return ret;		// some error happened?
207     }
208     else {
209 	/* Allocate memory to hold the compressed segment */
210 	unsigned char *compressed_data = (unsigned char *)malloc(page_len);
211 	size_t compressed_data_len = page_len;
212 	if(compressed_data==0){
213 	    return -2;			// memory error
214 	}
215 
216 	/* Get the data */
217 	if(af_get_page_raw(af,pagenum,&pageflag,compressed_data,&compressed_data_len)){
218 	    free(compressed_data);
219 	    return -3;			// read error
220 	}
221 
222 	/* Now uncompress directly into the buffer provided by the caller, unless the caller didn't
223 	 * provide a buffer. If that happens, allocate our own...
224 	 */
225 	int res = -1;			// 0 is success
226 	bool free_data = false;
227 	if(data==0){
228 	    data = (unsigned char *)malloc(af->image_pagesize);
229 	    free_data = true;
230 	    *bytes = af->image_pagesize; // I can hold this much
231 	}
232 
233 	switch((pageflag & AF_PAGE_COMP_ALG_MASK)){
234 	case AF_PAGE_COMP_ALG_ZERO:
235 	    if(compressed_data_len != 4){
236 		(*af->error_reporter)("ALG_ZERO compressed data is %d bytes, expected 4.",compressed_data_len);
237 		break;
238 	    }
239 	    memset(data,0,af->image_pagesize);
240 	    *bytes = ntohl(*(long *)compressed_data);
241 	    res = 0;			// not very hard to decompress with the ZERO compressor.
242 	    break;
243 
244 	case AF_PAGE_COMP_ALG_ZLIB:
245 	    res = uncompress(data,(uLongf *)bytes,compressed_data,compressed_data_len);
246 	    switch(res){
247 	    case Z_OK:
248 		break;
249 	    case Z_ERRNO:
250 		(*af->error_reporter)("Z_ERRNOR decompressing segment %" I64d,pagenum);
251 	    case Z_STREAM_ERROR:
252 		(*af->error_reporter)("Z_STREAM_ERROR decompressing segment %" I64d,pagenum);
253 	    case Z_DATA_ERROR:
254 		(*af->error_reporter)("Z_DATA_ERROR decompressing segment %" I64d,pagenum);
255 	    case Z_MEM_ERROR:
256 		(*af->error_reporter)("Z_MEM_ERROR decompressing segment %" I64d,pagenum);
257 	    case Z_BUF_ERROR:
258 		(*af->error_reporter)("Z_BUF_ERROR decompressing segment %" I64d,pagenum);
259 	    case Z_VERSION_ERROR:
260 		(*af->error_reporter)("Z_VERSION_ERROR decompressing segment %" I64d,pagenum);
261 	    default:
262 		(*af->error_reporter)("uncompress returned an invalid value in get_segment");
263 	    }
264 	    break;
265 
266 #ifdef USE_LZMA
267 	case AF_PAGE_COMP_ALG_LZMA:
268 	    res = lzma_uncompress(data,bytes,compressed_data,compressed_data_len);
269 	    if (af_trace) fprintf(af_trace,"   LZMA decompressed page %" I64d ". %d bytes => %u bytes\n",
270 				  pagenum,(int)compressed_data_len,(int)*bytes);
271 	    switch(res){
272 	    case 0:break;		// OK
273 	    case 1:(*af->error_reporter)("LZMA header error decompressing segment %" I64d "\n",pagenum);
274 		break;
275 	    case 2:(*af->error_reporter)("LZMA memory error decompressing segment %" I64d "\n",pagenum);
276 		break;
277 	    }
278 	    break;
279 #endif
280 
281 	default:
282 	    (*af->error_reporter)("Unknown compression algorithm 0x%d",
283 				  pageflag & AF_PAGE_COMP_ALG_MASK);
284 	    break;
285 	}
286 
287 	if(free_data){
288 	    free(data);
289 	    data = 0;			// restore the way it was
290 	}
291 	free(compressed_data);		// don't need this one anymore
292 	af->pages_decompressed++;
293 	if(res!=Z_OK) return -1;
294     }
295 
296     /* If the page size is larger than the sector_size,
297      * make sure that the rest of the sector is zeroed, and that the
298      * rest after that has the 'bad block' notation.
299      */
300     if(data && (af->image_pagesize > af->image_sectorsize)){
301 	const int SECTOR_SIZE = af->image_sectorsize;	// for ease of typing
302 	size_t bytes_left_in_sector = (SECTOR_SIZE - (*bytes % SECTOR_SIZE)) % SECTOR_SIZE;
303 	for(size_t i=0;i<bytes_left_in_sector;i++){
304 	    data[*bytes + i] = 0;
305 	}
306 	size_t end_of_data = *bytes + bytes_left_in_sector;
307 
308 	/* Now fill to the end of the page... */
309 	for(size_t i = end_of_data; i <= af->image_pagesize-SECTOR_SIZE; i+=SECTOR_SIZE){
310 	    memcpy(data+i,af->badflag,SECTOR_SIZE);
311 	    af->bytes_memcpy += SECTOR_SIZE;
312 	}
313     }
314     return 0;
315 }
316 
317 
is_buffer_zero(unsigned char * buf,int buflen)318 static bool is_buffer_zero(unsigned char *buf,int buflen)
319 {
320     if(buflen >= (int)sizeof(long))
321     {
322         // align to word boundary
323         buflen -= (intptr_t)buf % sizeof(long);
324 
325         while((intptr_t)buf % sizeof(long))
326         {
327             if(*buf++)
328                 return false;
329         }
330 
331         // read in words
332         long *ptr = (long*)buf;
333         buf += buflen - buflen % sizeof(long);
334         buflen %= sizeof(long);
335 
336         while(ptr < (long*)buf)
337         {
338             if(*ptr++)
339                 return false;
340         }
341     }
342 
343     while(buflen--)
344     {
345         if(*buf++)
346             return false;
347     }
348 
349     return true;
350 }
351 
352 /* Write a actual data segment to the disk and sign if necessary. */
af_update_page(AFFILE * af,int64_t pagenum,unsigned char * data,int datalen)353 int af_update_page(AFFILE *af,int64_t pagenum,unsigned char *data,int datalen)
354 {
355     char segname_buf[32];
356     snprintf(segname_buf,sizeof(segname_buf),AF_PAGE,pagenum); // determine segment name
357 
358 #ifdef USE_AFFSIGS
359     /* Write out the signature if we have a private key */
360     if(af->crypto && af->crypto->sign_privkey){
361 	af_sign_seg3(af,segname_buf,0,data,datalen,AF_SIGNATURE_MODE1);
362     }
363 #endif
364 
365 #ifdef HAVE_MD5
366     /* Write out MD5 if requested */
367     if(af->write_md5){
368 	unsigned char md5_buf[16];
369 	char md5name_buf[32];
370 	MD5(data,datalen,md5_buf);
371 	snprintf(md5name_buf,sizeof(md5name_buf),AF_PAGE_MD5,pagenum);
372 	af_update_segf(af,md5name_buf,0,md5_buf,sizeof(md5_buf),AF_SIGFLAG_NOSIG); // ignore failure
373     }
374 #endif
375 #ifdef HAVE_SHA1
376     /* Write out SHA1 if requested */
377     if(af->write_sha1){
378 	unsigned char sha1_buf[20];
379 	char sha1name_buf[32];
380 	SHA1(data,datalen,sha1_buf);
381 	snprintf(sha1name_buf,sizeof(sha1name_buf),AF_PAGE_SHA1,pagenum);
382 	af_update_segf(af,sha1name_buf,0,sha1_buf,sizeof(sha1_buf),AF_SIGFLAG_NOSIG); // ignore failure
383     }
384 #endif
385     /* Write out SHA256 if requested and if SHA256 is available */
386     if(af->write_sha256){
387 	unsigned char sha256_buf[32];
388 	if(af_SHA256(data,datalen,sha256_buf)==0){
389 	    char sha256name_buf[32];
390 	    snprintf(sha256name_buf,sizeof(sha256name_buf),AF_PAGE_SHA256,pagenum);
391 	    af_update_segf(af,sha256name_buf,0,sha256_buf,sizeof(sha256_buf),AF_SIGFLAG_NOSIG); // ignore failure
392 	}
393     }
394 
395     /* Check for bypass */
396     if(af->v->write){
397 	int r = (*af->v->write)(af,data,af->image_pagesize * pagenum,datalen);
398 	if(r!=datalen) return -1;
399 	return 0;
400     }
401 
402     struct affcallback_info acbi;
403     int ret = 0;
404     uint64_t starting_pages_written = af->pages_written;
405 
406     /* Setup the callback structure */
407     memset(&acbi,0,sizeof(acbi));
408     acbi.info_version = 1;
409     acbi.af = af->parent ? af->parent : af;
410     acbi.pagenum = pagenum;
411     acbi.bytes_to_write = datalen;
412 
413     size_t destLen = af->image_pagesize;	// it could be this big.
414 
415     /* Compress and write the data, if we are allowed to compress */
416     if(af->compression_type != AF_COMPRESSION_ALG_NONE){
417 	unsigned char *cdata = (unsigned char *)malloc(destLen); // compressed data
418 	uint32_t *ldata = (uint32_t *)cdata; // allows me to reference as a buffer of uint32_ts
419 	if(cdata!=0){		// If data could be allocated
420 	    int cres = -1;		// compression results
421 	    uint32_t flag = 0;	// flag for data segment
422 	    int dont_compress = 0;
423 
424 	    /* Try zero compression first; it's the best algorithm we have  */
425 	    if(is_buffer_zero(data,datalen)){
426 		acbi.compression_alg   = AF_PAGE_COMP_ALG_ZERO;
427 		acbi.compression_level = AF_COMPRESSION_MAX;
428 
429 		if(af->w_callback) { acbi.phase = 1; (*af->w_callback)(&acbi); }
430 
431 		*ldata = htonl(datalen); // store the data length
432 		destLen = 4;		 // 4 bytes
433 		flag = AF_PAGE_COMPRESSED | AF_PAGE_COMP_ALG_ZERO | AF_PAGE_COMP_MAX;
434 		cres = 0;
435 
436 		acbi.compressed = 1;		// it was compressed
437 		if(af->w_callback) {acbi.phase = 2;(*af->w_callback)(&acbi);}
438 	    }
439 
440 #ifdef USE_LZMA
441 	    if(cres!=0 && af->compression_type==AF_COMPRESSION_ALG_LZMA){ // try to compress with LZMA
442 		acbi.compression_alg   = AF_PAGE_COMP_ALG_LZMA;
443 		acbi.compression_level = 7; // right now, this is the level we use
444 		if(af->w_callback) { acbi.phase = 1; (*af->w_callback)(&acbi); }
445 
446 		cres = lzma_compress(cdata,&destLen,data,datalen,9);
447 #if 0
448 		switch(cres){
449 		case 0:break;		// OKAY
450 		case 1: (*af->error_reporter)("LZMA: Unspecified Error\n");break;
451 		case 2: (*af->error_reporter)("LZMA: Memory Allocating Error\n");break;
452 		case 3: (*af->error_reporter)("LZMA: Output buffer OVERFLOW\n"); break;
453 		default: (*af->error_reporter)("LZMA: Unknown error %d\n",cres);break;
454 		}
455 #endif
456 		if(cres==0){
457 		    flag = AF_PAGE_COMPRESSED | AF_PAGE_COMP_ALG_LZMA;
458 		    acbi.compressed = 1;
459 		    if(af->w_callback) {acbi.phase = 2;(*af->w_callback)(&acbi);}
460 		}
461 		else {
462 		    /* Don't bother reporting LZMA errors; we just won't compress */
463 		    dont_compress = 1;
464 		    if(af->w_callback) {acbi.phase = 2;(*af->w_callback)(&acbi);}
465 		}
466 	    }
467 #endif
468 
469 	    if(cres!=0
470 	       && af->compression_type==AF_COMPRESSION_ALG_ZLIB
471 	       && dont_compress==0){ // try to compress with zlib
472 		acbi.compression_alg   = AF_PAGE_COMP_ALG_ZLIB; // only one that we support
473 		acbi.compression_level = af->compression_level;
474 		if(af->w_callback) { acbi.phase = 1; (*af->w_callback)(&acbi); }
475 
476 		cres = compress2((Bytef *)cdata, (uLongf *)&destLen,
477 				 (Bytef *)data,datalen, af->compression_level);
478 
479 		if(cres==0){
480 		    flag = AF_PAGE_COMPRESSED | AF_PAGE_COMP_ALG_ZLIB;
481 		    if(af->compression_level == AF_COMPRESSION_MAX){
482 			flag |= AF_PAGE_COMP_MAX; // useful to know it can't be better
483 		    }
484 		}
485 		acbi.compressed = 1;	// it was compressed (or not compressed)
486 		if(af->w_callback) {acbi.phase = 2;(*af->w_callback)(&acbi);}
487 	    }
488 
489 	    if(cres==0 && destLen < af->image_pagesize){
490 		/* Prepare to write out the compressed segment with compression */
491 		if(af->w_callback) {acbi.phase = 3;(*af->w_callback)(&acbi);}
492 		ret = af_update_segf(af,segname_buf,flag,cdata,destLen,AF_SIGFLAG_NOSIG);
493 		acbi.bytes_written = destLen;
494 		if(af->w_callback) {acbi.phase = 4;(*af->w_callback)(&acbi);}
495 		if(ret==0){
496 		    af->pages_written++;
497 		    af->pages_compressed++;
498 		}
499 	    }
500 	    free(cdata);
501 	    cdata = 0;
502 	}
503     }
504 
505     /* If a compressed segment was not written, write it uncompressed */
506     if(af->pages_written == starting_pages_written){
507 	if(af->w_callback) {acbi.phase = 3;(*af->w_callback)(&acbi);}
508 	ret = af_update_segf(af,segname_buf,0,data,datalen,AF_SIGFLAG_NOSIG);
509 	acbi.bytes_written = datalen;
510 	if(af->w_callback) {acbi.phase = 4;(*af->w_callback)(&acbi);}
511 	if(ret==0){
512 	    acbi.bytes_written = datalen;	// because that is how much we wrote
513 	    af->pages_written++;
514 	}
515     }
516     return ret;
517 }
518 
519 /****************************************************************
520  *** Cache interface
521  ****************************************************************/
522 
523 /* The page cache is a read/write cache.
524  *
525  * Pages that are read are cached after they are decompressed.
526  * When new pages are fetched, we check the cache first to see if they are there;
527  * if so, they are satsfied by the cache.
528  *
529  * Modifications are written to the cache, then dumped to the disk.
530  *
531  * The cache is managed by two functions:
532  * af_cache_flush(af) - (prevously af_purge)
533  *      - Makes sure that all dirty buffers are written.
534  *      - Sets af->pb=NULL (no current page)
535  *      - (returns 0 if success, -1 if failure.)
536  *
537  * af_cache_writethrough(af,page,buf,buflen)
538  *      - used for write bypass
539  *
540  */
541 
542 static int cachetime = 0;
543 
544 
af_cache_flush(AFFILE * af)545 int af_cache_flush(AFFILE *af)
546 {
547     if(af_trace) fprintf(af_trace,"af_cache_flush()\n");
548     int ret = 0;
549     for(int i=0;i<af->num_pbufs;i++){
550 	struct aff_pagebuf *p = &af->pbcache[i];
551 	if(p->pagebuf_valid && p->pagebuf_dirty){
552 	    if(af_update_page(af,p->pagenum,p->pagebuf,p->pagebuf_bytes)){
553 		ret = -1;		// got an error; keep going, though
554 	    }
555 	    p->pagebuf_dirty = 0;
556 	    if(af_trace) fprintf(af_trace,"af_cache_flush: slot %d page %" PRIu64 " flushed.\n",i,p->pagenum);
557 	}
558     }
559     return ret;				// now return the error that I might have gotten
560 }
561 
562 /* If the page being written is in the cache, update it.
563  * Question: would it make sense to copy the data anyway? I don't think so, because
564  * the main use of writethrough is when imaging, and in that event you probably don't
565  * want the extra memcpy.
566  */
af_cache_writethrough(AFFILE * af,int64_t pagenum,const unsigned char * buf,int bufflen)567 void af_cache_writethrough(AFFILE *af,int64_t pagenum,const unsigned char *buf,int bufflen)
568 {
569     for(int i=0;i<af->num_pbufs;i++){
570 	struct aff_pagebuf *p = &af->pbcache[i];
571 	if(p->pagenum_valid && p->pagenum == pagenum){
572 	    if(p->pagebuf_dirty){
573 		(*af->error_reporter)("af_cache_writethrough: overwriting page %" I64u ".\n",pagenum);
574 		exit(-1);		// this shouldn't happen
575 	    }
576 	    memcpy(p->pagebuf,buf,bufflen);
577 	    memset(p->pagebuf+bufflen,0,af->image_pagesize-bufflen); // zero fill the rest
578 	    af->bytes_memcpy += bufflen;
579 	    p->pagebuf_valid = 1;	// we have a copy of it now.
580 	    p->pagebuf_dirty = 0;	// but it isn't dirty
581 	    p->last = cachetime++;
582 	}
583     }
584 }
585 
586 #ifdef HAVE_MALLOC_H
587 #include <malloc.h>
588 #endif
589 
590 #ifndef HAVE_VALLOC
591 #define valloc malloc
592 #endif
593 
af_cache_alloc(AFFILE * af,int64_t pagenum)594 struct aff_pagebuf *af_cache_alloc(AFFILE *af,int64_t pagenum)
595 {
596     if(af_trace) fprintf(af_trace,"af_cache_alloc(%p,%" I64d ")\n",af,pagenum);
597 
598     /* Make sure nothing in the cache is dirty */
599     if(af_cache_flush(af) < 0)
600 	return 0;
601 
602     /* See if this page is already in the cache */
603     for(int i=0;i<af->num_pbufs;i++){
604 	struct aff_pagebuf *p = &af->pbcache[i];
605 	if(p->pagenum_valid && p->pagenum==pagenum){
606 	    af->cache_hits++;
607 	    if(af_trace) fprintf(af_trace,"  page %" I64d " satisfied fromcache\n",pagenum);
608 	    p->last = cachetime++;
609 	    return p;
610 	}
611     }
612 
613     af->cache_misses++;
614     int slot = -1;
615     /* See if there is an empty slot in the cache */
616     for(int i=0;i<af->num_pbufs;i++){
617 	struct aff_pagebuf *p = &af->pbcache[i];
618 	if(p->pagenum_valid==0){
619 	    slot = i;
620 	    if(af_trace) fprintf(af_trace,"  slot %d given to page %" I64d "\n",slot,pagenum);
621 	    break;
622 	}
623     }
624     if(slot==-1){
625 	/* Find the oldest cache entry */
626 	int oldest_i = 0;
627 	int oldest_t = af->pbcache[0].last;
628 	for(int i=1;i<af->num_pbufs;i++){
629 	    if(af->pbcache[i].last < oldest_t){
630 		oldest_t = af->pbcache[i].last;
631 		oldest_i = i;
632 	    }
633 	}
634 	slot = oldest_i;
635 	if(af_trace) fprintf(af_trace,"  slot %d assigned to page %" I64d "\n",slot,pagenum);
636     }
637     /* take over this slot */
638     struct aff_pagebuf *p = &af->pbcache[slot];
639     if(p->pagebuf==0){
640 	p->pagebuf = (unsigned char *)valloc(af->image_pagesize); // allocate to a page boundary
641 	if(p->pagebuf==0){
642 	    /* Malloc failed; See if we can just use the first slot */
643 	    slot = 0;
644 	    if(af->pbcache[0].pagebuf==0) return 0; // ugh. Cannot malloc?
645 
646 	    /* First slot is available. Just use it. */
647 	    p = &af->pbcache[0];
648 	}
649     }
650     memset(p->pagebuf,0,af->image_pagesize); // clean object reuse
651     p->pagenum = pagenum;
652     p->pagenum_valid = 1;
653     p->pagebuf_valid = 0;
654     p->pagebuf_dirty = 0;
655     p->last = cachetime++;
656     if(af_trace){
657 	fprintf(af_trace,"   current pages in cache: ");
658 	for(int i=0;i<af->num_pbufs;i++){
659 	    fprintf(af_trace," %" I64d,af->pbcache[i].pagenum);
660 	}
661 	fprintf(af_trace,"\n");
662     }
663     return p;
664 }
665 
666 
667 
668 
669