📄 vnode_aff.cpp
字号:
/* * vnode_aff.cpp: * * Functions for the manipulation of AFF files... */#include "config.h"#include "afflib.h"#include "afflib_i.h"#include "vnode_aff.h"#include "aff_db.h"#define xstr(s) str(s)#define str(s) #s/* Low-level functions for putting * af_put_segv --- put a segment with an argument (also useful for putting numbers) * af_put_segq --- put a quadword, useful for putting 8-byte values. */static int aff_ignore_overhead(); static int aff_write_ignore(AFFILE *af,unsigned long bytes);static int aff_write_seg(AFFILE *af,const char *name,unsigned long arg, const void *value,unsigned int vallen); static int af_make_badflag(AFFILE *af); // creates a badflag and puts itstatic int aff_get_seg(AFFILE *af,const char *name,unsigned long *arg,unsigned char *data,size_t *datalen);static int aff_get_next_seg(AFFILE *af,char *segname,size_t segname_len, unsigned long *arg, unsigned char *data, size_t *datalen);/* af_write_ignore: * write an AF_IGNORE structure of a given size. */static int aff_ignore_overhead(){ return sizeof(struct af_segment_head)+sizeof(struct af_segment_tail);}static int aff_write_ignore(AFFILE *af,unsigned long bytes){ unsigned char *invalidate_data = (unsigned char *)calloc(bytes,1); aff_write_seg(af,AF_IGNORE,0,invalidate_data,bytes); // overwrite with NULLs free(invalidate_data); return(0);}/* aff_write_seg: * put the given named segment at the current position in the file. * Return 0 for success, -1 for failure (probably disk full?) * This is the only place where a segment actually gets written */int aff_write_seg(AFFILE *af, const char *segname,unsigned long arg,const void *data,unsigned int datalen){ //printf("aff_write_seg(%s) af->aseg=%p\n",segname,af->aseg); struct af_segment_head segh; struct af_segment_tail segt; if(af->debug){ (*af->error_reporter)("aff_write_seg(" POINTER_FMT ",'%s',%lu,data=" POINTER_FMT ",datalen=%u)", af,segname,arg,data,datalen); } assert(sizeof(segh)==16); assert(sizeof(segt)==8); /* If the last command was not a probe (so we know where we are), and * we are not at the end of the file, something is very wrong. */ unsigned int segname_len = strlen(segname); strcpy(segh.magic,AF_SEGHEAD); segh.name_len = htonl(segname_len); segh.data_len = htonl(datalen); segh.flag = htonl(arg); strcpy(segt.magic,AF_SEGTAIL); segt.segment_len = htonl(sizeof(segh)+segname_len + datalen + sizeof(segt)); int64 offset = ftello(af->aseg); af_toc_insert(af,segname,offset);#ifdef DEBUG { fprintf(stderr,"aff_write_segv: putting segment %s (datalen=%d) offset=%qd\n", segname,datalen,o); }#endif if(fwrite(&segh,sizeof(segh),1,af->aseg)!=1) return -10; if(fwrite(segname,1,segname_len,af->aseg)!=segname_len) return -11; if(fwrite(data,1,datalen,af->aseg)!=datalen) return -12; if(fwrite(&segt,sizeof(segt),1,af->aseg)!=1) return -13; fflush(af->aseg); // make sure it is on the disk return 0;}/**************************************************************** *** low-level routines for reading ****************************************************************//* aff_get_segment: * Get the named segment, using the toc cache. * If there is no cache, * - If the requested segment is the next segment, just get it. * - Otherwise go to the beginning and scan for it. */static int aff_get_seg(AFFILE *af,const char *name, unsigned long *arg,unsigned char *data,size_t *datalen){ char next[AF_MAX_NAME_LEN]; int first = 1; size_t segsize = 0; /* If the segment is in the directory, then seek the file to that location. * Otherwise, we'll probe the next segment, and if it is not there, * we will rewind to the beginning and go to the end. */ struct af_toc_mem *adm = af_toc(af,name); if(adm){ fseeko(af->aseg,adm->offset,SEEK_SET); int ret = af_get_next_seg(af,next,sizeof(next),arg,data,datalen); assert(strcmp(next,name)==0); // hopefully this is what they asked for return ret; } /* 2007-05-30: slg - if it is not in the TOC and we are using the TOC, * then it is not in the file. Just return. */ if(af->disable_toc==0) return -1; /* This code searches through the file. * This is what you have to do if there is no ToC. * It's slow.*/ do { int r = af_probe_next_seg(af,next,sizeof(next),0,0,&segsize,1); if(r==0 && strcmp(next,name)==0){ // found the segment! int ret = af_get_next_seg(af,next,sizeof(next),arg,data,datalen); assert(strcmp(next,name)==0); // hopefully it's still the same! return ret; } if(first){ // okay, should we try to rewind? af_rewind_seg(af); first = 0; // no longer the first time through continue; } if(r!=0){ // did we encounter an error reading? break; // yes } fseeko(af->aseg,segsize,SEEK_CUR); // seek to next segment } while(1); return -1; // couldn't find segment}/**************************************************************** *** Get the next segment. *** data must not be freed. *** *datalen_ is size of data; *datalen_ is modified to amount of segment *** if no data is specified, then just seek past it... *** Returns 0 on success, *** -1 on end of file. (AF_ERROR_EOF) *** -2 if *data is not large enough to hold the segment (AF_ERROR_DATASMALL) *** -3 af file is corrupt; no tail (AF_ERROR_CORRUPT) ****************************************************************/static int aff_get_next_seg(AFFILE *af,char *segname,size_t segname_len,unsigned long *arg, unsigned char *data,size_t *datalen_){ if(!af->aseg){ snprintf(af->error_str,sizeof(af->error_str),"af_get_next_segv only works with aff files"); return AF_ERROR_INVALID_ARG; } int64 start = ftello(af->aseg); size_t data_len; int r = af_probe_next_seg(af,segname,segname_len,arg,&data_len,0,0); if(r<0) return r; // propigate error code if(data){ /* Read the data? */ if(datalen_ == 0){ snprintf(af->error_str,sizeof(af->error_str),"af_get_next_seg: data provided but datalen is NULL"); return AF_ERROR_INVALID_ARG; } size_t read_size = data_len<=*datalen_ ? data_len : *datalen_; if(fread(data,1,read_size,af->aseg)!=read_size){ snprintf(af->error_str,sizeof(af->error_str),"af_get_next_segv: EOF on reading segment? File is corrupt."); return AF_ERROR_SEGH; } if(data_len > *datalen_){ /* Read was incomplete; * go back to the beginning of the segment and return * the incomplete code. */ fseeko(af->aseg,start,SEEK_SET); // go back return AF_ERROR_DATASMALL; } } else { fseeko(af->aseg,data_len,SEEK_CUR); // skip past the data } if(datalen_) *datalen_ = data_len; /* Now read the tail */ struct af_segment_tail segt; if(fread(&segt,sizeof(segt),1,af->aseg)!=1){ snprintf(af->error_str,sizeof(af->error_str),"af_get_next_segv: end of file reading segment tail..."); return AF_ERROR_TAIL; } /* Validate tail */ unsigned long stl = ntohl(segt.segment_len); unsigned long calculated_segment_len = sizeof(struct af_segment_head) + strlen(segname) + data_len + sizeof(struct af_segment_tail); if(strcmp(segt.magic,AF_SEGTAIL)!=0){ snprintf(af->error_str,sizeof(af->error_str),"af_get_next_segv: AF file corrupt. No tail!"); return AF_ERROR_TAIL; } if(stl != calculated_segment_len){ snprintf(af->error_str,sizeof(af->error_str),"af_get_next_segv: AF file corrupt (%lu!=%lu)!", stl,calculated_segment_len); return AF_ERROR_TAIL; } return 0;}static int aff_rewind_seg(AFFILE *af){ fseeko(af->aseg,sizeof(struct af_head),SEEK_SET); // go to the beginning return 0;}/**************************************************************** *** Update functions ****************************************************************//* * af_update_seg: * Update the given named segment with the new value. * if "append" is false, don't append if it can't be found. * if "append" is true and the named segment can't be found, append it. */int aff_update_seg(AFFILE *af, const char *name, unsigned long arg,const void *value,unsigned int vallen){ char next_segment_name[AF_MAX_NAME_LEN]; size_t next_segsize = 0; size_t next_datasize = 0; /* if we are updating with a different size, * remember the location and size of the AF_IGNORE segment that * has the smallest size that is >= strlen(name)+vallen */ size_t size_needed = strlen(name)+vallen+aff_ignore_overhead(); size_t size_closest = 0; uint64 loc_closest = 0; struct af_toc_mem *adm = af_toc(af,name); #ifdef DEBUG fprintf(stderr,"aff_update_seg(name=%s,arg=%lu,vallen=%u)\n",name,arg,vallen);#endif /* Is the last segment an ignore? */ if(adm){ fseeko(af->aseg,adm->offset,SEEK_SET); } else { af_rewind_seg(af); // start at the beginning } while(af_probe_next_seg(af,next_segment_name,sizeof(next_segment_name), 0,&next_datasize,&next_segsize,1)==0){ uint64 next_segment_loc = ftello(af->aseg);#ifdef DEBUG fprintf(stderr," next_segment_name=%s next_datasize=%d " "next_segsize=%d next_segment_loc=%qd\n", next_segment_name, next_datasize, next_segsize,next_segment_loc);#endif if(strcmp(next_segment_name,name)==0){ // found the segment! /* Okay. Is there room to fit it here? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -