📄 afflib.cpp
字号:
/* * Copyright (c) 2005 * 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"#include "vnode_raw.h"#include "vnode_split_raw.h"#include "vnode_afm.h"#include "vnode_aff.h"#include "vnode_afd.h"#include "vnode_ewf.h"#ifdef USE_S3#include "vnode_s3.h"#endif#include <fcntl.h>#include <assert.h>//#include <openssl/rand.h>#include <errno.h>// vnode implementations.// order mattersstruct af_vnode *af_vnode_array[] = {#ifdef USE_S3 &vnode_s3, // must be first for s3:// interpertation#endif &vnode_afd, &vnode_afm, // must be before aff &vnode_aff,#ifdef USE_LIBEWF &vnode_ewf, // libewf#endif &vnode_split_raw, // must be before raw &vnode_raw, // greedy; must be last 0};/* Returns the name and offset of the last segment */int af_last_seg(AFFILE *af,char *last_segname,int last_segname_len,int64 *pos){ /* Find the name of the last segment */ fseeko(af->aseg,0,SEEK_END); af_backspace(af); // back up one segment *pos = ftello(af->aseg); // remember where it is last_segname[0] = 0; return af_probe_next_seg(af,last_segname,last_segname_len,0,0,0,0);}/**************************************************************** *** GET FUNCTIONS ****************************************************************//**************************************************************** *** Probe the next segment: *** Return its name and argument, but don't advance the pointer.... *** Returns 0 on success, -1 on end of file or other error. ****************************************************************//**************************************************************** *** AFF creation functions ****************************************************************/static int aff_initialized = 0;int af_cache_debug = 0;FILE *af_trace = 0;void af_initialize(){ if(aff_initialized) return; /* make sure things were compiled properly */ assert(sizeof(struct af_head)==8); assert(sizeof(struct af_segment_head)==16); assert(sizeof(struct af_segment_tail)==8); const char *val = getenv(AFFLIB_CACHE_DEBUG); if(val) af_cache_debug = atoi(val); val = getenv(AFFLIB_TRACE); if(val){ af_trace = fopen(val,"wa"); fprintf(af_trace,"============================\n"); fprintf(af_trace,"AFFLIB trace started\n"); setvbuf(af_trace,0,_IONBF,0); } aff_initialized = 1; }/* Return 1 if a file is probably an AFF file * 0 if it is not. * -1 if failure. */int af_identify_file_type(const char *filename,int exists){ for(int i = 0; af_vnode_array[i]; i++){ if( (*af_vnode_array[i]->identify)(filename,exists)==1 ){ return (af_vnode_array[i]->type); } } return exists ? AF_IDENTIFY_NOEXIST : AF_IDENTIFY_ERR;}const char *af_identify_file_name(const char *filename,int exists){ for(int i = 0; af_vnode_array[i]; i++){ if( (*af_vnode_array[i]->identify)(filename,exists)==1 ){ return (af_vnode_array[i]->name); } } return 0;}AFFILE *af_open_with(const char *filename,int flags,int mode, struct af_vnode *v){ /* Alloate the space for the AFFILE structure */ AFFILE *af = (AFFILE *)calloc(sizeof(AFFILE),1); af->v = v; af->version = 2; af->openflags = flags | O_BINARY; // make sure that we ask for binray af->fname = strdup(filename); // remember file name af->exists = (access(filename,R_OK) == 0); // does the file exist? af->openmode = mode; af->image_sectorsize = 512; // default size af->error_reporter = warnx; af->badflag = (unsigned char *)malloc(af->image_sectorsize); /* Right now just set up the cache by hand */ const char *cache_pages = getenv(AFFLIB_CACHE_PAGES); if(cache_pages) af->num_pbufs = atoi(cache_pages); if(af->num_pbufs<1) af->num_pbufs = AFFLIB_CACHE_PAGES_DEFAULT; // default valuen af->pbcache = (struct aff_pagebuf *)calloc(af->num_pbufs,sizeof(struct aff_pagebuf)); /* Try opening it! */ if((*af->v->open)(af)){ /* Got an error; Free what was allocated and return */ if(af->badflag) free(af->badflag); if(af->pbcache) free(af->pbcache); if(af->fname) free(af->fname); memset(af,0,sizeof(*af)); // clean object reuse. free(af); return 0; } af_read_sizes(af); // set up the metadata if(af_trace) fprintf(af_trace,"af_open_with(%s,%o,%o,%s)\n",filename,flags,mode,v->name); return af;}AFFILE *af_open(const char *filename,int flags,int mode){ if(!aff_initialized) af_initialize(); if(flags & O_WRONLY){ errno = EINVAL; return 0; // this flag not supported } int exists = (flags & O_CREAT) ? 0 : 1; // file most exist if O_CREAT not specified /* Figure out it's format, then hand off to the correct subsystem. */ for(int i = 0; af_vnode_array[i]; i++){ /* Check to see if the implementation identifies the file */ if( (*af_vnode_array[i]->identify)(filename,exists)==1 ){ return af_open_with(filename,flags,mode,af_vnode_array[i]); } } return 0; // can't figure it out.}/* Open a regular file as an affile. * Can only be a raw file... */AFFILE *af_freopen(FILE *file){ if(!aff_initialized) af_initialize(); AFFILE *af = (AFFILE *)calloc(sizeof(AFFILE),1); af->v = &vnode_raw; af->image_sectorsize = 512; // default raw_freopen(af,file); return af;}#ifdef UNIX/* Open a regular file as an affile */AFFILE *af_popen(const char *command,const char *type){ if(!aff_initialized) af_initialize(); AFFILE *af = (AFFILE *)calloc(sizeof(AFFILE),1); af->v = &vnode_raw; raw_popen(af,command,type); af->image_sectorsize = 512; // default af->openflags = O_RDONLY; af->fname = strdup(command); return af;}#endif/* Close the image */int af_close(AFFILE *af){ int ret = 0; af_cache_flush(af); // flush the cache (if writing) if(af->writing && af->image_size != af->image_size_in_file){ af_update_segq(af,AF_IMAGESIZE,(int64)af->image_size); af->image_size_in_file = af->image_size; } if(getenv(AFFLIB_CACHE_STATS)){ fputc('\n',stderr); af_stats(af,stderr); } (*af->v->close)(af); /* Clear out the cache */ if(af->pbcache){ for(int i=0;i<af->num_pbufs;i++){ struct aff_pagebuf *p = &af->pbcache[i]; if(p->pagebuf){ memset(p->pagebuf,0,af->image_pagesize); // clean object reuse free(p->pagebuf); } } free(af->pbcache); } if(af->fname) free(af->fname); if(af->badflag) free(af->badflag); if(af->toc) free(af->toc); memset(af,0,sizeof(*af)); // clean object reuse free(af); return ret;}/* Seek in the virtual file */uint64 af_seek(AFFILE *af,int64 pos,int whence){ if(af_trace) fprintf(af_trace,"af_seek(%p,%"I64d",%d)\n",af,pos,whence); uint64 new_pos=0; switch(whence){ case SEEK_SET: new_pos = pos; break; case SEEK_CUR: new_pos += pos; break; case SEEK_END: new_pos = af_get_imagesize(af) - pos; break; } if(new_pos < 0) new_pos = 0; // new change if(af->pos == new_pos) return af->pos; // no change af->pos = new_pos; // set the new position return af->pos;}uint64 af_tell(AFFILE *af){ return af->pos;}/* Return if we are at the end of the file */int af_eof(AFFILE *af){ af_vnode_info vni; if(af_vstat(af,&vni)) return -1; // this is bad; we need vstat... if(vni.use_eof) return vni.at_eof; // if implementation wants to use it, use it if(af->pos<0){ // pos shouldn't be <0 errno = EINVAL; return -1; // this is bad } return (int64)af->pos >= vni.imagesize;}void af_enable_writing(AFFILE *af,int flag){ af->writing = flag;}void af_set_callback(AFFILE *af,void (*wcb)(struct affcallback_info *)){ af->w_callback = wcb;}void af_enable_compression(AFFILE *af,int type,int level){ af->compression_type = type; af->compression_level = level;}int af_compression_type(AFFILE *af){ return af->compression_type;}/* Return the 'extension' of str. * af_str("filename.aff") = ".aff" */const char *af_ext(const char *str){ int len = strlen(str); if(len==0) return str; // no extension for(int i=len-1;i>0;i--){ if(str[i]=='.') return &str[i+1]; } return str;}int af_ext_is(const char *filename,const char *ext){ return strcasecmp(af_ext(filename),ext)==0;}const char *af_filename(AFFILE *af){ return af->fname;}int af_identify(AFFILE *af){ return af->v->type;}/* af_get_imagesize: * Return the byte # of last mapped byte in image, or size of device; */int64 af_get_imagesize(AFFILE *af){ struct af_vnode_info vni; if(af_vstat(af,&vni)==0){ return vni.imagesize; } return -1;}int af_get_seg(AFFILE *af,const char *name,unsigned long *arg,unsigned char *data,size_t *datalen){ if(af->v->get_seg==0){ errno = ENOTSUP; return -1; // not supported by this file system } return (*af->v->get_seg)(af,name,arg,data,datalen);}int af_get_next_seg(AFFILE *af,char *segname,size_t segname_len,unsigned long *arg, unsigned char *data,size_t *datalen_){ if(af->v->get_next_seg==0){ errno = ENOTSUP; return -1; } return (*af->v->get_next_seg)(af,segname,segname_len,arg,data,datalen_);}int af_rewind_seg(AFFILE *af){ if(af->v->rewind_seg==0){ errno = ENOTSUP; return -1; } return (*af->v->rewind_seg)(af);}int af_update_seg(AFFILE *af, const char *name, unsigned long arg,const void *value,unsigned int vallen){ if(af->v->update_seg==0){ errno = ENOTSUP; return -1; // not supported by this file system } int r = (*af->v->update_seg)(af,name,arg,value,vallen); if(r==0) af->bytes_written += vallen; return r;}int af_del_seg(AFFILE *af,const char *name){ if(af->v->del_seg==0){ errno = ENOTSUP; return -1; // not supported } return (*af->v->del_seg)(af,name);}int af_vstat(AFFILE *af,struct af_vnode_info *vni){ memset(vni,0,sizeof(*vni)); // clear it if(af->v->vstat==0){ errno = ENOTSUP; return -1; // not supported } return (*af->v->vstat)(af,vni);}int af_has_pages(AFFILE *af){ struct af_vnode_info vni; if(af_vstat(af,&vni)) return -1; // can't figure it out return vni.has_pages; // will return 0 or 1}void af_stats(AFFILE *af,FILE *f){ fprintf(f,"AFSTATS for %s\n",af_filename(af)); fprintf(f,"Pages read: %"I64u"\n",af->pages_read); fprintf(f,"Pages written: %"I64u"\n",af->pages_written); fprintf(f,"Pages compressed: %"I64u"\n",af->pages_compressed); fprintf(f,"Pages decompressed: %"I64u"\n",af->pages_decompressed); fprintf(f,"Cache hits: %"I64u"\n",af->cache_hits); fprintf(f,"Cache misses: %"I64u"\n",af->cache_misses); fprintf(f,"Bytes copied: %"I64u"\n",af->bytes_memcpy); }#ifndef HAVE_ERR#include <stdarg.h>void err(int eval,const char *fmt,...){ va_list ap; va_start(ap,fmt); vfprintf(stderr,fmt,ap); fprintf(stderr,": %s\n",strerror(errno)); va_end(ap); exit(eval);}#endif#ifndef HAVE_ERRX#include <stdarg.h>void errx(int eval,const char *fmt,...){ va_list ap; va_start(ap,fmt); vfprintf(stderr,fmt,ap); fprintf(stderr,"%s\n",strerror(errno)); va_end(ap); exit(eval);}#endif#ifndef HAVE_WARN#include <stdarg.h>void warn(const char *fmt, ...){ va_list args; va_start(args,fmt); vfprintf(stderr,fmt, args); fprintf(stderr,": %s",strerror(errno));}#endif#ifndef HAVE_WARNX#include <stdarg.h>void warnx(const char *fmt,...){ va_list ap; va_start(ap,fmt); vfprintf(stderr,fmt,ap); va_end(ap);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -