(C) Relatively high density file backups on paper. Cross-platform CLI port of Ollydbg's Paperback from Windows and Borland C.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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. };