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