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
00021 long i,s;
00022 do {
00023 --sskip;
00024 i=0; s=0;
00025 do { ++i; s = (s+sskip)%len; } while (0!=s);
00026
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
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
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;
00074 long fblocks;
00075 long stripeskip;
00076 long ostripeskip;
00077 FILE* infile=fopen(protectedfname,"rb");
00078 if (NULL == infile) { perror(protectedfname); abort(); }
00079
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;
00085 P(fblocks); assert(fblocks*blklen>=fsize);
00086 stripeskip=interleaveskip(fblocks,hblen); P(stripeskip);
00087
00088
00089 FILE* eccfile=fopen(eccfname,"wb");
00090 if (NULL == eccfile) { perror(eccfname); abort(); }
00091
00092
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);
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
00121 char *protbuf, *writeptr;
00122 const long eccblocks=hbcorr*long(ceil(double(fblocks)/hblen));
00123 P(eccblocks);
00124
00125 protbuf = (char*) malloc(eccblocks*blklen*sizeof(char));
00126 writeptr=protbuf;
00127
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
00137
00138 ostripeskip=interleaveskip(eccblocks,hbcorr); P(ostripeskip);
00139 addheaderitem("ostripeskip",ostripeskip);
00140 writeheader(eccfile);
00141 if (verbose) {
00142 std::cout << "Writing " << eccfname << std::endl; std::cout.flush();
00143 }
00144 writeanddeinterleave(protbuf, eccblocks, ostripeskip, eccfile);
00145 writeheader(eccfile);
00146 fclose(eccfile);
00147 free(inbuf);
00148 }
00149
00151 bool correctfile()
00152 {
00153 long protfsize;
00154 long protfblocks;
00155 long eccfsize;
00156 long eccblocks;
00157 long stripeskip;
00158 long ostripeskip;
00159
00160 FILE* protectedfile=fopen(protectedfname,"rb");
00161 if (NULL == protectedfile) { perror(protectedfname); abort(); }
00162
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;
00168 P(protfblocks); assert(protfblocks*blklen>=protfsize);
00169
00170 FILE* eccfile=fopen(eccfname,"rb");
00171 if (NULL == eccfile) { perror(protectedfname); abort(); }
00172
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
00179 char* header=readheader(eccfile);
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(value);
00187
00188 } else if ( 0 == strcmp(key,"fsize") ) {
00189 P(key);
00190 P(value);
00191 assert ( atol(value) == protfsize );
00192
00193 } else if ( 0 == strcmp(key,"fdate") ) {
00194 P(key);
00195 P(value);
00196
00197 } else if ( 0 == strcmp(key,"date") ) {
00198 P(key);
00199 P(value);
00200
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
00211 } else if ( 0 == strcmp(key,"blklen") ) {
00212
00213 assert( blklen == atol(value) );
00214 P(blklen);
00215 } else if ( 0 == strcmp(key,"hblen") ) {
00216 hblen=atol(value); P(hblen);
00217 } else if ( 0 == strcmp(key,"hbcorr") ) {
00218
00219 assert( hbcorr == atol(value) );
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
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);
00238 fclose(protectedfile);
00239
00240
00241 int errors = 0, i;
00242 char *protbuf;
00243 if (verbose) {
00244 std::cout << "Reading " << eccfname << std::endl;
00245 std::cout.flush();
00246 }
00247 protbuf = readandinterleave(eccblocks,ostripeskip,eccfile);
00248
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
00267 FILE* correctedfile=fopen(correctedfname,"wb");
00268 if (NULL == correctedfile) { perror(correctedfname); abort(); }
00269
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
00278
00279 if ( 0 != truncate(correctedfname, protfsize) ) {
00280 perror(correctedfname); abort();
00281 }
00282
00283
00284 if ( 0 == errors ) {
00285 if ( verbose ) std::cout << "File " << correctedfname << " is OK.\n";
00286 return true;
00287 }
00288 return false;
00289 }