(C) Relatively high density file backups on paper. Cross-platform CLI port of Ollydbg's Paperback from Windows and Borland C.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

Fileproc.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. ////////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // PaperBack -- high density backups on the plain paper //
  4. // //
  5. // Copyright (c) 2007 Oleh Yuschuk //
  6. // ollydbg at t-online de (set Subject to 'paperback' or be filtered out!) //
  7. // //
  8. // //
  9. // This file is part of PaperBack. //
  10. // //
  11. // Paperback is free software; you can redistribute it and/or modify it under //
  12. // the terms of the GNU General Public License as published by the Free //
  13. // Software Foundation; either version 3 of the License, or (at your option) //
  14. // any later version. //
  15. // //
  16. // PaperBack is distributed in the hope that it will be useful, but WITHOUT //
  17. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //
  18. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for //
  19. // more details. //
  20. // //
  21. // You should have received a copy of the GNU General Public License along //
  22. // with this program. If not, see <http://www.gnu.org/licenses/>. //
  23. // //
  24. // //
  25. // Note that bzip2 compression/decompression library, which is the part of //
  26. // this project, is covered by different license, which, in my opinion, is //
  27. // compatible with GPL. //
  28. // //
  29. ////////////////////////////////////////////////////////////////////////////////
  30. #ifdef _WIN32
  31. #include <windows.h>
  32. #elif __linux__
  33. #include <sys/stat.h>
  34. #endif
  35. #include <stdlib.h>
  36. #include <algorithm>
  37. #include <stdint.h>
  38. #include "bzlib.h"
  39. #include "aes.h"
  40. #include "paperbak.h"
  41. #include "Resource.h"
  42. // Clears descriptor of processed file
  43. void Closefproc(int slot) {
  44. if (slot<0 || slot>=NFILE)
  45. return; // Error in input data
  46. if (::pb_fproc[slot].datavalid!=NULL)
  47. free(::pb_fproc[slot].datavalid);
  48. if (::pb_fproc[slot].data!=NULL)
  49. free(::pb_fproc[slot].data);
  50. memset(::pb_fproc+slot,0,sizeof(t_fproc));
  51. //Updatefileinfo(slot,::pb_fproc+slot); //GUI
  52. };
  53. // Starts new decoded page. Returns non-negative index to table of processed
  54. // files on success or -1 on error.
  55. int Startnextpage(t_superblock *superblock) {
  56. int i,slot,freeslot;
  57. t_fproc *pf;
  58. // Check whether file is already in the list of processed files. If not,
  59. // initialize new descriptor.
  60. freeslot=-1;
  61. for (slot=0,pf=::pb_fproc; slot<NFILE; slot++,pf++) {
  62. if (pf->busy==0) { // Empty descriptor
  63. if (freeslot<0) freeslot=slot;
  64. continue; };
  65. if (strnicmp(pf->name,superblock->name,64)!=0)
  66. continue; // Different file name
  67. if (pf->mode!=superblock->mode)
  68. continue; // Different compression mode
  69. if (pf->modified.dwLowDateTime!=superblock->modified.dwLowDateTime ||
  70. pf->modified.dwHighDateTime!=superblock->modified.dwHighDateTime)
  71. continue; // Different timestamp - wrong version?
  72. if (pf->datasize!=superblock->datasize)
  73. continue; // Different compressed size
  74. if (pf->origsize!=superblock->origsize)
  75. continue; // Different original size
  76. // File found. Check for the case of two backup copies printed with
  77. // different settings.
  78. if (pf->pagesize!=superblock->pagesize)
  79. pf->pagesize=0;
  80. break; };
  81. if (slot>=NFILE) {
  82. // No matching descriptor, create new one.
  83. if (freeslot<0) {
  84. Reporterror("Maximal number of processed files exceeded");
  85. return -1; };
  86. slot=freeslot;
  87. pf=::pb_fproc+slot;
  88. memset(pf,0,sizeof(t_fproc));
  89. // Allocate block and recovery tables.
  90. pf->nblock=(superblock->datasize+NDATA-1)/NDATA;
  91. pf->datavalid=(uchar *)calloc(pf->nblock, sizeof(uchar));
  92. pf->data=(uchar *)calloc(pf->nblock*NDATA, sizeof(uchar));
  93. if (pf->datavalid==NULL || pf->data==NULL) {
  94. if (pf->datavalid!=NULL) free(pf->datavalid);
  95. if (pf->data!=NULL) free(pf->data);
  96. Reporterror("Low memory");
  97. return -1;
  98. };
  99. // Initialize remaining fields.
  100. memcpy(pf->name,superblock->name,64);
  101. pf->modified=superblock->modified;
  102. pf->attributes=superblock->attributes;
  103. pf->filecrc=superblock->filecrc;
  104. pf->datasize=superblock->datasize;
  105. pf->pagesize=superblock->pagesize;
  106. pf->origsize=superblock->origsize;
  107. pf->mode=superblock->mode;
  108. if (pf->pagesize>0)
  109. pf->npages=(pf->datasize+pf->pagesize-1)/pf->pagesize;
  110. else
  111. pf->npages=0;
  112. pf->ndata=0;
  113. for (i=0; i<pf->npages && i<8; i++)
  114. pf->rempages[i]=i+1;
  115. // Initialize statistics and declare descriptor as busy.
  116. pf->goodblocks=0;
  117. pf->badblocks=0;
  118. pf->restoredbytes=0;
  119. pf->recoveredblocks=0;
  120. pf->busy=1; };
  121. // Invalidate page limits and report success.
  122. pf=::pb_fproc+slot;
  123. pf->page=superblock->page;
  124. pf->ngroup=superblock->ngroup;
  125. pf->minpageaddr=0xFFFFFFFF;
  126. pf->maxpageaddr=0;
  127. //Updatefileinfo(slot,pf);
  128. return slot;
  129. };
  130. // Adds block recognized by decoder to file described by file descriptor with
  131. // specified index. Returns 0 on success and -1 on any error.
  132. int Addblock(t_block *block,int slot) {
  133. int i,j;
  134. t_fproc *pf;
  135. if (slot<0 || slot>=NFILE)
  136. return -1; // Invalid index of file descriptor
  137. pf=::pb_fproc+slot;
  138. if (pf->busy==0)
  139. return -1; // Index points to unused descriptor
  140. // Add block to descriptor.
  141. if (block->recsize==0) {
  142. // Ordinary data block.
  143. i=block->addr/NDATA;
  144. if ((uint32_t)(i*NDATA)!=block->addr)
  145. return -1; // Invalid data alignment
  146. if (i>=pf->nblock)
  147. return -1; // Data outside the data size
  148. if (pf->datavalid[i]!=1) {
  149. memcpy(pf->data+block->addr,block->data,NDATA);
  150. pf->datavalid[i]=1; // Valid data
  151. pf->ndata++; };
  152. pf->minpageaddr=std::min(pf->minpageaddr,block->addr);
  153. pf->maxpageaddr=std::max(pf->maxpageaddr,block->addr+NDATA); }
  154. else {
  155. // Data recovery block. I write it to all free locations within the group.
  156. if (block->recsize!=(uint32_t)(pf->ngroup*NDATA))
  157. return -1; // Invalid recovery scope
  158. i=block->addr/block->recsize;
  159. if (i*block->recsize!=block->addr)
  160. return -1; // Invalid data alignment
  161. i=block->addr/NDATA;
  162. for (j=i; j<i+pf->ngroup; j++) {
  163. if (j>=pf->nblock)
  164. return -1; // Data outside the data size
  165. if (pf->datavalid[j]!=0) continue;
  166. memcpy(pf->data+j*NDATA,block->data,NDATA);
  167. pf->datavalid[j]=2; }; // Valid recovery data
  168. pf->minpageaddr=std::min(pf->minpageaddr,block->addr);
  169. pf->maxpageaddr=std::max(pf->maxpageaddr,block->addr+block->recsize);
  170. };
  171. // Report success.
  172. return 0;
  173. };
  174. // Processes gathered data. Returns -1 on error, 0 if file is complete and
  175. // number of pages to scan if there is still missing data. In the last case,
  176. // fills list of several first remaining pages in file descriptor.
  177. int Finishpage(int slot,int ngood,int nbad,uint32_t nrestored) {
  178. int i,j,r,rmin,rmax,nrec,irec,firstblock,nrempages;
  179. uchar *pr,*pd;
  180. t_fproc *pf;
  181. if (slot<0 || slot>=NFILE)
  182. return -1; // Invalid index of file descriptor
  183. pf=::pb_fproc+slot;
  184. if (pf->busy==0)
  185. return -1; // Index points to unused descriptor
  186. // Update statistics. Note that it grows also when the same page is scanned
  187. // repeatedly.
  188. pf->goodblocks+=ngood;
  189. pf->badblocks+=nbad;
  190. pf->restoredbytes+=nrestored;
  191. printf("ngood: %d", pb_procdata.ngood);
  192. printf("nbad: %d", pb_procdata.nbad);
  193. printf("nsuper: %d", pb_procdata.nsuper);
  194. printf("nrestored: %d", pb_procdata.nrestored);
  195. // Restore bad blocks if corresponding recovery blocks are available (max. 1
  196. // per group).
  197. if (pf->ngroup>0) {
  198. rmin=(pf->minpageaddr/(NDATA*pf->ngroup))*pf->ngroup;
  199. rmax=(pf->maxpageaddr/(NDATA*pf->ngroup))*pf->ngroup;
  200. // Walk groups of data on current page, one by one.
  201. for (r=rmin; r<=rmax; r+=pf->ngroup) {
  202. if (r+pf->ngroup>pf->nblock)
  203. break; // Inconsistent data
  204. // Count blocks with recovery data in the group.
  205. nrec=0;
  206. for (i=r; i<r+pf->ngroup; i++) {
  207. if (pf->datavalid[i]==2) {
  208. nrec++; irec=i;
  209. pf->datavalid[i]=0; // Prepare for next round
  210. };
  211. };
  212. if (nrec==1) {
  213. // Exactly one block in group is missing, recovery is possible.
  214. pr=pf->data+irec*NDATA;
  215. // Invert recovery data.
  216. for (j=0; j<NDATA; j++) *pr++^=0xFF;
  217. // XOR recovery data with good data blocks.
  218. for (i=r; i<r+pf->ngroup; i++) {
  219. if (i==irec) continue;
  220. pr=pf->data+irec*NDATA;
  221. pd=pf->data+i*NDATA;
  222. for (j=0; j<NDATA; j++) {
  223. *pr++^=*pd++;
  224. };
  225. };
  226. pf->datavalid[irec]=1;
  227. pf->recoveredblocks++;
  228. pf->ndata++;
  229. };
  230. };
  231. };
  232. // Check whether there are still bad blocks on the page.
  233. firstblock=(pf->page-1)*(pf->pagesize/NDATA);
  234. for (j=firstblock; j<firstblock+pf->pagesize/NDATA && j<pf->nblock; j++) {
  235. if (pf->datavalid[j]!=1) break; };
  236. if (j<firstblock+pf->pagesize/NDATA && j<pf->nblock)
  237. Message("Unrecoverable errors on page, please scan it again",0);
  238. else if (nbad>0)
  239. Message("Page processed, all bad blocks successfully restored",0);
  240. else
  241. Message("Page processed",0);
  242. // Calculate list of (partially) incomplete pages.
  243. nrempages=0;
  244. if (pf->pagesize>0) {
  245. for (i=0; i<pf->npages && nrempages<8; i++) {
  246. firstblock=i*(pf->pagesize/NDATA);
  247. for (j=firstblock; j<firstblock+pf->pagesize/NDATA && j<pf->nblock; j++) {
  248. if (pf->datavalid[j]==1)
  249. continue;
  250. // Page incomplete.
  251. pf->rempages[nrempages++]=i+1;
  252. break;
  253. };
  254. };
  255. };
  256. if (nrempages<8)
  257. pf->rempages[nrempages]=0;
  258. //Updatefileinfo(slot,pf);
  259. if (pf->ndata==pf->nblock) {
  260. if (::pb_autosave==0) {
  261. Message("File restored.",0);
  262. }
  263. else {
  264. Message("File complete",0);
  265. Saverestoredfile(slot,0);
  266. };
  267. };
  268. return 0; ////////////////////////////////////////////////////////////////////
  269. };
  270. // Saves file with specified index and closes file descriptor (if force is 1,
  271. // attempts to save data even if file is not yet complete). Returns 0 on
  272. // success and -1 on error.
  273. int Saverestoredfile(int slot,int force) {
  274. int n,success;
  275. ushort filecrc;
  276. uint32_t l,length;
  277. uchar *bufout,*data,*tempdata;
  278. t_fproc *pf;
  279. aes_context ctx;
  280. //HANDLE hfile;
  281. FILE *hfile;
  282. if (slot<0 || slot>=NFILE)
  283. return -1; // Invalid index of file descriptor
  284. pf=::pb_fproc+slot;
  285. if (pf->busy==0 || pf->nblock==0)
  286. return -1; // Index points to unused descriptor
  287. if (pf->ndata!=pf->nblock && force==0)
  288. return -1; // Still incomplete data
  289. Message("",0);
  290. // If data is encrypted, decrypt it to temporary buffer. Decryption in place
  291. // is possible, but the whole data would be lost if password is incorrect.
  292. if (pf->mode & PBM_ENCRYPTED) {
  293. if (pf->datasize & 0x0000000F) {
  294. Reporterror("Encrypted data is not aligned");
  295. return -1;
  296. };
  297. if (Getpassword()!=0) {
  298. Reporterror("Cancelling bitmap decoding");
  299. return -1; // User cancelled decryption
  300. }
  301. tempdata=(uchar *)malloc(pf->datasize);
  302. if (tempdata==NULL) {
  303. Reporterror("Low memory, can't decrypt data");
  304. return -1;
  305. };
  306. n=strlen(::pb_password);
  307. while (n<PASSLEN) ::pb_password[n++]=0;
  308. memset(&ctx,0,sizeof(ctx));
  309. aes_set_key(&ctx,(uchar *)::pb_password,256);
  310. for (l=0; l<pf->datasize; l+=16)
  311. aes_decrypt(&ctx,pf->data+l,tempdata+l);
  312. filecrc=Crc16(tempdata,pf->datasize);
  313. if (filecrc!=pf->filecrc) {
  314. Reporterror("Invalid password, please try again");
  315. free (tempdata);
  316. return -1;
  317. }
  318. else {
  319. free (pf->data);
  320. pf->data=tempdata;
  321. pf->mode&=~PBM_ENCRYPTED;
  322. };
  323. };
  324. // If data is compressed, unpack it to temporary buffer.
  325. if ((pf->mode & PBM_COMPRESSED)==0) {
  326. // Data is not compressed.
  327. data=pf->data; length=pf->origsize;
  328. bufout=NULL;
  329. }
  330. else {
  331. // Data is compressed. Create temporary buffer.
  332. if (pf->origsize==0)
  333. pf->origsize=pf->datasize*4; // Weak attempt to recover
  334. bufout=(uchar *)malloc(pf->origsize);
  335. if (bufout==NULL) {
  336. Reporterror("Low memory");
  337. return -1; };
  338. // Unpack data.
  339. length=pf->origsize;
  340. success=BZ2_bzBuffToBuffDecompress((char *)bufout,(uint *)&length,
  341. (char*)pf->data,pf->datasize,0,0);
  342. if (success!=BZ_OK) {
  343. free (bufout);
  344. Reporterror("Unable to unpack data");
  345. return -1; };
  346. data=bufout; };
  347. // Ask user for file name.
  348. // FIXME selectoutfile must be initialized prior/by arg
  349. //if (pf->name!=NULL) {
  350. // if (bufout!=NULL) free (bufout);
  351. // return -1;
  352. //};
  353. // Open file and save data.
  354. //hfile=CreateFile(::pb_outfile,GENERIC_WRITE,0,NULL,
  355. // CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
  356. hfile = fopen (::pb_outfile, "wb");
  357. if (hfile==NULL) {
  358. if (bufout!=NULL)
  359. free (bufout);
  360. Reporterror("Unable to create file");
  361. return -1;
  362. };
  363. //WriteFile(hfile,data,length,&l,NULL);
  364. l = fwrite (data, sizeof(char), length, hfile);
  365. // Restore old modification date and time.
  366. #ifdef _WIN32
  367. // open HANDLE and set file time
  368. handleFile=CreateFile(::pb_outfile,GENERIC_WRITE,0,NULL,
  369. CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
  370. if (handleFile==INVALID_HANDLE_VALUE) {
  371. if (bufout!=NULL)
  372. free(bufout);
  373. Reporterror("Unable to open handle to set file time");
  374. return -1;
  375. };
  376. SetFileTime(handleFile,&pf->modified,&pf->modified,&pf->modified);
  377. // Close file and restore old basic attributes.
  378. CloseHandle(hfile);
  379. SetFileAttributes(::pb_outfile,pf->attributes);
  380. if (bufout!=NULL)
  381. free(bufout);
  382. if (l!=length) {
  383. Reporterror("I/O error");
  384. return -1;
  385. };
  386. #elif __linux__
  387. // Set file time
  388. // FIXME left off here
  389. // Restore mode
  390. #endif
  391. // Close file descriptor and report success.
  392. Closefproc(slot);
  393. Message("File saved",0);
  394. return 0;
  395. };