miniunz.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. /*
  2. miniunz.c
  3. Version 1.1, February 14h, 2010
  4. sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
  5. Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
  6. Modifications of Unzip for Zip64
  7. Copyright (C) 2007-2008 Even Rouault
  8. Modifications for Zip64 support on both zip and unzip
  9. Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
  10. */
  11. #define unix
  12. #ifndef _WIN32
  13. #ifndef __USE_FILE_OFFSET64
  14. #define __USE_FILE_OFFSET64
  15. #endif
  16. #ifndef __USE_LARGEFILE64
  17. #define __USE_LARGEFILE64
  18. #endif
  19. #ifndef _LARGEFILE64_SOURCE
  20. #define _LARGEFILE64_SOURCE
  21. #endif
  22. #ifndef _FILE_OFFSET_BIT
  23. #define _FILE_OFFSET_BIT 64
  24. #endif
  25. #endif
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <time.h>
  30. #include <errno.h>
  31. #include <fcntl.h>
  32. #ifdef unix
  33. # include <unistd.h>
  34. # include <utime.h>
  35. #else
  36. # include <direct.h>
  37. # include <io.h>
  38. #endif
  39. #include "unzip.h"
  40. #define CASESENSITIVITY (0)
  41. #define WRITEBUFFERSIZE (8192)
  42. #define MAXFILENAME (256)
  43. #ifdef _WIN32
  44. #define USEWIN32IOAPI
  45. #include "iowin32.h"
  46. #endif
  47. /*
  48. mini unzip, demo of unzip package
  49. usage :
  50. Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir]
  51. list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT
  52. if it exists
  53. */
  54. /* change_file_date : change the date/time of a file
  55. filename : the filename of the file where date/time must be modified
  56. dosdate : the new date at the MSDos format (4 bytes)
  57. tmu_date : the SAME new date at the tm_unz format */
  58. void change_file_date(filename,dosdate,tmu_date)
  59. const char *filename;
  60. uLong dosdate;
  61. tm_unz tmu_date;
  62. {
  63. #ifdef _WIN32
  64. HANDLE hFile;
  65. FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
  66. hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE,
  67. 0,NULL,OPEN_EXISTING,0,NULL);
  68. GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
  69. DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
  70. LocalFileTimeToFileTime(&ftLocal,&ftm);
  71. SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
  72. CloseHandle(hFile);
  73. #else
  74. #ifdef unix
  75. struct utimbuf ut;
  76. struct tm newdate;
  77. newdate.tm_sec = tmu_date.tm_sec;
  78. newdate.tm_min=tmu_date.tm_min;
  79. newdate.tm_hour=tmu_date.tm_hour;
  80. newdate.tm_mday=tmu_date.tm_mday;
  81. newdate.tm_mon=tmu_date.tm_mon;
  82. if (tmu_date.tm_year > 1900)
  83. newdate.tm_year=tmu_date.tm_year - 1900;
  84. else
  85. newdate.tm_year=tmu_date.tm_year ;
  86. newdate.tm_isdst=-1;
  87. ut.actime=ut.modtime=mktime(&newdate);
  88. utime(filename,&ut);
  89. #endif
  90. #endif
  91. }
  92. /* mymkdir and change_file_date are not 100 % portable
  93. As I don't know well Unix, I wait feedback for the unix portion */
  94. int mymkdir(dirname)
  95. const char* dirname;
  96. {
  97. int ret=0;
  98. #ifdef _WIN32
  99. ret = _mkdir(dirname);
  100. #else
  101. #ifdef unix
  102. ret = mkdir (dirname,0775);
  103. #endif
  104. #endif
  105. return ret;
  106. }
  107. int makedir (newdir)
  108. char *newdir;
  109. {
  110. char *buffer ;
  111. char *p;
  112. int len = (int)strlen(newdir);
  113. if (len <= 0)
  114. return 0;
  115. buffer = (char*)malloc(len+1);
  116. if (buffer==NULL)
  117. {
  118. printf("Error allocating memory\n");
  119. return UNZ_INTERNALERROR;
  120. }
  121. strcpy(buffer,newdir);
  122. if (buffer[len-1] == '/') {
  123. buffer[len-1] = '\0';
  124. }
  125. if (mymkdir(buffer) == 0)
  126. {
  127. free(buffer);
  128. return 1;
  129. }
  130. p = buffer+1;
  131. while (1)
  132. {
  133. char hold;
  134. while(*p && *p != '\\' && *p != '/')
  135. p++;
  136. hold = *p;
  137. *p = 0;
  138. if ((mymkdir(buffer) == -1) && (errno == ENOENT))
  139. {
  140. printf("couldn't create directory %s\n",buffer);
  141. free(buffer);
  142. return 0;
  143. }
  144. if (hold == 0)
  145. break;
  146. *p++ = hold;
  147. }
  148. free(buffer);
  149. return 1;
  150. }
  151. void do_banner()
  152. {
  153. printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n");
  154. printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n");
  155. }
  156. void do_help()
  157. {
  158. printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \
  159. " -e Extract without pathname (junk paths)\n" \
  160. " -x Extract with pathname\n" \
  161. " -v list files\n" \
  162. " -l list files\n" \
  163. " -d directory to extract into\n" \
  164. " -o overwrite files without prompting\n" \
  165. " -p extract crypted file using password\n\n");
  166. }
  167. void Display64BitsSize(ZPOS64_T n, int size_char)
  168. {
  169. /* to avoid compatibility problem , we do here the conversion */
  170. char number[21];
  171. int offset=19;
  172. int pos_string = 19;
  173. number[20]=0;
  174. for (;;) {
  175. number[offset]=(char)((n%10)+'0');
  176. if (number[offset] != '0')
  177. pos_string=offset;
  178. n/=10;
  179. if (offset==0)
  180. break;
  181. offset--;
  182. }
  183. {
  184. int size_display_string = 19-pos_string;
  185. while (size_char > size_display_string)
  186. {
  187. size_char--;
  188. printf(" ");
  189. }
  190. }
  191. printf("%s",&number[pos_string]);
  192. }
  193. int do_list(uf)
  194. unzFile uf;
  195. {
  196. uLong i;
  197. unz_global_info64 gi;
  198. int err;
  199. err = unzGetGlobalInfo64(uf,&gi);
  200. if (err!=UNZ_OK)
  201. printf("error %d with zipfile in unzGetGlobalInfo \n",err);
  202. printf(" Length Method Size Ratio Date Time CRC-32 Name\n");
  203. printf(" ------ ------ ---- ----- ---- ---- ------ ----\n");
  204. for (i=0;i<gi.number_entry;i++)
  205. {
  206. char filename_inzip[256];
  207. unz_file_info64 file_info;
  208. uLong ratio=0;
  209. const char *string_method;
  210. char charCrypt=' ';
  211. err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
  212. if (err!=UNZ_OK)
  213. {
  214. printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
  215. break;
  216. }
  217. if (file_info.uncompressed_size>0)
  218. ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size);
  219. /* display a '*' if the file is crypted */
  220. if ((file_info.flag & 1) != 0)
  221. charCrypt='*';
  222. if (file_info.compression_method==0)
  223. string_method="Stored";
  224. else
  225. if (file_info.compression_method==Z_DEFLATED)
  226. {
  227. uInt iLevel=(uInt)((file_info.flag & 0x6)/2);
  228. if (iLevel==0)
  229. string_method="Defl:N";
  230. else if (iLevel==1)
  231. string_method="Defl:X";
  232. else if ((iLevel==2) || (iLevel==3))
  233. string_method="Defl:F"; /* 2:fast , 3 : extra fast*/
  234. }
  235. else
  236. if (file_info.compression_method==Z_BZIP2ED)
  237. {
  238. string_method="BZip2 ";
  239. }
  240. else
  241. string_method="Unkn. ";
  242. Display64BitsSize(file_info.uncompressed_size,7);
  243. printf(" %6s%c",string_method,charCrypt);
  244. Display64BitsSize(file_info.compressed_size,7);
  245. printf(" %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n",
  246. ratio,
  247. (uLong)file_info.tmu_date.tm_mon + 1,
  248. (uLong)file_info.tmu_date.tm_mday,
  249. (uLong)file_info.tmu_date.tm_year % 100,
  250. (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min,
  251. (uLong)file_info.crc,filename_inzip);
  252. if ((i+1)<gi.number_entry)
  253. {
  254. err = unzGoToNextFile(uf);
  255. if (err!=UNZ_OK)
  256. {
  257. printf("error %d with zipfile in unzGoToNextFile\n",err);
  258. break;
  259. }
  260. }
  261. }
  262. return 0;
  263. }
  264. int do_extract_currentfile(uf,popt_extract_without_path,popt_overwrite,password)
  265. unzFile uf;
  266. const int* popt_extract_without_path;
  267. int* popt_overwrite;
  268. const char* password;
  269. {
  270. char filename_inzip[256];
  271. char* filename_withoutpath;
  272. char* p;
  273. int err=UNZ_OK;
  274. FILE *fout=NULL;
  275. void* buf;
  276. uInt size_buf;
  277. unz_file_info64 file_info;
  278. uLong ratio=0;
  279. err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
  280. if (err!=UNZ_OK)
  281. {
  282. printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
  283. return err;
  284. }
  285. size_buf = WRITEBUFFERSIZE;
  286. buf = (void*)malloc(size_buf);
  287. if (buf==NULL)
  288. {
  289. printf("Error allocating memory\n");
  290. return UNZ_INTERNALERROR;
  291. }
  292. p = filename_withoutpath = filename_inzip;
  293. while ((*p) != '\0')
  294. {
  295. if (((*p)=='/') || ((*p)=='\\'))
  296. filename_withoutpath = p+1;
  297. p++;
  298. }
  299. if ((*filename_withoutpath)=='\0')
  300. {
  301. if ((*popt_extract_without_path)==0)
  302. {
  303. printf("creating directory: %s\n",filename_inzip);
  304. mymkdir(filename_inzip);
  305. }
  306. }
  307. else
  308. {
  309. const char* write_filename;
  310. int skip=0;
  311. if ((*popt_extract_without_path)==0)
  312. write_filename = filename_inzip;
  313. else
  314. write_filename = filename_withoutpath;
  315. err = unzOpenCurrentFilePassword(uf,password);
  316. if (err!=UNZ_OK)
  317. {
  318. printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err);
  319. }
  320. if (((*popt_overwrite)==0) && (err==UNZ_OK))
  321. {
  322. char rep=0;
  323. FILE* ftestexist;
  324. ftestexist = fopen64(write_filename,"rb");
  325. if (ftestexist!=NULL)
  326. {
  327. fclose(ftestexist);
  328. do
  329. {
  330. char answer[128];
  331. int ret;
  332. printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename);
  333. ret = scanf("%1s",answer);
  334. if (ret != 1)
  335. {
  336. exit(EXIT_FAILURE);
  337. }
  338. rep = answer[0] ;
  339. if ((rep>='a') && (rep<='z'))
  340. rep -= 0x20;
  341. }
  342. while ((rep!='Y') && (rep!='N') && (rep!='A'));
  343. }
  344. if (rep == 'N')
  345. skip = 1;
  346. if (rep == 'A')
  347. *popt_overwrite=1;
  348. }
  349. if ((skip==0) && (err==UNZ_OK))
  350. {
  351. fout=fopen64(write_filename,"wb");
  352. /* some zipfile don't contain directory alone before file */
  353. if ((fout==NULL) && ((*popt_extract_without_path)==0) &&
  354. (filename_withoutpath!=(char*)filename_inzip))
  355. {
  356. char c=*(filename_withoutpath-1);
  357. *(filename_withoutpath-1)='\0';
  358. makedir(write_filename);
  359. *(filename_withoutpath-1)=c;
  360. fout=fopen64(write_filename,"wb");
  361. }
  362. if (fout==NULL)
  363. {
  364. printf("error opening %s\n",write_filename);
  365. }
  366. }
  367. if (fout!=NULL)
  368. {
  369. printf(" extracting: %s\n",write_filename);
  370. do
  371. {
  372. err = unzReadCurrentFile(uf,buf,size_buf);
  373. if (err<0)
  374. {
  375. printf("error %d with zipfile in unzReadCurrentFile\n",err);
  376. break;
  377. }
  378. if (err>0)
  379. if (fwrite(buf,err,1,fout)!=1)
  380. {
  381. printf("error in writing extracted file\n");
  382. err=UNZ_ERRNO;
  383. break;
  384. }
  385. }
  386. while (err>0);
  387. if (fout)
  388. fclose(fout);
  389. if (err==0)
  390. change_file_date(write_filename,file_info.dosDate,
  391. file_info.tmu_date);
  392. }
  393. if (err==UNZ_OK)
  394. {
  395. err = unzCloseCurrentFile (uf);
  396. if (err!=UNZ_OK)
  397. {
  398. printf("error %d with zipfile in unzCloseCurrentFile\n",err);
  399. }
  400. }
  401. else
  402. unzCloseCurrentFile(uf); /* don't lose the error */
  403. }
  404. free(buf);
  405. return err;
  406. }
  407. int do_extract(uf,opt_extract_without_path,opt_overwrite,password)
  408. unzFile uf;
  409. int opt_extract_without_path;
  410. int opt_overwrite;
  411. const char* password;
  412. {
  413. uLong i;
  414. unz_global_info64 gi;
  415. int err;
  416. FILE* fout=NULL;
  417. err = unzGetGlobalInfo64(uf,&gi);
  418. if (err!=UNZ_OK)
  419. printf("error %d with zipfile in unzGetGlobalInfo \n",err);
  420. for (i=0;i<gi.number_entry;i++)
  421. {
  422. if (do_extract_currentfile(uf,&opt_extract_without_path,
  423. &opt_overwrite,
  424. password) != UNZ_OK)
  425. break;
  426. if ((i+1)<gi.number_entry)
  427. {
  428. err = unzGoToNextFile(uf);
  429. if (err!=UNZ_OK)
  430. {
  431. printf("error %d with zipfile in unzGoToNextFile\n",err);
  432. break;
  433. }
  434. }
  435. }
  436. return 0;
  437. }
  438. int do_extract_onefile(uf,filename,opt_extract_without_path,opt_overwrite,password)
  439. unzFile uf;
  440. const char* filename;
  441. int opt_extract_without_path;
  442. int opt_overwrite;
  443. const char* password;
  444. {
  445. int err = UNZ_OK;
  446. if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK)
  447. {
  448. printf("file %s not found in the zipfile\n",filename);
  449. return 2;
  450. }
  451. if (do_extract_currentfile(uf,&opt_extract_without_path,
  452. &opt_overwrite,
  453. password) == UNZ_OK)
  454. return 0;
  455. else
  456. return 1;
  457. }
  458. int main(argc,argv)
  459. int argc;
  460. char *argv[];
  461. {
  462. const char *zipfilename=NULL;
  463. const char *filename_to_extract=NULL;
  464. const char *password=NULL;
  465. char filename_try[MAXFILENAME+16] = "";
  466. int i;
  467. int ret_value=0;
  468. int opt_do_list=0;
  469. int opt_do_extract=1;
  470. int opt_do_extract_withoutpath=0;
  471. int opt_overwrite=0;
  472. int opt_extractdir=0;
  473. const char *dirname=NULL;
  474. unzFile uf=NULL;
  475. do_banner();
  476. if (argc==1)
  477. {
  478. do_help();
  479. return 0;
  480. }
  481. else
  482. {
  483. for (i=1;i<argc;i++)
  484. {
  485. if ((*argv[i])=='-')
  486. {
  487. const char *p=argv[i]+1;
  488. while ((*p)!='\0')
  489. {
  490. char c=*(p++);;
  491. if ((c=='l') || (c=='L'))
  492. opt_do_list = 1;
  493. if ((c=='v') || (c=='V'))
  494. opt_do_list = 1;
  495. if ((c=='x') || (c=='X'))
  496. opt_do_extract = 1;
  497. if ((c=='e') || (c=='E'))
  498. opt_do_extract = opt_do_extract_withoutpath = 1;
  499. if ((c=='o') || (c=='O'))
  500. opt_overwrite=1;
  501. if ((c=='d') || (c=='D'))
  502. {
  503. opt_extractdir=1;
  504. dirname=argv[i+1];
  505. }
  506. if (((c=='p') || (c=='P')) && (i+1<argc))
  507. {
  508. password=argv[i+1];
  509. i++;
  510. }
  511. }
  512. }
  513. else
  514. {
  515. if (zipfilename == NULL)
  516. zipfilename = argv[i];
  517. else if ((filename_to_extract==NULL) && (!opt_extractdir))
  518. filename_to_extract = argv[i] ;
  519. }
  520. }
  521. }
  522. if (zipfilename!=NULL)
  523. {
  524. # ifdef USEWIN32IOAPI
  525. zlib_filefunc64_def ffunc;
  526. # endif
  527. strncpy(filename_try, zipfilename,MAXFILENAME-1);
  528. /* strncpy doesnt append the trailing NULL, of the string is too long. */
  529. filename_try[ MAXFILENAME ] = '\0';
  530. # ifdef USEWIN32IOAPI
  531. fill_win32_filefunc64A(&ffunc);
  532. uf = unzOpen2_64(zipfilename,&ffunc);
  533. # else
  534. uf = unzOpen64(zipfilename);
  535. # endif
  536. if (uf==NULL)
  537. {
  538. strcat(filename_try,".zip");
  539. # ifdef USEWIN32IOAPI
  540. uf = unzOpen2_64(filename_try,&ffunc);
  541. # else
  542. uf = unzOpen64(filename_try);
  543. # endif
  544. }
  545. }
  546. if (uf==NULL)
  547. {
  548. printf("Cannot open %s or %s.zip\n",zipfilename,zipfilename);
  549. return 1;
  550. }
  551. printf("%s opened\n",filename_try);
  552. if (opt_do_list==1)
  553. ret_value = do_list(uf);
  554. else if (opt_do_extract==1)
  555. {
  556. #ifdef _WIN32
  557. if (opt_extractdir && _chdir(dirname))
  558. #else
  559. if (opt_extractdir && chdir(dirname))
  560. #endif
  561. {
  562. printf("Error changing into %s, aborting\n", dirname);
  563. exit(-1);
  564. }
  565. if (filename_to_extract == NULL)
  566. ret_value = do_extract(uf, opt_do_extract_withoutpath, opt_overwrite, password);
  567. else
  568. ret_value = do_extract_onefile(uf, filename_to_extract, opt_do_extract_withoutpath, opt_overwrite, password);
  569. }
  570. unzClose(uf);
  571. return ret_value;
  572. }