📄 vnode_afd.cpp
字号:
/* * vnode_aff.cpp: * * Functions for the manipulation of AFF files... */#include "config.h"#include "afflib.h"#include "afflib_i.h"#include "vnode_afd.h"#include "aff_db.h"#ifndef F_OK#define F_OK 00#endif#ifndef R_OK#define R_OK 04#endif#ifdef WIN32/**************************************************************** *** Windows emulation of opendir()/readdir() *** From php ****************************************************************//* struct dirent - same as Unix */struct dirent { long d_ino; /* inode (always 1 in WIN32) */ off_t d_off; /* offset to this dirent */ int d_reclen; /* length of d_name; was unsigned short */ char d_name[_MAX_FNAME + 1]; /* filename (null terminated) */};/* typedef DIR - not the same as Unix */typedef struct { long handle; /* _findfirst/_findnext handle */ short offset; /* offset into directory */ short finished; /* 1 if there are not more files */ struct _finddata_t fileinfo; /* from _findfirst/_findnext */ char *dir; /* the dir we are reading */ struct dirent dent; /* the dirent to return */} DIR;/* Function prototypes */DIR *opendir(const char *);struct dirent *readdir(DIR *);int readdir_r(DIR *, struct dirent *, struct dirent **);int closedir(DIR *);int rewinddir(DIR *);/********************************************************************** * Implement dirent-style opendir/readdir/rewinddir/closedir on Win32 * * Functions defined are opendir(), readdir(), rewinddir() and * closedir() with the same prototypes as the normal dirent.h * implementation. * * Does not implement telldir(), seekdir(), or scandir(). The dirent * struct is compatible with Unix, except that d_ino is always 1 and * d_off is made up as we go along. * * The DIR typedef is not compatible with Unix. **********************************************************************/static DIR *opendir(const char *dir){ DIR *dp; char *filespec; long handle; int index; filespec = (char *)malloc(strlen(dir) + 2 + 1); strcpy(filespec, dir); index = strlen(filespec) - 1; if (index >= 0 && (filespec[index] == '/' || (filespec[index] == '\\' && !IsDBCSLeadByte(filespec[index-1])))) filespec[index] = '\0'; strcat(filespec, "/*"); dp = (DIR *) malloc(sizeof(DIR)); dp->offset = 0; dp->finished = 0; if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0) { if (errno == ENOENT) { dp->finished = 1; } else { free(dp); free(filespec); return NULL; } } dp->dir = strdup(dir); dp->handle = handle; free(filespec); return dp;}static struct dirent *readdir(DIR *dp){ if (!dp || dp->finished) return NULL; if (dp->offset != 0) { if (_findnext(dp->handle, &(dp->fileinfo)) < 0) { dp->finished = 1; return NULL; } } dp->offset++; strlcpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME+1); dp->dent.d_ino = 1; dp->dent.d_reclen = strlen(dp->dent.d_name); dp->dent.d_off = dp->offset; return &(dp->dent);}static int readdir_r(DIR *dp, struct dirent *entry, struct dirent **result){ if (!dp || dp->finished) { *result = NULL; return 0; } if (dp->offset != 0) { if (_findnext(dp->handle, &(dp->fileinfo)) < 0) { dp->finished = 1; *result = NULL; return 0; } } dp->offset++; strlcpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME+1); dp->dent.d_ino = 1; dp->dent.d_reclen = strlen(dp->dent.d_name); dp->dent.d_off = dp->offset; memcpy(entry, &dp->dent, sizeof(*entry)); *result = &dp->dent; return 0;}static int closedir(DIR *dp){ if (!dp) return 0; _findclose(dp->handle); if (dp->dir) free(dp->dir); if (dp) free(dp); return 0;}static int rewinddir(DIR *dp){ /* Re-set to the beginning */ char *filespec; long handle; int index; _findclose(dp->handle); dp->offset = 0; dp->finished = 0; filespec = (char *)malloc(strlen(dp->dir) + 2 + 1); strcpy(filespec, dp->dir); index = strlen(filespec) - 1; if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\')) filespec[index] = '\0'; strcat(filespec, "/*"); if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0) { if (errno == ENOENT) dp->finished = 1; } dp->handle = handle; free(filespec); return 0;}#endif/**************************************************************** *** Service routines ****************************************************************/struct afd_private { AFFILE **afs; // list of AFFILEs... int num_afs; // number of them int cur_file; // current segment number...};static inline struct afd_private *AFD_PRIVATE(AFFILE *af){ assert(af->v == &vnode_afd); return (struct afd_private *)(af->vnodeprivate);}static bool last4_is_afd(const char *filename){ return af_ext_is(filename,"afd");}static bool last4_is_aff(const char *filename){ return af_ext_is(filename,"aff");}/* afd_file_with_seg: * Returns the AFFILE for a given segment, or 0 if it isn't found. */static AFFILE *afd_file_with_seg(AFFILE *af,const char *name){ struct afd_private *ap = AFD_PRIVATE(af); for(int i=0;i<ap->num_afs;i++){ if(af_get_seg(ap->afs[i],name,0,0,0)==0){ return ap->afs[i]; } } errno = ENOTDIR; // get ready for error return return 0;}static void aff_filename(AFFILE *afd,char *buf,int buflen,int num){ snprintf(buf,buflen,"%s/file_%03d.aff",afd->fname,num);}/* Return 1 if a file is an AFF file */static int afd_identify_file(const char *filename,int exists){ if(filename==0 || strlen(filename)==0) return 0; // zero-length filenames aren't welcome if(exists && access(filename,R_OK)!=0) return 0; // needs to exist and it doesn't /* If it ends with a '/', remove it */ char *fn = (char *)alloca(strlen(filename)+1); strcpy(fn,filename); char *lastc = fn + strlen(fn) - 1; if(*lastc=='/') *lastc = '\000'; /* If filename exists and it is a dir, it needs to end afd */ struct stat sb; if(stat(fn,&sb)==0){ if((sb.st_mode & S_IFMT)==S_IFDIR){ if(last4_is_afd(fn)) return 1; } return 0; // } /* Doesn't exist. Does it end .afd ? */ if(last4_is_afd(fn)) return 1; return 0;}/* Add a file to the AFF system. * if fname==0, create a new one and copy over the relevant metadata... */static int afd_add_file(AFFILE *af,const char *fname_){ struct afd_private *ap = AFD_PRIVATE(af); const char *segs_to_copy[] = {AF_BADFLAG, AF_CASE_NUM, AF_IMAGE_GID, AF_ACQUISITION_ISO_COUNTRY, AF_ACQUISITION_COMMAND_LINE, AF_ACQUISITION_DATE, AF_ACQUISITION_NOTES, AF_ACQUISITION_DEVICE, AF_ACQUISITION_TECHNICIAN, AF_DEVICE_MANUFACTURER, AF_DEVICE_MODEL, AF_DEVICE_SN, AF_DEVICE_FIRMWARE, AF_DEVICE_SOURCE, AF_CYLINDERS, AF_HEADS, AF_SECTORS_PER_TRACK, AF_LBA_SIZE, AF_HPA_PRESENT, AF_DCO_PRESENT, AF_LOCATION_IN_COMPUTER, AF_DEVICE_CAPABILITIES, 0}; char fname[MAXPATHLEN+1]; memset(fname,0,sizeof(fname)); if(fname_){ strlcpy(fname,fname_,sizeof(fname)); } else { aff_filename(af,fname,sizeof(fname),ap->num_afs); } int new_file = access(fname,F_OK)!=0; // Is this a new file? AFFILE *af2 = af_open(fname,af->openflags,af->openmode); if(af2==0){ (*af->error_reporter)("open(%s,%d,%d) failed: %s\n", fname,af->openflags,af->openmode,strerror(errno)); return -1; // this is bad } ap->num_afs += 1; ap->afs = (AFFILE **)realloc(ap->afs,sizeof(AFFILE *) * ap->num_afs); ap->afs[ap->num_afs-1] = af2; if(new_file){ if(af->writing==0){ (af->error_reporter)("afd_add_file: created new file and not writing?\n"); return -1; } /* Copy over configuration from AFD vnode*/ af_enable_writing(af2,af->writing); af_enable_compression(af2,af->compression_type,af->compression_level); af_set_pagesize(af2,af->image_pagesize); // af_set_sectorsize(af2,af->image_sectorsize); af_update_seg(af,AF_AFF_FILE_TYPE,0,"AFD",3); /* If this is the second file, copy over additional metadata from first... */ if(ap->num_afs>0){ AFFILE *af0 = ap->afs[0]; memcpy(af2->badflag,af0->badflag,af->image_sectorsize); af2->bytes_memcpy += af->image_sectorsize; for(const char **segname=segs_to_copy;*segname;segname++){ unsigned char data[65536]; // big enough for most metadata size_t datalen = sizeof(data); unsigned long arg=0; if(af_get_seg(af0,*segname,&arg,data,&datalen)==0){ int r = af_update_seg(af2,*segname,arg,data,datalen); if(r!=0){ (*af->error_reporter)("afd_add_file: could not update %s in %s (r=%d)", *segname,af_filename(af2),r); } } } } } return 0;} /**************************************************************** *** User-visible functions. ****************************************************************/static int afd_open(AFFILE *af){ if(af->fname==0 || strlen(af->fname)==0) return -1; // zero-length filenames aren't welcome /* If the name ends with a '/', remove it */ char *lastc = af->fname + strlen(af->fname) - 1; if(*lastc=='/') *lastc = '\000'; /* If the directory doesn't exist, make it (if we are O_CREAT) */ struct stat sb; if(stat(af->fname,&sb)!=0){ if((af->openflags & O_CREAT) == 0){ // flag not set errno = ENOTDIR; return -1; } mode_t omask = umask(0); // reset umask for now... mkdir(af->fname,af->openmode|0111); // make the directory umask(omask); // put back the old mask } af->maxsize = AFD_DEFAULT_MAXSIZE; af->vnodeprivate = (void *)calloc(1,sizeof(struct afd_private)); struct afd_private *ap = AFD_PRIVATE(af); ap->afs = (AFFILE **)malloc(sizeof(AFFILE *)); /* Open the directory and read all of the AFF files */ DIR *dirp = opendir(af->fname); if(!dirp){ return -1; // something is wrong... } struct dirent *dp; while ((dp = readdir(dirp)) != NULL){ if (last4_is_aff(dp->d_name)){ char path[MAXPATHLEN+1]; strlcpy(path,af->fname,sizeof(path)); strlcat(path,"/",sizeof(path)); strlcat(path,dp->d_name,sizeof(path)); if(afd_add_file(af,path)){ return -1; } } } closedir(dirp); return 0; // "we were successful"}static int afd_close(AFFILE *af){ struct afd_private *ap = AFD_PRIVATE(af); uint64 image_size = af_get_imagesize(af); // get the largest imagesize /* Close all of the subfiles, then free the memory, then close this file */ for(int i=0;i<ap->num_afs;i++){ ap->afs[i]->image_size = image_size; // set each to have current imagesize af_close(ap->afs[i]); // and close each file } free(ap->afs); memset(ap,0,sizeof(*ap)); // clean object reuse free(ap); // won't need it again return 0;}#ifndef WIN32static uint64 max(uint64 a,uint64 b){ return a > b ? a : b;}#endifstatic int afd_vstat(AFFILE *af,struct af_vnode_info *vni){ struct afd_private *ap = AFD_PRIVATE(af); memset(vni,0,sizeof(*vni)); // clear it /* See if there is some device that knows how big the disk is */ if(ap->num_afs>0){ af_vstat(ap->afs[0],vni); // get disk free bytes } /* Get the file with the largest imagesize from either the * AFD or any of the sub AFDs... */ vni->imagesize = af->image_size; for(int i=0;i<ap->num_afs;i++){ vni->imagesize = max(vni->imagesize,ap->afs[i]->image_size); } vni->has_pages = 1; vni->supports_metadata = 1; return 0;}static int afd_get_seg(AFFILE *af,const char *name,unsigned long *arg,unsigned char *data, size_t *datalen){ AFFILE *af2 = afd_file_with_seg(af,name); if(af2){ return af_get_seg(af2,name,arg,data,datalen); // use this one } return -1; // not found}static int afd_get_next_seg(AFFILE *af,char *segname,size_t segname_len,unsigned long *arg, unsigned char *data,size_t *datalen_){ /* See if there are any more in the current segment */ struct afd_private *ap = AFD_PRIVATE(af); while (ap->cur_file < ap->num_afs) { int r = af_get_next_seg(ap->afs[ap->cur_file],segname,segname_len,arg,data,datalen_); if(r!=AF_ERROR_EOF){ // if it is not EOF return r; } ap->cur_file++; // advance to the next file if(ap->cur_file < ap->num_afs){ // rewind it to the beginning af_rewind_seg(ap->afs[ap->cur_file]); } } while(ap->cur_file < ap->num_afs); return AF_ERROR_EOF; // really made it to the end}/* Rewind all of the segments */static int afd_rewind_seg(AFFILE *af){ struct afd_private *ap = AFD_PRIVATE(af); ap->cur_file = 0; for(int i=0;i<ap->num_afs;i++){ af_rewind_seg(ap->afs[i]); } return 0; }/* Update: * If this segment is in any of the existing files, update it there. * Otherwise, if the last file isn't too big, add it there. * Otherwise, ada a new file. */static int afd_update_seg(AFFILE *af, const char *name, unsigned long arg,const void *value,unsigned int vallen) { struct afd_private *ap = AFD_PRIVATE(af); AFFILE *af2 = afd_file_with_seg(af,name); if(af2){ return af_update_seg(af2,name,arg,value,vallen); // update where it was found } /* Segment doesn't exist anywhere... */ /* Append to the last file if there is space and a space limitation... */ if(ap->num_afs>0){ AFFILE *af3 = ap->afs[ap->num_afs-1]; FILE *aseg = af3->aseg; uint64 offset = ftello(aseg); fseeko(aseg,0,SEEK_END); uint64 len = ftello(aseg); fseeko(aseg,offset,SEEK_SET); if((len + vallen + 1024 < af->maxsize) && (af->maxsize!=0)){ /* It should fit with room left over! */ return af_update_seg(af3,name,arg,value,vallen); } } /* Add a new segment and update that one */ if(afd_add_file(af,0)) return -1; AFFILE *af4 = ap->afs[ap->num_afs-1]; // this is the one just added return af_update_seg(af4,name,arg,value,vallen);}int afd_del_seg(AFFILE *af,const char *segname){ AFFILE *af2 = afd_file_with_seg(af,segname); if(af2){ return af_del_seg(af2,segname); } return -1; // not found}struct af_vnode vnode_afd = { AF_IDENTIFY_AFD, // AF_VNODE_TYPE_COMPOUND|AF_VNODE_TYPE_RELIABLE, // "AFF Directory", afd_identify_file, afd_open, // open afd_close, // close afd_vstat, // vstat afd_get_seg, // get_seg afd_get_next_seg, // get_next_seg afd_rewind_seg, // rewind_seg afd_update_seg, // update_seg afd_del_seg, // del_seg 0, // read 0 // write};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -