📄 afflib_pages.cpp
字号:
/* * The AFFLIB page abstraction. *//* * Copyright (c) 2005, 2006 * Simson L. Garfinkel and Basis Technology, Inc. * All rights reserved. * * This code is derrived from software contributed by * Simson L. Garfinkel * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Simson L. Garfinkel * and Basis Technology Corp. * 4. Neither the name of Simson Garfinkel, Basis Technology, or other * contributors to this program may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "config.h"#include "afflib.h"#include "afflib_i.h"/* af_read_sizes: * Get the page sizes if they are set in the file. */void af_read_sizes(AFFILE *af){ if(af_get_seg(af,AF_PAGESIZE,&af->image_pagesize,0,0)){ af_get_seg(af,AF_SEGSIZE_D,&af->image_pagesize,0,0); // try old name } if(af_get_segq(af,AF_IMAGESIZE,(int64 *)&af->image_size)){ /* Need to recover the image size */ char segname[AF_MAX_NAME_LEN]; unsigned long arg; size_t datalen = 0; af_rewind_seg(af); // start at the beginning int64 highest_page = -1; while(af_get_next_seg(af,segname,sizeof(segname),&arg,0,&datalen)==0){ if(segname[0]==0) continue; // ignore sector int64 pagenum = af_segname_page_number(segname); if(pagenum > highest_page) highest_page = pagenum; } af->image_size = af->image_pagesize * (highest_page+1); } af->image_size_in_file = af->image_size; af_get_seg(af,AF_SECTORSIZE,&af->image_sectorsize,0,0); if(af->image_sectorsize==0) af->image_sectorsize = 512; // reasonable default size_t sectorsize = af->image_sectorsize; if(af->badflag==0) af->badflag = (unsigned char *)malloc(sectorsize); if(af_get_seg(af,AF_BADFLAG,0,af->badflag,(size_t *)§orsize)==0){ af->badflag_set = 1; }}int af_page_size(AFFILE *af){ return af->image_pagesize;}/* af_set_sectorsize: * Sets the sectorsize. * Fails with -1 if imagesize >=0 unless these changes permitted */int af_set_sectorsize(AFFILE *af,int sectorsize){ struct af_vnode_info vni; af_vstat(af,&vni); if(vni.changable_pagesize==0 && af->image_size>0){ errno = EINVAL; return -1; } af->image_sectorsize =sectorsize; if(af->badflag==0) af->badflag = (unsigned char *)malloc(sectorsize); else af->badflag = (unsigned char *)realloc(af->badflag,sectorsize); af->badflag_set = 0; if(af_update_seg(af,AF_SECTORSIZE,sectorsize,0,0)){ if(errno != ENOTSUP) return -1; } return 0;}/* * af_set_pagesize: * Sets the pagesize. Fails with -1 if it can't be changed. */int af_set_pagesize(AFFILE *af,long pagesize){ /* Allow the pagesize to be changed if it hasn't been set yet * and if this format doesn't support metadata updating (which is the raw formats) */ struct af_vnode_info vni; af_vstat(af,&vni); if(vni.changable_pagesize==0 && af->image_size>0){ if(pagesize==af->image_pagesize) return 0; // it's already set to this, so let it pass errno = EINVAL; return -1; } if(pagesize % af->image_sectorsize != 0){ (*af->error_reporter)("Cannot set pagesize to %d (sectorsize=%d)\n", pagesize,af->image_sectorsize); errno = EINVAL; return -1; } af->image_pagesize = pagesize; if(af_update_seg(af,AF_PAGESIZE,pagesize,0,0)){ if(errno != ENOTSUP) return -1; // error updating (don't report ENOTSUP); } return 0;}/**************************************************************** *** page-level interface ****************************************************************/int af_get_page_raw(AFFILE *af,int64 pagenum,unsigned long *arg, unsigned char *data,size_t *bytes){ char segname[AF_MAX_NAME_LEN]; memset(segname,0,sizeof(segname)); sprintf(segname,AF_PAGE,pagenum); int r = af_get_seg(af,segname,arg,data,bytes); if(r!=0){ /* Couldn't read with AF_PAGE; try AF_SEG_D */ sprintf(segname,AF_SEG_D,pagenum); r = af_get_seg(af,segname,arg,data,bytes); } if(r==0 && bytes && *bytes>0) af->pages_read++; // note that we read a page return r;}/* af_get_page: * Get a page from its named segment. * If the page is compressed, uncompress it. * data points to a segmenet of at least *bytes; * *bytes is then modified to indicate the actual amount of bytes read. * if shouldfree is set, then data should be freed. * Return 0 if success, -1 if fail. */int af_get_page(AFFILE *af,int64 pagenum,unsigned char *data,size_t *bytes){ unsigned long arg=0; size_t page_len=0; if (af_trace) fprintf(af_trace,"af_get_page(%p,pagenum=%"I64d",buf=%p,bytes=%d)\n",af,pagenum,data,bytes); /* Find out the size of the segment and if it is compressed or not. * If we can't find it with new nomenclature, try the old one... */ if(af_get_page_raw(af,pagenum,&arg,0,&page_len)){ /* Segment doesn't exist. * If we have been provided with a buffer, fill buffer with the 'bad segment' flag and return. */ if (data) { for(size_t i = 0;i <= af->image_pagesize - af->image_sectorsize; i+= af->image_sectorsize){ memcpy(data+i,af->badflag,af->image_sectorsize); af->bytes_memcpy += af->image_sectorsize; } } return -1; // segment doesn't exist } /* If no data buffer was provided, just return */ if(data==0) return 0; /* If the segment isn't compressed, just get it*/ unsigned long pageflag = 0; if((arg & AF_PAGE_COMPRESSED)==0){ int ret = af_get_page_raw(af,pagenum,&pageflag,data,bytes); if(*bytes > page_len) *bytes = page_len; // we only read this much if(ret!=0) return ret; // some error happened? } else { /* Allocate memory to hold the compressed segment */ unsigned char *compressed_data = (unsigned char *)malloc(page_len); size_t compressed_data_len = page_len; if(compressed_data==0){ return -2; // memory error } /* Get the data */ if(af_get_page_raw(af,pagenum,&pageflag,compressed_data,&compressed_data_len)){ free(compressed_data); return -3; // read error } /* Now uncompress directly into the buffer provided by the caller. */ int res = -1; // 0 is success switch((pageflag & AF_PAGE_COMP_ALG_MASK)){ case AF_PAGE_COMP_ALG_ZERO: if(compressed_data_len != 4){ (*af->error_reporter)("ALG_ZERO compressed data is %d bytes, expected 4.",compressed_data_len); break; } memset(data,0,af->image_pagesize); *bytes = ntohl(*(long *)compressed_data); res = 0; // not very hard to decompress with the ZERO compressor. break; case AF_PAGE_COMP_ALG_ZLIB: res = uncompress(data,(uLongf *)bytes,compressed_data,compressed_data_len); switch(res){ case Z_OK: break; case Z_ERRNO: (*af->error_reporter)("Z_ERRNOR decompressing segment %"I64d,pagenum); case Z_STREAM_ERROR: (*af->error_reporter)("Z_STREAM_ERROR decompressing segment %"I64d,pagenum); case Z_DATA_ERROR: (*af->error_reporter)("Z_DATA_ERROR decompressing segment %"I64d,pagenum); case Z_MEM_ERROR: (*af->error_reporter)("Z_MEM_ERROR decompressing segment %"I64d,pagenum); case Z_BUF_ERROR: (*af->error_reporter)("Z_BUF_ERROR decompressing segment %"I64d,pagenum); case Z_VERSION_ERROR: (*af->error_reporter)("Z_VERSION_ERROR decompressing segment %"I64d,pagenum); default: (*af->error_reporter)("uncompress returned an invalid value in get_segment"); } break;#ifdef USE_LZMA case AF_PAGE_COMP_ALG_LZMA: res = lzma_uncompress(data,bytes,compressed_data,compressed_data_len); if (af_trace) fprintf(af_trace," LZMA decompressed page %"I64d". %d bytes => %d bytes\n", pagenum,compressed_data_len,*bytes); switch(res){ case 0:break; // OK case 1:(*af->error_reporter)("LZMA header error decompressing segment %"I64d"\n",pagenum); break; case 2:(*af->error_reporter)("LZMA memory error decompressing segment %"I64d"\n",pagenum); break; } break;#endif default: (*af->error_reporter)("Unknown compression algorithm 0x%d", pageflag & AF_PAGE_COMP_ALG_MASK); break; } free(compressed_data); // don't need this one anymore af->pages_decompressed++; if(res!=Z_OK) return -1; } /* If the page size is larger than the sector_size, * make sure that the rest of the sector is zeroed, and that the * rest after that has the 'bad block' notation. */ if(af->image_pagesize > af->image_sectorsize){ const int SECTOR_SIZE = af->image_sectorsize; // for ease of typing size_t bytes_left_in_sector = (SECTOR_SIZE - (*bytes % SECTOR_SIZE)) % SECTOR_SIZE; for(size_t i=0;i<bytes_left_in_sector;i++){ data[*bytes + i] = 0; } size_t end_of_data = *bytes + bytes_left_in_sector; /* Now fill to the end of the page... */ for(size_t i = end_of_data; i <= af->image_pagesize-SECTOR_SIZE; i+=SECTOR_SIZE){ memcpy(data+i,af->badflag,SECTOR_SIZE); af->bytes_memcpy += SECTOR_SIZE; } } return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -