📄 recovery.c
字号:
/* * $Id: recovery.c,v 1.5 2003/05/03 22:18:48 andrew_belov Exp $ * --------------------------------------------------------------------------- * This module contains a set of procedures to create and use special recovery * records (XRJ files) introduced with ARJ v 2.55. * */#include "arj.h"DEBUGHDR(__FILE__) /* Debug information block */#define DEFAULT_PROTPAD_SIZE 1024 /* Protection data granularity */#define MAX_BLOCK_SIZE 4096 /* Maximum size of temporary block */#define DIVISOR_BITS 10 /* Depends on data granularity */#define PROTBLOCK_HDR_SIZE 14 /* Header of protection block */#define PROT_SIG_SIZE 6 /* Signature size *//* Local variables */static char prot_sig[]="PSigx"; /* Protection block signature */static char blocks_numstr[]="%3dx "; /* Number of blocks to process */static char prot_ticker[]="."; /* Block counter */static unsigned long prot_blk_size=0L; /* Size of std. protection block *//* Calculates CRC-16 of the given block. The result differs from the one given by CCITT V.41 CRC-16. */static unsigned short crc16_for_block(char *data, int len){ int remain; unsigned char *tmp_dptr; unsigned short crc16term; tmp_dptr=(unsigned char *)data; crc16term=0; for(remain=len; remain>0; remain--) { crc16term=crc16tab[crc16term>>8]^((crc16term<<8)|(unsigned short)(*(tmp_dptr++))); } return(crc16term^0xAAAA);}/* Returns number of bytes needed to hold the temporary block */static int calc_protpad_size(int len){ long tmp_len, divisor; tmp_len=(long)len+1; while(1) { divisor=2L; while(divisor*divisor<=tmp_len) { if(tmp_len%divisor==0L) break; else divisor++; } if(tmp_len%divisor!=0L) break; tmp_len++; } return((int)tmp_len);}/* Returns the proportion of protection data size to archive size, per mille */static long calc_protdata_pct(unsigned long protsize, unsigned long archsize){ int dec; for(dec=0; dec<3; dec++) { if(protsize<=0x19999999) protsize*=10L; else archsize/=10L; } if(archsize==0) return(0); else return(protsize/archsize);}/* Relocates the protection data */static void relocate_protdata(char *dest, char *src, int len){ int i; for(i=0; i<len; i++) *(dest++)=*(src++);}/* Returns the overall size of protection data */unsigned long calc_protdata_size(unsigned long limit, int threshold){ unsigned int ct; if(prot_blk_size==0L) { prot_blk_size=(DEFAULT_PROTPAD_SIZE- ((unsigned long) (calc_protpad_size(DEFAULT_PROTPAD_SIZE)+ 4-DEFAULT_PROTPAD_SIZE)*2L+PROTBLOCK_HDR_SIZE))>>1; if(prot_blk_size>16384L) prot_blk_size=16384L; } ct=0; while(prot_blk_size>MAX_BLOCK_SIZE) { prot_blk_size>>=1; ct++; } prot_blk_size*=DEFAULT_PROTPAD_SIZE; prot_blk_size>>=(DIVISOR_BITS-ct); return((((limit>>(DIVISOR_BITS-ct))/prot_blk_size+1L)* threshold*DEFAULT_PROTPAD_SIZE)<<2);}/* Creates a protection file for the given archive */int create_protfile(FILE *stream, unsigned long offset, int state){ int protpad_size; int pad1_size, pad2_size; int block_size; char *pad_array[4]; char *protpad, *protpad_r; char *single_pad, *single_pad_r; char *protpad_bck; unsigned long ifile_size; /* Input file size */ unsigned long block_offset; int block_divisor; int total_blocks; /* Total number of MAX_BLOCK_SIZE-byte blocks in the recovery file. */ int cur_block; /* 0-relative */ int pad_ctr; int section_size; /* Number of bytes read */ unsigned long crc32_tmp; long per_mille; unsigned long data_offset; protpad_size=calc_protpad_size(DEFAULT_PROTPAD_SIZE); pad1_size=protpad_size+4-DEFAULT_PROTPAD_SIZE; pad2_size=(pad1_size<<1)+PROTBLOCK_HDR_SIZE; block_size=(DEFAULT_PROTPAD_SIZE-pad2_size)>>1; #ifndef __32BIT__ if(block_size>MAX_BLOCK_SIZE) block_size=MAX_BLOCK_SIZE; #else if(block_size>16384) block_size=16384; #endif protpad=malloc_msg(protpad_size+2); protpad_r=malloc_msg(protpad_size+2); single_pad=malloc_msg(DEFAULT_PROTPAD_SIZE+2); single_pad_r=malloc_msg(DEFAULT_PROTPAD_SIZE+2); protpad_bck=malloc_msg(protpad_size+2); pad_array[0]=single_pad; pad_array[1]=protpad; pad_array[2]=protpad_r; pad_array[3]=single_pad_r; fseek(stream, 0L, SEEK_END); ifile_size=ftell(stream); fseek(stream, 0L, SEEK_END); file_write(prot_sig, 1, PROT_SIG_SIZE, stream); fseek(stream, 0L, SEEK_END); data_offset=ftell(stream); block_offset=(unsigned long)block_size; for(block_divisor=0; block_offset>MAX_BLOCK_SIZE; block_divisor++) block_offset>>=1; block_offset*=(unsigned long)DEFAULT_PROTPAD_SIZE; block_offset>>=(DIVISOR_BITS-block_divisor); total_blocks=((ifile_size>>(DIVISOR_BITS-block_divisor))/block_offset+1); total_blocks=state?offset:offset*total_blocks; msg_cprintf(0, M_WORKING); msg_cprintf(0, (FMSG *)blocks_numstr, total_blocks); for(cur_block=0; cur_block<total_blocks; cur_block++) { msg_cprintf(0, (FMSG *)prot_ticker); for(pad_ctr=0; pad_ctr<protpad_size; pad_ctr++) protpad_r[pad_ctr]=protpad[pad_ctr]='\0'; for(pad_ctr=0; pad_ctr<DEFAULT_PROTPAD_SIZE; pad_ctr++) single_pad_r[pad_ctr]=single_pad[pad_ctr]='\0'; block_divisor=0; block_offset=(unsigned long)cur_block*(unsigned long)DEFAULT_PROTPAD_SIZE; while(block_offset<ifile_size) { fseek(stream, block_offset, SEEK_SET); section_size=min(DEFAULT_PROTPAD_SIZE, (ifile_size-block_offset)); section_size=fread(protpad_bck+1, 1, section_size, stream); protpad_bck[0]='\0'; for(pad_ctr=section_size+1; pad_ctr<protpad_size; pad_ctr++) protpad_bck[pad_ctr]='\0'; for(pad_ctr=0; pad_ctr<protpad_size; pad_ctr++) { protpad[pad_ctr]^=protpad_bck[pad_ctr]; protpad_r[pad_ctr]^=protpad_bck[(pad_ctr+block_divisor)%protpad_size]; } crc32term=(unsigned long) crc16_for_block(protpad_bck+1, DEFAULT_PROTPAD_SIZE); crc32_for_block(protpad_bck+1, DEFAULT_PROTPAD_SIZE); crc32_tmp=crc32term; pad_ctr=(pad1_size<<1)+((block_divisor<<2)>>1)+DIVISOR_BITS; if(pad_ctr+1>=DEFAULT_PROTPAD_SIZE) error(M_PROTECT_BUG); mput_word(crc32_tmp, &single_pad [pad_ctr]); mput_word(crc32_tmp>>16, &single_pad_r[pad_ctr]); block_offset+=(unsigned long)total_blocks* (unsigned long)DEFAULT_PROTPAD_SIZE; block_divisor++; } for(pad_ctr=0; pad_ctr<pad1_size; pad_ctr++) { section_size=protpad_size-pad1_size; single_pad_r[pad_ctr+10]=single_pad[pad_ctr+10]= protpad[section_size+pad_ctr]; single_pad_r[pad_ctr+pad1_size+10]=single_pad[pad_ctr+pad1_size+10]= protpad_r[section_size+pad_ctr]; } mput_word ( 0x1111, &single_pad [0]); mput_word ( 0x1111, &single_pad_r[0]); mput_word ( total_blocks, &single_pad [2]); mput_word ( total_blocks, &single_pad_r[2]); mput_word ( DEFAULT_PROTPAD_SIZE, &single_pad [4]); mput_word ( DEFAULT_PROTPAD_SIZE, &single_pad_r[4]); mput_dword ( ifile_size, &single_pad [6]); mput_dword ( ifile_size, &single_pad_r[6]); for(block_divisor=0; block_divisor<4; block_divisor++) { relocate_protdata(protpad_bck+4, pad_array[block_divisor], DEFAULT_PROTPAD_SIZE-4); crc32term=CRC_MASK; crc32_for_block(protpad_bck+4, DEFAULT_PROTPAD_SIZE-4); mput_dword(crc32term, protpad_bck); fseek(stream, (unsigned long)DEFAULT_PROTPAD_SIZE* (unsigned long)cur_block+(unsigned long)block_divisor* (unsigned long)total_blocks*(unsigned long)DEFAULT_PROTPAD_SIZE+ data_offset, SEEK_SET); file_write(protpad_bck, 1, DEFAULT_PROTPAD_SIZE, stream); } } fseek(stream, 0L, SEEK_END); block_offset=ftell(stream)-data_offset; per_mille=calc_protdata_pct(block_offset, ifile_size); nputlf(); msg_cprintf(0, M_PROT_RATIO, block_offset, per_mille/10L, (int)(per_mille%10L)); free(protpad); free(protpad_r); free(single_pad); free(single_pad_r); free(protpad_bck); return(0);}/* Aborts the recovery process, saying "too much damage" */static void abort_recovery(){ error(M_RECOVERY_ABORTED);}/* Checks for a protection signature */unsigned long chk_prot_sig(FILE *stream, unsigned long rp_ofs){ unsigned long sig_offset=0L; unsigned long fsize; char c; char pad[10]; fseek(stream, 0L, SEEK_END); fsize=ftell(stream); while(rp_ofs<fsize) { fseek(stream, rp_ofs, SEEK_SET); c=fgetc(stream); while(rp_ofs<fsize) { if(c!=prot_sig[0]) c=fgetc(stream); else { c=fgetc(stream); if(c==prot_sig[1]) break; } rp_ofs++; } if(rp_ofs>=fsize) break; if(fread(pad, 1, PROT_SIG_SIZE-2, stream)!=PROT_SIG_SIZE-2) break; if(!strcmp(prot_sig+2, pad)) { sig_offset=ftell(stream); if(rp_ofs!=0) break; } rp_ofs++; } return(sig_offset);}/* Verifies and/or repairs a damaged archive */int recover_file(char *name, char *protname, char *rec_name, int test_mode, unsigned long sig_offset){ unsigned int cur_stream; unsigned int cur_section; unsigned long block_offset; unsigned long ifile_size; unsigned long orig_ifile_size; /* Size of undamaged input file (stored in the protection file) */ unsigned long dest_file_size; /* Size of output file (number of bytes to write) */ int errors; /* Total number of damaged sections */ int protpad_size; int pad1_size; int section_size; /* Number of bytes read */ int total_blocks; int data_damage; /* Data damage flag */ int damage_level; /* 0, 1 or 2 (highest) */ int damage_flag, pad_damage_flag; int pad_flag, bck_pad_flag; /* Section damage flag */ int rec_size=0, bck_rec_size=0; /* Recovered sections size */ char *protpad, *protpad_r; char *single_pad, *single_pad_r; char *protpad_bck; FILE *astream, *xstream; /* ARJ and XRJ files */ FILE *ostream; /* Destination file */ int pad_ctr; unsigned long rd_offset; /* Offset of recovery data within xstream */ int ins_lf=0; errors=0; protpad_size=calc_protpad_size(DEFAULT_PROTPAD_SIZE); /* -> EBX */ pad1_size=protpad_size+4-DEFAULT_PROTPAD_SIZE; protpad=malloc_msg(protpad_size+2); protpad_r=malloc_msg(protpad_size+2); single_pad=malloc_msg(DEFAULT_PROTPAD_SIZE+2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -