Main Page | Alphabetical List | Compound List | File List | Compound Members | File Members

protectcorrectfile.cc

Go to the documentation of this file.
00001 
00002 
00003 
00004 #include "protectcorrectfile.h"
00005 
00006 #include "options.h"
00007 #include "header.h"
00008 #include "footprint.h"
00009 #include "hyperblkcodec.h"
00010 
00011 #include <sys/stat.h>
00012 #include <assert.h>
00013 
00014 
00017 long interleaveskip(const long len, const long stripenum)
00018 {
00019   long sskip = len/stripenum+1;
00020   // decrease sskip until the cycle modulo len is len.
00021   long i,s;
00022   do {
00023     --sskip;
00024     i=0; s=0;
00025     do { ++i; s = (s+sskip)%len; } while (0!=s);
00026     // P(sskip); P(i);
00027   } while(len != i);
00028   return sskip;
00029 }
00030 
00035 char* readandinterleave(int fblocks, int stripe, FILE* infile)
00036 {
00037   char* buf = (char*) malloc((fblocks+hblen)*blklen*sizeof(char));
00038   // we avoid using new so the (very large!) buffer is not zeroed.
00039   if (NULL == buf) {
00040     std::cerr << progname << ": can't allocate enough memory ("
00041               << (fblocks+hblen)*blklen*sizeof(char) << " bytes)\n";
00042     abort();
00043   }
00044   // but we zero the last few blocks since they might be used later.
00045   memset(buf+(fblocks)*blklen,0,hblen*blklen*sizeof(char));
00046   long blkpos=0;
00047   for (long blkcount=0; blkcount<fblocks; ++blkcount) {
00048     if ( 0 == fread(buf+(blkpos*blklen), sizeof(char), blklen, infile) )
00049       { perror("readandinterleave"); abort(); }
00050     blkpos = (blkpos+stripe)%fblocks;
00051   }
00052   return buf;
00053 }
00054 
00059 void writeanddeinterleave(char* buf, int fblocks, int stripe, FILE* outfile)
00060 {
00061   long blkpos=0;
00062   for (long blkcount=0; blkcount<fblocks; ++blkcount) {
00063     if ( 0 == fwrite(buf+(blkpos*blklen), sizeof(char)*blklen, 1, outfile) )
00064       { perror("writeanddeinterleave"); abort(); }
00065     blkpos = (blkpos+stripe)%fblocks;
00066   }
00067 }
00068 
00070 void protectfile()
00071 {
00072   long i;
00073   long fsize;                   // file size of protectedfile
00074   long fblocks;                 // file size in blocks
00075   long stripeskip;              // striping parameter
00076   long ostripeskip;             // eccfile striping parameter
00077   FILE* infile=fopen(protectedfname,"rb");
00078   if (NULL == infile) { perror(protectedfname); abort(); }
00079   // calculate file size
00080   if (0 != fseek(infile, 0, SEEK_END) ) { perror(protectedfname); abort(); }
00081   fsize = ftell(infile);  P(fsize);
00082   fseek(infile,0,SEEK_SET);
00083   fblocks = fsize/blklen;
00084   if (fblocks*blklen<fsize) ++fblocks; // round up
00085   P(fblocks); assert(fblocks*blklen>=fsize);
00086   stripeskip=interleaveskip(fblocks,hblen);  P(stripeskip);
00087   
00088   // open eccfile
00089   FILE* eccfile=fopen(eccfname,"wb");
00090   if (NULL == eccfile) { perror(eccfname); abort(); }
00091 
00092   // now do the interleaving.
00093   if (verbose) {
00094     std::cout << "Reading " << protectedfname << std::endl;
00095     std::cout.flush();
00096   }
00097   char* inbuf = readandinterleave(fblocks,stripeskip,infile);
00098   assert(ftell(infile)==fsize); // P(inbuf);
00099 
00100   addheaderitem("protectedfile",protectedfname);
00101   addheaderitem("fsize",fsize);
00102   {
00103     char stim[64]; struct stat buf;
00104     stat(protectedfname,&buf);
00105     strftime(stim,64,"%Y-%m-%d %T",localtime(&buf.st_mtime));
00106     addheaderitem("fdate",stim);
00107   }
00108   addheaderitem("footprint",footprint(infile));
00109   {
00110     char stim[64]; time_t tim; time(&tim);
00111     strftime(stim,64,"%Y-%m-%d %T",localtime(&tim));
00112     addheaderitem("date",stim);
00113   }
00114   addheaderitem("blklen",blklen);
00115   addheaderitem("hblen",hblen);
00116   addheaderitem("hbcorr",hbcorr);
00117   addheaderitem("stripeskip",stripeskip);
00118   fclose(infile);
00119 
00120   // calculate ecc data
00121   char *protbuf, *writeptr;
00122   const long eccblocks=hbcorr*long(ceil(double(fblocks)/hblen));
00123   P(eccblocks);
00124   // we avoid using new so the (very large!) buffer is not zeroed.
00125   protbuf = (char*) malloc(eccblocks*blklen*sizeof(char));
00126   writeptr=protbuf;
00127   // for(i=0; i<eccblocks*blklen; ++i) protbuf[i]='y'; // for testing
00128   if (verbose) {
00129     std::cout << "Calculating ... " << std::endl; std::cout.flush();
00130   }
00131   for(i=0; i<fblocks ; i+=hblen) {
00132     hyperblockprotect(inbuf+i*blklen,writeptr);
00133     writeptr += hbcorr*blklen;
00134   }
00135   assert((writeptr-protbuf)/blklen == eccblocks);
00136   // P(protbuf); // P(crc(protbuf,eccblocks*blklen*sizeof(char)));
00137   // write ecc data to file
00138   ostripeskip=interleaveskip(eccblocks,hbcorr);  P(ostripeskip);
00139   addheaderitem("ostripeskip",ostripeskip);
00140   writeheader(eccfile); // first copy of header
00141   if (verbose) {
00142     std::cout << "Writing " << eccfname << std::endl; std::cout.flush();
00143   }
00144   writeanddeinterleave(protbuf, eccblocks, ostripeskip, eccfile);
00145   writeheader(eccfile); // second copy of header
00146   fclose(eccfile);
00147   free(inbuf);
00148 }
00149 
00151 bool correctfile()
00152 {
00153   long protfsize;                   // file size of protectedfile
00154   long protfblocks;                 // file size in blocks
00155   long eccfsize;                   // file size of eccfile
00156   long eccblocks;      // number of ecc hyperblocks (hbcorr blks) in eccfile
00157   long stripeskip;              // striping parameter
00158   long ostripeskip;              // striping parameter for ecc file
00159   // open protected file (to correct)
00160   FILE* protectedfile=fopen(protectedfname,"rb");
00161   if (NULL == protectedfile) { perror(protectedfname); abort(); }
00162   // calculate file size
00163   if (0 != fseek(protectedfile, 0, SEEK_END) ) { perror(protectedfname); abort(); }
00164   protfsize = ftell(protectedfile); rewind(protectedfile);
00165   P(protfsize);
00166   protfblocks = protfsize/blklen;
00167   if (protfblocks*blklen<protfsize) ++protfblocks; // round up
00168   P(protfblocks); assert(protfblocks*blklen>=protfsize);
00169   // open ecc file 
00170   FILE* eccfile=fopen(eccfname,"rb");
00171   if (NULL == eccfile) { perror(protectedfname); abort(); }
00172   // calculate file size
00173   if (0 != fseek(eccfile, 0, SEEK_END) ) { perror(protectedfname); abort(); }
00174   eccfsize = ftell(eccfile);  P(eccfsize);
00175   fseek(eccfile,0,SEEK_SET);
00176   eccblocks = (eccfsize-2*headerlen)/blklen;
00177   P(eccblocks); assert(eccblocks*blklen+2*headerlen == eccfsize);
00178   // read header
00179   char* header=readheader(eccfile); // P(header);
00180   while(*header) {
00181     char* value=index(header,'='); *(value++)=0;
00182     char* key=header;
00183     header=index(value,';'); *(header++)=0;
00184     if ( 0 == strcmp(key,"protectedfile") ) {
00185       P(key);
00186       P(/*protectedfile*/value);
00187       // ignore for now
00188     } else if ( 0 == strcmp(key,"fsize") ) {
00189       P(key);
00190       P(value);
00191       assert ( atol(value) == protfsize );
00192       // XXX: we should ask what to do, here.
00193     } else if ( 0 == strcmp(key,"fdate") ) {
00194       P(key);
00195       P(/*fdate*/value);
00196       // ignore for now
00197     } else if ( 0 == strcmp(key,"date") ) {
00198       P(key);
00199       P(/*date*/value);
00200       // ignore for now
00201     } else if ( 0 == strcmp(key,"footprint") ) {
00202       char *protfprint = footprint(protectedfile);
00203       P(protfprint);
00204       P(     value);
00205       if (0 != strcmp(protfprint, value) ) {
00206         std::cerr << protectedfname << ": footprints are not conforming ("
00207                   << int(100*footPrintDiff(protfprint, value)) << "%) :"
00208                   << protfprint << " versus " << value << "\n";
00209       }
00210       // XXX: we should ask whether we should continue.
00211     } else if ( 0 == strcmp(key,"blklen") ) {
00212       // blklen=atol(value);
00213       assert( blklen == atol(value) ); // const
00214       P(blklen);
00215     } else if ( 0 == strcmp(key,"hblen") ) {
00216       hblen=atol(value); P(hblen); 
00217     } else if ( 0 == strcmp(key,"hbcorr") ) {
00218       // hbcorr=atol(value);
00219       assert( hbcorr == atol(value) );  // const
00220       P(hbcorr);
00221     } else if ( 0 == strcmp(key,"stripeskip") ) {
00222       stripeskip=atol(value); P(stripeskip);
00223     } else if ( 0 == strcmp(key,"ostripeskip") ) {
00224       ostripeskip=atol(value); P(ostripeskip);
00225     } else {
00226       std::cerr << progname << ": unknown tag " << key << "=" << value
00227                 << " in eccfile " << eccfname << "\n";
00228     }
00229   }
00230   
00231   // read and interleave the protectedfile
00232   rewind(protectedfile);
00233   if (verbose) {
00234     std::cout << "Reading " << protectedfname << std::endl; std::cout.flush();
00235   }
00236   char* inbuf=readandinterleave(protfblocks,stripeskip,protectedfile);
00237   assert(ftell(protectedfile)==protfsize); // P(inbuf);
00238   fclose(protectedfile);
00239 
00240   // read eccfile and correct file
00241   int errors = 0, i;
00242   char *protbuf;                 // data from the ecc file
00243   if (verbose) {
00244     std::cout << "Reading " << eccfname << std::endl;
00245     std::cout.flush();
00246   }
00247   protbuf =   readandinterleave(eccblocks,ostripeskip,eccfile);
00248   // P(protbuf); P(crc(protbuf,eccblocks*blklen*sizeof(char))); 
00249   char *protptr=protbuf;
00250   if (verbose) {
00251     std::cout << "Calculating ... " << std::endl; std::cout.flush();
00252   }
00253   for(i=0; i<protfblocks ; i+=hblen) {
00254     bool correctable = hyperblockcorrect(inbuf+i*blklen,protptr);
00255     if (!correctable) std::cout << "uncorr(" << i << ") ";
00256     errors += correctable ? 0 : 1;
00257     protptr += hbcorr*blklen;
00258   }
00259   if (errors > 0) {
00260     std::cout << "WARNING: " << errors << " uncorrectable out of "
00261               << (protfblocks/hblen) << " hyperblocks"
00262               << " in file " << correctedfname << "\n";
00263   }
00264   fclose(eccfile);
00265   
00266   // write the corrected file
00267   FILE* correctedfile=fopen(correctedfname,"wb");
00268   if (NULL == correctedfile) { perror(correctedfname); abort(); }
00269   // ensure that required size is available
00270   fseek(correctedfile, protfsize-1, SEEK_SET); 
00271   fwrite("e",1,1,correctedfile); rewind(correctedfile);
00272   if (verbose) {
00273     std::cout << "Writing " << protectedfname << std::endl; std::cout.flush();
00274   }
00275   writeanddeinterleave(inbuf,protfblocks,stripeskip,correctedfile);
00276   free(inbuf); fclose(correctedfile);
00277   // we have to truncate it again, since we might have written too much
00278   // at the last block.
00279   if ( 0 != truncate(correctedfname, protfsize) ) {
00280     perror(correctedfname); abort();
00281   }
00282   
00283   // return value
00284   if ( 0 == errors ) {
00285     if ( verbose ) std::cout << "File " << correctedfname << " is OK.\n";
00286     return true;
00287   }
00288   return false; // uncorrectable errors.
00289 }

Generated on Tue Dec 30 12:07:35 2003 for ErrorProtect by doxygen 1.3.2