/* 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 u_char *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_t offset = ftello(aseg); fseeko(aseg,0,SEEK_END); uint64_t 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); } } /* Create a new file and add the segment to it.*/ 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); }
/* For afm_update_seg, hand off page updates to the split_raw implementation * and metadata updates to the AFF implementation. */ static int afm_update_seg(AFFILE *af, const char *name, uint32_t arg,const u_char *value,uint32_t vallen) { struct afm_private *ap = AFM_PRIVATE(af); int64_t page_num = af_segname_page_number(name); // <0 means update metadata if(page_num<0){ return af_update_seg(ap->aff,name,arg,value,vallen); } return af_update_seg(ap->sr,name,arg,value,vallen); }
static int afm_create(AFFILE *af) { if (af_update_seg (af, AF_RAW_IMAGE_FILE_EXTENSION, 0, (const u_char *)SPLITRAW_DEFAULT_EXTENSION, strlen(SPLITRAW_DEFAULT_EXTENSION))) { (*af->error_reporter)("split_raw_read_write_setup: %s: failed to write %s\n", af->fname, AF_RAW_IMAGE_FILE_EXTENSION); afm_close(af); // close the sub-file return -1; // we failed } af_set_pagesize(af,AFM_DEFAULT_PAGESIZE); af_update_seg(af,AF_AFF_FILE_TYPE,0,(const u_char *)"AFM",3); return 0; }
/* * af_set_pagesize: * Sets the pagesize. Fails with -1 if it can't be changed. */ int af_set_pagesize(AFFILE *af,u_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; }
/* Requires no locking */ int af_update_seg_frombio(AFFILE *af,const char *segname,unsigned long arg,BIO *bio) { /* Get the buffer to write out */ u_char *buf=0; size_t buflen = BIO_get_mem_data(bio,&buf); return af_update_seg(af,segname,0,buf,buflen); }
/* * af_make_badflag: * Create a randomized bag flag and * leave an empty segment of how many badsectors there are * in the image... */ int af_make_badflag(AFFILE *af) { #ifdef HAVE_OPENSSL_RAND_H /* Use a good random number generator if we have it */ RAND_pseudo_bytes(af->badflag,af->image_sectorsize); strcpy((char *)af->badflag,"BAD SECTOR"); #else /* Otherwise use a bad one */ for(int i=0;i<af->image_sectorsize;i++){ af->badflag[i] = rand() & 0xff; } #endif AF_WRLOCK(af); af->badflag_set = 1; if(af_update_seg(af,AF_BADFLAG,0,af->badflag,af->image_sectorsize)){ AF_UNLOCK(af); return -1; } if(af_update_segq(af,AF_BADSECTORS,0)){ AF_UNLOCK(af); return -1; } AF_UNLOCK(af); return 0; }
int af_update_segq(AFFILE *af, const char *name, int64_t value) { struct aff_quad q; q.low = htonl((uint32_t)(value & 0xffffffff)); q.high = htonl((uint32_t)(value >> 32)); return af_update_seg(af,name,AF_SEG_QUADWORD,(const u_char *)&q,8); }
int sequential_test() { char buf[1024]; const char *fmt = "this is line %d\n"; printf("Sequential test...\n"); AFFILE *af = open_testfile("test_sequential",1); for(int i=0;i<MAX_FMTS;i++){ if(i%250==0) printf("\rwriting %d/%d...",i,MAX_FMTS); sprintf(buf,fmt,i); if(af_write(af,(unsigned char *)buf,strlen(buf))!=(int)strlen(buf)){ err(1,"Attempt to write buffer %d failed\n",i); } } /* Test for a random bug that was reported */ af_update_seg(af,"test",0,(const u_char *)"foo",3); af_update_seg(af,"test",0,(const u_char *)"bar",3); af_del_seg(af,"test"); af_del_seg(af,"test"); af_close(af); printf("\nSequential file written.\n"); printf("\n"); printf("Now verifying the string...\n"); af = open_testfile("test_sequential",0); if(!af) err(1,"af_open"); for(int i=0;i<MAX_FMTS;i++){ char rbuf[1024]; sprintf(buf,fmt,i); int len = strlen(buf); if(af_read(af,(unsigned char *)rbuf,len)!=len){ err(1,"Attempt to read entry %d failed\n",i); } rbuf[len] = 0; // terminate the string if(strcmp(buf,rbuf)!=0){ err(1,"Attempt to verify entry %d failed.\nExpected: (len=%zd) '%s'\nGot: (len=%zd) '%s'\n", i,strlen(buf),buf,strlen(rbuf),rbuf); } } af_close(af); printf("===========================\n\n"); return 0; }
/* * make the IMAGE_GID segment if it doesn't exist * Returns -1 if an error, 0 if the GID exists, and 1 if one is made. */ int af_make_gid(AFFILE *af) { int ret = 0; AF_WRLOCK(af); if(af_get_seg(af,AF_IMAGE_GID,0,0,0)!=0){ unsigned char bit128[16]; RAND_pseudo_bytes(bit128,sizeof(bit128)); int r = af_update_seg(af,AF_IMAGE_GID,0,bit128,sizeof(bit128)); if(r<0) ret = -1; else ret = 1; } AF_UNLOCK(af); return ret; }
/* 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; }
void maxsize_test() { printf("Maxsize test. This test is designed to test creation of files\n"); printf("Larger than 4GB. Currently it's disabled, though.\n"); #if 0 char segname[16]; char buf[1024]; char fn[1024]; int numpages = 1000; AFFILE *af = af_open(filename(fn,sizeof(fn),"maxsize"),O_CREAT|O_RDWR|O_TRUNC,0666); memset(buf,0,sizeof(buf)); for(int64_t i=0;i<numpages;i++){ sprintf(buf,"This is page %"I64d". ****************************************************\n",i); sprintf(segname,AF_PAGE,i); af_update_seg(af,segname,0,buf,sizeof(buf)); } af_close(af); printf("\nMaxsize test passes.\n"); #endif printf("\n====================\n"); }
int af_set_acquisition_date(AFFILE *af,time_t t) { char timebuf[64]; strftime(timebuf,sizeof(timebuf),"%Y-%m-%d %H:%M:%S\n",localtime(&t)); return af_update_seg(af,AF_ACQUISITION_DATE,0,(const u_char *)timebuf,strlen(timebuf)); }
/* 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_NO_CRYPTO,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){ /* Copy over configuration from AFD vnode*/ 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,(const u_char *)"AFD",3); /* If this is the second file, copy over additional metadata from first... */ if(ap->num_afs>1){ 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; }
int aestest() { unsigned char keyblock[32]; /* Make a key; doesn't need to be a good key; make it 256 bits */ for(int i=0;i<32;i++){ keyblock[i] = i; } AFFILE *af = af_open("crypto.aff",O_CREAT|O_RDWR|O_TRUNC,0666); if(!af) err(1,"af_open"); if(af_set_aes_key(af,keyblock,256)) err(1,"af_set_aes_key"); af_set_pagesize(af,65536); /* Now, let's write some data of various sizes */ u_char test[1024],buf[1024],rbuf[1024]; size_t buflen = sizeof(buf); make_test_seg(test,0); for(u_int len=0;len<=strlen((const char *)test);len++){ if(af_update_seg(af,"page0",0,test,len)) err(1,"af_update_seg len=%d",len); /* Now try to read the segment */ memset(buf,0,sizeof(buf)); buflen = sizeof(buf); if(af_get_seg(af,"page0",0,(unsigned char *)buf,&buflen)){ err(1,"Could not read encrypted segment with length %d.\n",len); } if(buflen!=len){ printf("size of returned segment = %zd ",buflen); printf("(should be %d) \n",len); exit(0); } if(memcmp(buf,test,len)!=0){ printf("does not match\n"); printf(" wanted: %s\n",test); printf(" got: %s\n",buf); exit(0); } } if(af_close(af)) err(1,"af_close"); /* Now re-open the file, do not set the encryption key, and see if we can read it */ int r; memset(buf,0,sizeof(buf)); af = af_open("crypto.aff",O_RDONLY,0666); buflen = sizeof(buf); r = af_get_seg(af,"page0",0,(unsigned char *)buf,&buflen); if(r!=-1) { errx(1,"Error; attempt to read segment 'encrypted' succeded. It should have failed."); } /* Try to read 'encrypted/aes' */ r = af_get_seg(af,"encrypted/aes",0,(unsigned char *)buf,&buflen); if(memcmp(buf,test,buflen)==0){ errx(1,"Error: segment encrypted/aes wasn't actually encrypted."); } af_close(af); /* Now set the correct encryption key and see if we can read it */ af = af_open("crypto.aff",O_RDONLY,0666); if(af_set_aes_key(af,keyblock,256)) err(1,"af_set_aes_key"); buflen = sizeof(buf); memset(buf,0,sizeof(buf)); r = af_get_seg(af,"page0",0,(unsigned char *)buf,&buflen); if(buflen != strlen((const char *)test)){ errx(1,"Error: Could not read encrypted segment after re-opening file"); } if(memcmp(buf,test,buflen)!=0) errx(1,"Error: Re-read of file produces wrong data."); printf("encrypted data read and decrypted: '%s'\n",buf); /* Try to read a segment that doesn't eixst */ buflen = 0; if(af_get_seg(af,"encrypted2",0,0,&buflen)==0){ errx(1,"Error: Attempt to get size of non-existant segment 'encrypted2' got %zd\n",buflen); } af_close(af); /* Now set the wrong encryption key and see if we can read it */ memset(buf,0,sizeof(buf)); af = af_open("crypto.aff",O_RDONLY,0666); keyblock[3] = 42; if(af_set_aes_key(af,keyblock,256)) err(1,"af_set_aes_key"); buflen = sizeof(buf); r = af_get_seg(af,"page0",0,(unsigned char *)buf,&buflen); if(memcmp(buf,test,buflen)==0) errx(1,"Error: Setting wrong key still produces correct data."); af_close(af); printf("Basic crypto checks. Now check passphrase....\n"); /* Write the data with a passphrase and try to read it back */ af = af_open("crypto_pass.aff",O_CREAT|O_RDWR|O_TRUNC,0666); if(!af) err(1,"af_open 3"); af_set_pagesize(af,65536); if(af_establish_aes_passphrase(af,"yummy")) err(1,"af_establish_aes_passphrase"); if(af_use_aes_passphrase(af,"yummy")) err(1,"af_use_aes_passphrase"); if(af_update_seg(af,"page0",0,(const u_char *)test,strlen((const char *)test))) err(1,"af_update_seg failed at 3"); if(af_close(af)) err(1,"af_close at 3"); /* Now try to read it back */ memset(rbuf,0,sizeof(rbuf)); size_t rbuflen = sizeof(rbuf); af = af_open("crypto_pass.aff",O_RDONLY,0666); if(!af) err(1,"af_open 4"); if(af_get_seg(af,"page0",0,(unsigned char *)buf,&buflen)==0){ errx(1,"af_get_seg should have failed and didn't"); } if(af_use_aes_passphrase(af,"yummy")) err(1,"af_set_passphrase 2"); rbuflen=sizeof(rbuf); if(af_get_seg(af,"page0",0,(unsigned char *)rbuf,&rbuflen)){ errx(1,"af_get_seg failed"); } if(rbuflen!=strlen((const char *)test)) errx(1,"Reading encrypted data returned wrong size"); if(memcmp(rbuf,test,rbuflen)!=0) errx(1,"Error: wrong data"); printf("encrypted data read with passphrase 'yummy': %s\n",rbuf); af_close(af); /* Try to change the passphrase */ af = af_open("crypto_pass.aff",O_RDWR,0666); if(!af) err(1,"af_open 5"); if(af_change_aes_passphrase(af,"yummy","dummy")) err(1,"could not change passphrase"); af_close(af); /* Try to read with new passphrase */ af = af_open("crypto_pass.aff",O_RDONLY,0666); if(!af) err(1,"af_open 5"); memset(rbuf,0,sizeof(rbuf)); rbuflen = sizeof(rbuf); if(af_use_aes_passphrase(af,"dummy")) err(1,"af_set_passphrase 2"); rbuflen=sizeof(rbuf); if(af_get_seg(af,"page0",0,(unsigned char *)rbuf,&rbuflen)){ errx(1,"af_get_seg failed"); } if(rbuflen!=strlen((const char *)test)) errx(1,"Reading encrypted with new passphrase data returned wrong size"); if(memcmp(rbuf,test,rbuflen)!=0) errx(1,"Error: wrong data"); printf("encrypted data read with new passphrase 'dummy': %s\n",rbuf); af_close(af); exit(0); /* Now try to read with the wrong passphrase */ af = af_open("crypto.aff",O_RDONLY,0666); if(af_use_aes_passphrase(af,"yummy2")) err(1,"af_set_passphrase 3"); buflen=sizeof(buf); memset(buf,0,sizeof(buf)); if(af_get_seg(af,"page0",0,(unsigned char *)buf,&buflen)){ printf("Couldn't get data with wrong passphrase (that's good)\n"); } printf("data read with wrong passphrase: %s\n",buf); if(buflen>0 && memcmp(buf,test,buflen)==0){ errx(1,"Error: data fetched with wrong passphrase was not scrambled."); } af_close(af); exit(0); }