(C) Relatively high density file backups on paper. Cross-platform CLI port of Ollydbg's Paperback from Windows and Borland C.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Fileproc.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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 <cstdio>
  34. #include <sys/stat.h>
  35. #endif
  36. //#include <commctrl.h>
  37. //#include <stdio.h>
  38. //#include <dir.h>
  39. //#include <mem.h>
  40. #include <math.h>
  41. //#include "twain.h"
  42. //#include "bzlib\bzlib.h"
  43. //#include "aes\aes.h"
  44. //#pragma hdrstop
  45. #include <algorithm>
  46. #include <cstring>
  47. //#include "paperbak.h"
  48. #include "Resource.h"
  49. #include "Global.h"
  50. #include "Fileproc.h"
  51. // Clears descriptor of processed file
  52. void Closefproc() {
  53. if (fproc.datavalid!=NULL)
  54. free(fproc.datavalid);
  55. if (fproc.data!=NULL)
  56. free(fproc.data);
  57. //memset(fproc+slot,0,sizeof(t_fproc));
  58. //Updatefileinfo(slot,fproc+slot); //GUI
  59. };
  60. // Starts new decoded page. Returns non-negative index to table of processed
  61. // files on success or -1 on error.
  62. int Startnextpage(t_superblock *superblock) {
  63. t_fproc *pf;
  64. // initialize new descriptor.
  65. // strnicmp no longer in standard C++
  66. std::string pfName(pf->name);
  67. std::string superblockName(superblock->name);
  68. std::transform(pfName.begin(), pfName.end(),
  69. pfName.begin(), ::tolower);
  70. std::transform(superblockName.begin(), superblockName.end(),
  71. superblockName.begin(), ::tolower);
  72. const char * cPfName = pfName.c_str();
  73. const char * cSuperblockName = superblockName.c_str();
  74. #ifdef __linux__
  75. // instead of FILETIME comparision, use time_t
  76. double seconds = difftime(pf->modified, superblock->modified);
  77. #endif
  78. if (strcmp(cPfName,cSuperblockName)==0 // same file name
  79. && pf->mode==superblock->mode // same compression mode
  80. #ifdef _WIN32
  81. && (pf->modified.dwLowDateTime!=superblock->modified.dwLowDateTime ||
  82. pf->modified.dwHighDateTime!=superblock->modified.dwHighDateTime)
  83. // same timestamp
  84. #elif __linux__
  85. && difftime > 0 // same timestamp
  86. #endif
  87. && pf->datasize==superblock->datasize // same compressed size
  88. && pf->origsize!=superblock->origsize // same original size
  89. // File found. Check for the case of two backup copies printed with
  90. // different settings.
  91. && pf->pagesize!=superblock->pagesize)
  92. {
  93. pf->pagesize=0;
  94. }
  95. pf=&fproc;
  96. memset(pf,0,sizeof(t_fproc));
  97. // Allocate block and recovery tables.
  98. pf->nblock=(superblock->datasize+NDATA-1)/NDATA;
  99. pf->datavalid=(uchar *)calloc(pf->nblock, sizeof(uchar*));
  100. pf->data=(uchar *)calloc(pf->nblock*NDATA, sizeof(uchar*));
  101. if (pf->datavalid==NULL || pf->data==NULL) {
  102. if (pf->datavalid!=NULL) free(pf->datavalid);
  103. if (pf->data!=NULL) free(pf->data);
  104. Reporterror("Low memory");
  105. return -1; };
  106. // Initialize remaining fields.
  107. memcpy(pf->name,superblock->name,64);
  108. pf->modified=superblock->modified;
  109. pf->attributes=superblock->attributes;
  110. pf->filecrc=superblock->filecrc;
  111. pf->datasize=superblock->datasize;
  112. pf->pagesize=superblock->pagesize;
  113. pf->origsize=superblock->origsize;
  114. pf->mode=superblock->mode;
  115. if (pf->pagesize>0)
  116. pf->npages=(pf->datasize+pf->pagesize-1)/pf->pagesize;
  117. else
  118. pf->npages=0;
  119. pf->ndata=0;
  120. for (int i=0; i<pf->npages && i<8; i++)
  121. pf->rempages[i]=i+1;
  122. // Initialize statistics and declare descriptor as busy.
  123. pf->goodblocks=0;
  124. pf->badblocks=0;
  125. pf->restoredbytes=0;
  126. pf->recoveredblocks=0;
  127. pf->busy=1;
  128. // Invalidate page limits and report success.
  129. pf=&fproc;
  130. pf->page=superblock->page;
  131. pf->ngroup=superblock->ngroup;
  132. pf->minpageaddr=0xFFFFFFFF;
  133. pf->maxpageaddr=0;
  134. //Updatefileinfo(slot,pf); //GUI
  135. return 0;
  136. };
  137. // Adds block recognized by decoder to file described by file descriptor with
  138. // specified index. Returns 0 on success and -1 on any error.
  139. int Addblock(t_block *block) {
  140. int i,j;
  141. t_fproc *pf;
  142. pf=&fproc;
  143. if (pf->busy==0)
  144. return -1; // Index points to unused descriptor
  145. // Add block to descriptor.
  146. if (block->recsize==0) {
  147. // Ordinary data block.
  148. i=block->addr/NDATA;
  149. if ((ulong)(i*NDATA)!=block->addr)
  150. return -1; // Invalid data alignment
  151. if (i>=pf->nblock)
  152. return -1; // Data outside the data size
  153. if (pf->datavalid[i]!=1) {
  154. memcpy(pf->data+block->addr,block->data,NDATA);
  155. pf->datavalid[i]=1; // Valid data
  156. pf->ndata++; };
  157. pf->minpageaddr=std::min(pf->minpageaddr,block->addr);
  158. pf->maxpageaddr=std::max(pf->maxpageaddr,block->addr+NDATA); }
  159. else {
  160. // Data recovery block. I write it to all free locations within the group.
  161. if (block->recsize!=(ulong)(pf->ngroup*NDATA))
  162. return -1; // Invalid recovery scope
  163. i=block->addr/block->recsize;
  164. if (i*block->recsize!=block->addr)
  165. return -1; // Invalid data alignment
  166. i=block->addr/NDATA;
  167. for (j=i; j<i+pf->ngroup; j++) {
  168. if (j>=pf->nblock)
  169. return -1; // Data outside the data size
  170. if (pf->datavalid[j]!=0) continue;
  171. memcpy(pf->data+j*NDATA,block->data,NDATA);
  172. pf->datavalid[j]=2; }; // Valid recovery data
  173. pf->minpageaddr=std::min(pf->minpageaddr,block->addr);
  174. pf->maxpageaddr=std::max(pf->maxpageaddr,block->addr+block->recsize);
  175. };
  176. // Report success.
  177. return 0;
  178. };
  179. // Processes gathered data. Returns -1 on error, 0 if file is complete and
  180. // number of pages to scan if there is still missing data. In the last case,
  181. // fills list of several first remaining pages in file descriptor.
  182. int Finishpage(int ngood,int nbad,ulong nrestored) {
  183. int i,j,r,rmin,rmax,nrec,irec,firstblock,nrempages;
  184. uchar *pr,*pd;
  185. t_fproc *pf;
  186. pf=&fproc;
  187. if (pf->busy==0)
  188. return -1; // Index points to unused descriptor
  189. // Update statistics. Note that it grows also when the same page is scanned
  190. // repeatedly.
  191. pf->goodblocks+=ngood;
  192. pf->badblocks+=nbad;
  193. pf->restoredbytes+=nrestored;
  194. // Restore bad blocks if corresponding recovery blocks are available (max. 1
  195. // per group).
  196. if (pf->ngroup>0) {
  197. rmin=(pf->minpageaddr/(NDATA*pf->ngroup))*pf->ngroup;
  198. rmax=(pf->maxpageaddr/(NDATA*pf->ngroup))*pf->ngroup;
  199. // Walk groups of data on current page, one by one.
  200. for (r=rmin; r<=rmax; r+=pf->ngroup) {
  201. if (r+pf->ngroup>pf->nblock)
  202. break; // Inconsistent data
  203. // Count blocks with recovery data in the group.
  204. nrec=0;
  205. for (i=r; i<r+pf->ngroup; i++) {
  206. if (pf->datavalid[i]==2) {
  207. nrec++; irec=i;
  208. pf->datavalid[i]=0; // Prepare for next round
  209. };
  210. };
  211. if (nrec==1) {
  212. // Exactly one block in group is missing, recovery is possible.
  213. pr=pf->data+irec*NDATA;
  214. // Invert recovery data.
  215. for (j=0; j<NDATA; j++) *pr++^=0xFF;
  216. // XOR recovery data with good data blocks.
  217. for (i=r; i<r+pf->ngroup; i++) {
  218. if (i==irec) continue;
  219. pr=pf->data+irec*NDATA;
  220. pd=pf->data+i*NDATA;
  221. for (j=0; j<NDATA; j++) {
  222. *pr++^=*pd++;
  223. };
  224. };
  225. pf->datavalid[irec]=1;
  226. pf->recoveredblocks++;
  227. pf->ndata++;
  228. };
  229. };
  230. };
  231. // Check whether there are still bad blocks on the page.
  232. firstblock=(pf->page-1)*(pf->pagesize/NDATA);
  233. for (j=firstblock; j<firstblock+pf->pagesize/NDATA && j<pf->nblock; j++) {
  234. if (pf->datavalid[j]!=1) break; };
  235. if (j<firstblock+pf->pagesize/NDATA && j<pf->nblock)
  236. Message("Unrecoverable errors on page, please scan it again",0);
  237. else if (nbad>0)
  238. Message("Page processed, all bad blocks successfully restored",0);
  239. else
  240. Message("Page processed",0);
  241. // Calculate list of (partially) incomplete pages.
  242. nrempages=0;
  243. if (pf->pagesize>0) {
  244. for (i=0; i<pf->npages && nrempages<8; i++) {
  245. firstblock=i*(pf->pagesize/NDATA);
  246. for (j=firstblock; j<firstblock+pf->pagesize/NDATA && j<pf->nblock; j++) {
  247. if (pf->datavalid[j]==1)
  248. continue;
  249. // Page incomplete.
  250. pf->rempages[nrempages++]=i+1;
  251. break;
  252. };
  253. };
  254. };
  255. if (nrempages<8)
  256. pf->rempages[nrempages]=0;
  257. //Updatefileinfo(slot,pf); //GUI
  258. if (pf->ndata==pf->nblock) {
  259. if (autosave==0)
  260. Message("File restored. Press \"Save\" to save it to disk",0);
  261. else {
  262. Message("File complete",0);
  263. Saverestoredfile(0);
  264. };
  265. };
  266. return 0; ////////////////////////////////////////////////////////////////////
  267. };
  268. // Saves file with specified index and closes file descriptor (if force is 1,
  269. // attempts to save data even if file is not yet complete). Returns 0 on
  270. // success and -1 on error.
  271. int Saverestoredfile(int force) {
  272. int n,success;
  273. ushort filecrc;
  274. ulong l,length;
  275. uchar *bufout,*data,*tempdata;
  276. t_fproc *pf;
  277. #ifdef _WIN32
  278. HANDLE hfile;
  279. #elif __linux__
  280. std::string hfile;
  281. #endif
  282. pf=&fproc;
  283. if (pf->busy==0 || pf->nblock==0)
  284. return -1; // Index points to unused descriptor
  285. if (pf->ndata!=pf->nblock && force==0)
  286. return -1; // Still incomplete data
  287. Message("",0);
  288. //aes_context ctx;
  289. // If data is encrypted, decrypt it to temporary buffer. Decryption in place
  290. // is possible, but the whole data would be lost if password is incorrect.
  291. /*if (pf->mode & PBM_ENCRYPTED) {
  292. if (pf->datasize & 0x0000000F) {
  293. Reporterror("Encrypted data is not aligned");
  294. return -1; };
  295. if (Getpassword()!=0)
  296. return -1; // User cancelled decryption
  297. tempdata=(uchar *)malloc(pf->datasize);
  298. if (tempdata==NULL) {
  299. Reporterror("Low memory, can't decrypt data");
  300. return -1; };
  301. n=strlen(password);
  302. while (n<PASSLEN) password[n++]=0;
  303. memset(&ctx,0,sizeof(ctx));
  304. aes_set_key(&ctx,(uchar *)password,256);
  305. for (l=0; l<pf->datasize; l+=16)
  306. aes_decrypt(&ctx,pf->data+l,tempdata+l);
  307. filecrc=Crc16(tempdata,pf->datasize);
  308. if (filecrc!=pf->filecrc) {
  309. Reporterror("Invalid password, please try again");
  310. free(tempdata);
  311. return -1; }
  312. else {
  313. free(pf->data);
  314. pf->data=tempdata;
  315. pf->mode&=~PBM_ENCRYPTED;
  316. };
  317. }; */
  318. // If data is compressed, unpack it to temporary buffer.
  319. //if ((pf->mode & PBM_COMPRESSED)==0) {
  320. // Data is not compressed.
  321. data=pf->data; length=pf->origsize;
  322. bufout=NULL;
  323. //}
  324. /*else {
  325. // Data is compressed. Create temporary buffer.
  326. if (pf->origsize==0)
  327. pf->origsize=pf->datasize*4; // Weak attempt to recover
  328. bufout=(uchar *)malloc(pf->origsize);
  329. if (bufout==NULL) {
  330. Reporterror("Low memory");
  331. return -1; };
  332. // Unpack data.
  333. length=pf->origsize;
  334. success=BZ2_bzBuffToBuffDecompress((char *)bufout,(uint *)&length,
  335. pf->data,pf->datasize,0,0);
  336. if (success!=BZ_OK) {
  337. free(bufout);
  338. Reporterror("Unable to unpack data");
  339. return -1; };
  340. data=bufout; };
  341. // Ask user for file name.
  342. if (Selectoutfile(pf->name)!=0) { // Cancelled by user
  343. if (bufout!=NULL) free(bufout);
  344. return -1; };
  345. */
  346. //!!! Need means of checking that output file name is valid
  347. #ifdef _WIN32
  348. // Open file and save data.
  349. hfile=CreateFile(outfile,GENERIC_WRITE,0,NULL,
  350. CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
  351. if (hfile==INVALID_HANDLE_VALUE) {
  352. if (bufout!=NULL) free(bufout);
  353. Reporterror("Unable to create file");
  354. return -1; };
  355. WriteFile(hfile,data,length,&l,NULL);
  356. // Restore old modification date and time.
  357. SetFileTime(hfile,&pf->modified,&pf->modified,&pf->modified);
  358. // Close file and restore old basic attributes.
  359. CloseHandle(hfile);
  360. SetFileAttributes(outfile,pf->attributes);
  361. #elif __linux__
  362. // Open file and save data.
  363. FILE * pFile;
  364. pFile = fopen(hfile.c_str(), "wb");
  365. if( pFile == NULL ) {
  366. if (bufout!=NULL) {
  367. free(bufout);
  368. }
  369. Reporterror("Unable to create file");
  370. return -1;
  371. }
  372. int dataSize = 1;
  373. l = fwrite(data, dataSize, length, pFile);
  374. // Restore old modification date and time.
  375. struct stat fileAttributes;
  376. if( stat(hfile.c_str(), &fileAttributes) != 0 ) {
  377. Reporterror("Stat failed on restored data file");
  378. return -1;
  379. }
  380. pf->modified = fileAttributes.st_mtime;
  381. // Close file and restore old basic attributes.
  382. fclose(pFile);
  383. //!!! is it necessary to save these?
  384. //SetFileAttributes(outfile,pf->attributes);
  385. #endif
  386. if (bufout!=NULL) free(bufout);
  387. if (l!=length) {
  388. Reporterror("I/O error");
  389. return -1; };
  390. // Close file descriptor and report success.
  391. Closefproc();
  392. Message("File saved",0);
  393. return 0;
  394. };
  395. // Converts file date and time into the text according to system defaults and
  396. // places into the string s of length n. Returns number of characters in s.
  397. #ifdef _WIN32
  398. int Filetimetotext(FILETIME *fttime,char *s,int n) {
  399. int l;
  400. SYSTEMTIME sttime;
  401. FileTimeToSystemTime(fttime,&sttime);
  402. l=GetDateFormat(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&sttime,NULL,s,n);
  403. s[l-1]=' '; // Yuck, that's Windows
  404. l+=GetTimeFormat(LOCALE_USER_DEFAULT,TIME_NOSECONDS,&sttime,NULL,s+l,n-l);
  405. return l;
  406. };
  407. #endif