1/* 2 minizip.c 3 Version 1.1, February 14h, 2010 4 sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) 5 6 Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) 7 8 Modifications of Unzip for Zip64 9 Copyright (C) 2007-2008 Even Rouault 10 11 Modifications for Zip64 support on both zip and unzip 12 Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) 13*/ 14 15 16#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) 17 #ifndef __USE_FILE_OFFSET64 18 #define __USE_FILE_OFFSET64 19 #endif 20 #ifndef __USE_LARGEFILE64 21 #define __USE_LARGEFILE64 22 #endif 23 #ifndef _LARGEFILE64_SOURCE 24 #define _LARGEFILE64_SOURCE 25 #endif 26 #ifndef _FILE_OFFSET_BIT 27 #define _FILE_OFFSET_BIT 64 28 #endif 29#endif 30 31#ifdef __APPLE__ 32// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions 33#define FOPEN_FUNC(filename, mode) fopen(filename, mode) 34#define FTELLO_FUNC(stream) ftello(stream) 35#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) 36#else 37#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) 38#define FTELLO_FUNC(stream) ftello64(stream) 39#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) 40#endif 41 42 43 44#include <stdio.h> 45#include <stdlib.h> 46#include <string.h> 47#include <time.h> 48#include <errno.h> 49#include <fcntl.h> 50 51#ifdef _WIN32 52# include <direct.h> 53# include <io.h> 54#else 55# include <unistd.h> 56# include <utime.h> 57# include <sys/types.h> 58# include <sys/stat.h> 59#endif 60 61#include "zip.h" 62 63#ifdef _WIN32 64 #define USEWIN32IOAPI 65 #include "iowin32.h" 66#endif 67 68 69 70#define WRITEBUFFERSIZE (16384) 71#define MAXFILENAME (256) 72 73#ifdef _WIN32 74static int filetime(f, tmzip, dt) 75 const char *f; /* name of file to get info on */ 76 tm_zip *tmzip; /* return value: access, modific. and creation times */ 77 uLong *dt; /* dostime */ 78{ 79 int ret = 0; 80 { 81 FILETIME ftLocal; 82 HANDLE hFind; 83 WIN32_FIND_DATAA ff32; 84 85 hFind = FindFirstFileA(f,&ff32); 86 if (hFind != INVALID_HANDLE_VALUE) 87 { 88 FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); 89 FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); 90 FindClose(hFind); 91 ret = 1; 92 } 93 } 94 return ret; 95} 96#else 97#if defined(unix) || defined(__APPLE__) 98static int filetime(f, tmzip, dt) 99 const char *f; /* name of file to get info on */ 100 tm_zip *tmzip; /* return value: access, modific. and creation times */ 101 uLong *dt; /* dostime */ 102{ 103 (void)dt; 104 int ret=0; 105 struct stat s; /* results of stat() */ 106 struct tm* filedate; 107 time_t tm_t=0; 108 109 if (strcmp(f,"-")!=0) 110 { 111 char name[MAXFILENAME+1]; 112 size_t len = strlen(f); 113 if (len > MAXFILENAME) 114 len = MAXFILENAME; 115 116 strncpy(name, f,MAXFILENAME-1); 117 /* strncpy doesnt append the trailing NULL, of the string is too long. */ 118 name[ MAXFILENAME ] = '\0'; 119 120 if (name[len - 1] == '/') 121 name[len - 1] = '\0'; 122 /* not all systems allow stat'ing a file with / appended */ 123 if (stat(name,&s)==0) 124 { 125 tm_t = s.st_mtime; 126 ret = 1; 127 } 128 } 129 filedate = localtime(&tm_t); 130 131 tmzip->tm_sec = filedate->tm_sec; 132 tmzip->tm_min = filedate->tm_min; 133 tmzip->tm_hour = filedate->tm_hour; 134 tmzip->tm_mday = filedate->tm_mday; 135 tmzip->tm_mon = filedate->tm_mon ; 136 tmzip->tm_year = filedate->tm_year; 137 138 return ret; 139} 140#else 141uLong filetime(f, tmzip, dt) 142 const char *f; /* name of file to get info on */ 143 tm_zip *tmzip; /* return value: access, modific. and creation times */ 144 uLong *dt; /* dostime */ 145{ 146 return 0; 147} 148#endif 149#endif 150 151 152 153 154static int check_exist_file(filename) 155 const char* filename; 156{ 157 FILE* ftestexist; 158 int ret = 1; 159 ftestexist = FOPEN_FUNC(filename,"rb"); 160 if (ftestexist==NULL) 161 ret = 0; 162 else 163 fclose(ftestexist); 164 return ret; 165} 166 167static void do_banner() 168{ 169 printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n"); 170 printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n"); 171} 172 173static void do_help() 174{ 175 printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ 176 " -o Overwrite existing file.zip\n" \ 177 " -a Append to existing file.zip\n" \ 178 " -0 Store only\n" \ 179 " -1 Compress faster\n" \ 180 " -9 Compress better\n\n" \ 181 " -j exclude path. store only the file name.\n\n"); 182} 183 184/* calculate the CRC32 of a file, 185 because to encrypt a file, we need known the CRC32 of the file before */ 186static int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) 187{ 188 unsigned long calculate_crc=0; 189 int err=ZIP_OK; 190 FILE * fin = FOPEN_FUNC(filenameinzip,"rb"); 191 192 unsigned long size_read = 0; 193 unsigned long total_read = 0; 194 if (fin==NULL) 195 { 196 err = ZIP_ERRNO; 197 } 198 199 if (err == ZIP_OK) 200 do 201 { 202 err = ZIP_OK; 203 size_read = fread(buf,1,size_buf,fin); 204 if (size_read < size_buf) 205 if (feof(fin)==0) 206 { 207 printf("error in reading %s\n",filenameinzip); 208 err = ZIP_ERRNO; 209 } 210 211 if (size_read>0) 212 calculate_crc = crc32_z(calculate_crc,buf,size_read); 213 total_read += size_read; 214 215 } while ((err == ZIP_OK) && (size_read>0)); 216 217 if (fin) 218 fclose(fin); 219 220 *result_crc=calculate_crc; 221 printf("file %s crc %lx\n", filenameinzip, calculate_crc); 222 return err; 223} 224 225static int isLargeFile(const char* filename) 226{ 227 int largeFile = 0; 228 ZPOS64_T pos = 0; 229 FILE* pFile = FOPEN_FUNC(filename, "rb"); 230 231 if(pFile != NULL) 232 { 233 FSEEKO_FUNC(pFile, 0, SEEK_END); 234 pos = (ZPOS64_T)FTELLO_FUNC(pFile); 235 236 printf("File : %s is %lld bytes\n", filename, pos); 237 238 if(pos >= 0xffffffff) 239 largeFile = 1; 240 241 fclose(pFile); 242 } 243 244 return largeFile; 245} 246 247int main(argc,argv) 248 int argc; 249 char *argv[]; 250{ 251 int i; 252 int opt_overwrite=0; 253 int opt_compress_level=Z_DEFAULT_COMPRESSION; 254 int opt_exclude_path=0; 255 int zipfilenamearg = 0; 256 char filename_try[MAXFILENAME+16]; 257 int zipok; 258 int err=0; 259 size_t size_buf=0; 260 void* buf=NULL; 261 const char* password=NULL; 262 263 264 do_banner(); 265 if (argc==1) 266 { 267 do_help(); 268 return 0; 269 } 270 else 271 { 272 for (i=1;i<argc;i++) 273 { 274 if ((*argv[i])=='-') 275 { 276 const char *p=argv[i]+1; 277 278 while ((*p)!='\0') 279 { 280 char c=*(p++);; 281 if ((c=='o') || (c=='O')) 282 opt_overwrite = 1; 283 if ((c=='a') || (c=='A')) 284 opt_overwrite = 2; 285 if ((c>='0') && (c<='9')) 286 opt_compress_level = c-'0'; 287 if ((c=='j') || (c=='J')) 288 opt_exclude_path = 1; 289 290 if (((c=='p') || (c=='P')) && (i+1<argc)) 291 { 292 password=argv[i+1]; 293 i++; 294 } 295 } 296 } 297 else 298 { 299 if (zipfilenamearg == 0) 300 { 301 zipfilenamearg = i ; 302 } 303 } 304 } 305 } 306 307 size_buf = WRITEBUFFERSIZE; 308 buf = (void*)malloc(size_buf); 309 if (buf==NULL) 310 { 311 printf("Error allocating memory\n"); 312 return ZIP_INTERNALERROR; 313 } 314 315 if (zipfilenamearg==0) 316 { 317 zipok=0; 318 } 319 else 320 { 321 int i,len; 322 int dot_found=0; 323 324 zipok = 1 ; 325 strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME-1); 326 /* strncpy doesnt append the trailing NULL, of the string is too long. */ 327 filename_try[ MAXFILENAME ] = '\0'; 328 329 len=(int)strlen(filename_try); 330 for (i=0;i<len;i++) 331 if (filename_try[i]=='.') 332 dot_found=1; 333 334 if (dot_found==0) 335 strcat(filename_try,".zip"); 336 337 if (opt_overwrite==2) 338 { 339 /* if the file don't exist, we not append file */ 340 if (check_exist_file(filename_try)==0) 341 opt_overwrite=1; 342 } 343 else 344 if (opt_overwrite==0) 345 if (check_exist_file(filename_try)!=0) 346 { 347 char rep=0; 348 do 349 { 350 char answer[128]; 351 int ret; 352 printf("The file %s exists. Overwrite ? [y]es, [n]o, [a]ppend : ",filename_try); 353 ret = scanf("%1s",answer); 354 if (ret != 1) 355 { 356 exit(EXIT_FAILURE); 357 } 358 rep = answer[0] ; 359 if ((rep>='a') && (rep<='z')) 360 rep -= 0x20; 361 } 362 while ((rep!='Y') && (rep!='N') && (rep!='A')); 363 if (rep=='N') 364 zipok = 0; 365 if (rep=='A') 366 opt_overwrite = 2; 367 } 368 } 369 370 if (zipok==1) 371 { 372 zipFile zf; 373 int errclose; 374# ifdef USEWIN32IOAPI 375 zlib_filefunc64_def ffunc; 376 fill_win32_filefunc64A(&ffunc); 377 zf = zipOpen2_64(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); 378# else 379 zf = zipOpen64(filename_try,(opt_overwrite==2) ? 2 : 0); 380# endif 381 382 if (zf == NULL) 383 { 384 printf("error opening %s\n",filename_try); 385 err= ZIP_ERRNO; 386 } 387 else 388 printf("creating %s\n",filename_try); 389 390 for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++) 391 { 392 if (!((((*(argv[i]))=='-') || ((*(argv[i]))=='/')) && 393 ((argv[i][1]=='o') || (argv[i][1]=='O') || 394 (argv[i][1]=='a') || (argv[i][1]=='A') || 395 (argv[i][1]=='p') || (argv[i][1]=='P') || 396 ((argv[i][1]>='0') || (argv[i][1]<='9'))) && 397 (strlen(argv[i]) == 2))) 398 { 399 FILE * fin; 400 size_t size_read; 401 const char* filenameinzip = argv[i]; 402 const char *savefilenameinzip; 403 zip_fileinfo zi; 404 unsigned long crcFile=0; 405 int zip64 = 0; 406 407 zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = 408 zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; 409 zi.dosDate = 0; 410 zi.internal_fa = 0; 411 zi.external_fa = 0; 412 filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); 413 414/* 415 err = zipOpenNewFileInZip(zf,filenameinzip,&zi, 416 NULL,0,NULL,0,NULL / * comment * /, 417 (opt_compress_level != 0) ? Z_DEFLATED : 0, 418 opt_compress_level); 419*/ 420 if ((password != NULL) && (err==ZIP_OK)) 421 err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); 422 423 zip64 = isLargeFile(filenameinzip); 424 425 /* The path name saved, should not include a leading slash. */ 426 /*if it did, windows/xp and dynazip couldn't read the zip file. */ 427 savefilenameinzip = filenameinzip; 428 while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) 429 { 430 savefilenameinzip++; 431 } 432 433 /*should the zip file contain any path at all?*/ 434 if( opt_exclude_path ) 435 { 436 const char *tmpptr; 437 const char *lastslash = 0; 438 for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) 439 { 440 if( *tmpptr == '\\' || *tmpptr == '/') 441 { 442 lastslash = tmpptr; 443 } 444 } 445 if( lastslash != NULL ) 446 { 447 savefilenameinzip = lastslash+1; // base filename follows last slash. 448 } 449 } 450 451 /**/ 452 err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, 453 NULL,0,NULL,0,NULL /* comment*/, 454 (opt_compress_level != 0) ? Z_DEFLATED : 0, 455 opt_compress_level,0, 456 /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ 457 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, 458 password,crcFile, zip64); 459 460 if (err != ZIP_OK) 461 printf("error in opening %s in zipfile\n",filenameinzip); 462 else 463 { 464 fin = FOPEN_FUNC(filenameinzip,"rb"); 465 if (fin==NULL) 466 { 467 err=ZIP_ERRNO; 468 printf("error in opening %s for reading\n",filenameinzip); 469 } 470 } 471 472 if (err == ZIP_OK) 473 do 474 { 475 err = ZIP_OK; 476 size_read = fread(buf,1,size_buf,fin); 477 if (size_read < size_buf) 478 if (feof(fin)==0) 479 { 480 printf("error in reading %s\n",filenameinzip); 481 err = ZIP_ERRNO; 482 } 483 484 if (size_read>0) 485 { 486 err = zipWriteInFileInZip (zf,buf,(unsigned)size_read); 487 if (err<0) 488 { 489 printf("error in writing %s in the zipfile\n", 490 filenameinzip); 491 } 492 493 } 494 } while ((err == ZIP_OK) && (size_read>0)); 495 496 if (fin) 497 fclose(fin); 498 499 if (err<0) 500 err=ZIP_ERRNO; 501 else 502 { 503 err = zipCloseFileInZip(zf); 504 if (err!=ZIP_OK) 505 printf("error in closing %s in the zipfile\n", 506 filenameinzip); 507 } 508 } 509 } 510 errclose = zipClose(zf,NULL); 511 if (errclose != ZIP_OK) 512 printf("error in closing %s\n",filename_try); 513 } 514 else 515 { 516 do_help(); 517 } 518 519 free(buf); 520 return 0; 521} 522