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 74 uLong filetime(f, tmzip, dt) 75 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 #ifdef unix || __APPLE__ 98 uLong filetime(f, tmzip, dt) 99 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 int ret=0; 104 struct stat s; /* results of stat() */ 105 struct tm* filedate; 106 time_t tm_t=0; 107 108 if (strcmp(f,"-")!=0) 109 { 110 char name[MAXFILENAME+1]; 111 int len = strlen(f); 112 if (len > MAXFILENAME) 113 len = MAXFILENAME; 114 115 strncpy(name, f,MAXFILENAME-1); 116 /* strncpy doesnt append the trailing NULL, of the string is too long. */ 117 name[ MAXFILENAME ] = '\0'; 118 119 if (name[len - 1] == '/') 120 name[len - 1] = '\0'; 121 /* not all systems allow stat'ing a file with / appended */ 122 if (stat(name,&s)==0) 123 { 124 tm_t = s.st_mtime; 125 ret = 1; 126 } 127 } 128 filedate = localtime(&tm_t); 129 130 tmzip->tm_sec = filedate->tm_sec; 131 tmzip->tm_min = filedate->tm_min; 132 tmzip->tm_hour = filedate->tm_hour; 133 tmzip->tm_mday = filedate->tm_mday; 134 tmzip->tm_mon = filedate->tm_mon ; 135 tmzip->tm_year = filedate->tm_year; 136 137 return ret; 138 } 139 #else 140 uLong filetime(f, tmzip, dt) 141 char *f; /* name of file to get info on */ 142 tm_zip *tmzip; /* return value: access, modific. and creation times */ 143 uLong *dt; /* dostime */ 144 { 145 return 0; 146 } 147 #endif 148 #endif 149 150 151 152 153 int check_exist_file(filename) 154 const char* filename; 155 { 156 FILE* ftestexist; 157 int ret = 1; 158 ftestexist = FOPEN_FUNC(filename,"rb"); 159 if (ftestexist==NULL) 160 ret = 0; 161 else 162 fclose(ftestexist); 163 return ret; 164 } 165 166 void do_banner() 167 { 168 printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n"); 169 printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n"); 170 } 171 172 void do_help() 173 { 174 printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ 175 " -o Overwrite existing file.zip\n" \ 176 " -a Append to existing file.zip\n" \ 177 " -0 Store only\n" \ 178 " -1 Compress faster\n" \ 179 " -9 Compress better\n\n" \ 180 " -j exclude path. store only the file name.\n\n"); 181 } 182 183 /* calculate the CRC32 of a file, 184 because to encrypt a file, we need known the CRC32 of the file before */ 185 int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) 186 { 187 unsigned long calculate_crc=0; 188 int err=ZIP_OK; 189 FILE * fin = FOPEN_FUNC(filenameinzip,"rb"); 190 191 unsigned long size_read = 0; 192 unsigned long total_read = 0; 193 if (fin==NULL) 194 { 195 err = ZIP_ERRNO; 196 } 197 198 if (err == ZIP_OK) 199 do 200 { 201 err = ZIP_OK; 202 size_read = (int)fread(buf,1,size_buf,fin); 203 if (size_read < size_buf) 204 if (feof(fin)==0) 205 { 206 printf("error in reading %s\n",filenameinzip); 207 err = ZIP_ERRNO; 208 } 209 210 if (size_read>0) 211 calculate_crc = crc32(calculate_crc,buf,size_read); 212 total_read += size_read; 213 214 } while ((err == ZIP_OK) && (size_read>0)); 215 216 if (fin) 217 fclose(fin); 218 219 *result_crc=calculate_crc; 220 printf("file %s crc %lx\n", filenameinzip, calculate_crc); 221 return err; 222 } 223 224 int isLargeFile(const char* filename) 225 { 226 int largeFile = 0; 227 ZPOS64_T pos = 0; 228 FILE* pFile = FOPEN_FUNC(filename, "rb"); 229 230 if(pFile != NULL) 231 { 232 int n = FSEEKO_FUNC(pFile, 0, SEEK_END); 233 pos = FTELLO_FUNC(pFile); 234 235 printf("File : %s is %lld bytes\n", filename, pos); 236 237 if(pos >= 0xffffffff) 238 largeFile = 1; 239 240 fclose(pFile); 241 } 242 243 return largeFile; 244 } 245 246 int main(argc,argv) 247 int argc; 248 char *argv[]; 249 { 250 int i; 251 int opt_overwrite=0; 252 int opt_compress_level=Z_DEFAULT_COMPRESSION; 253 int opt_exclude_path=0; 254 int zipfilenamearg = 0; 255 char filename_try[MAXFILENAME+16]; 256 int zipok; 257 int err=0; 258 int size_buf=0; 259 void* buf=NULL; 260 const char* password=NULL; 261 262 263 do_banner(); 264 if (argc==1) 265 { 266 do_help(); 267 return 0; 268 } 269 else 270 { 271 for (i=1;i<argc;i++) 272 { 273 if ((*argv[i])=='-') 274 { 275 const char *p=argv[i]+1; 276 277 while ((*p)!='\0') 278 { 279 char c=*(p++);; 280 if ((c=='o') || (c=='O')) 281 opt_overwrite = 1; 282 if ((c=='a') || (c=='A')) 283 opt_overwrite = 2; 284 if ((c>='0') && (c<='9')) 285 opt_compress_level = c-'0'; 286 if ((c=='j') || (c=='J')) 287 opt_exclude_path = 1; 288 289 if (((c=='p') || (c=='P')) && (i+1<argc)) 290 { 291 password=argv[i+1]; 292 i++; 293 } 294 } 295 } 296 else 297 { 298 if (zipfilenamearg == 0) 299 { 300 zipfilenamearg = i ; 301 } 302 } 303 } 304 } 305 306 size_buf = WRITEBUFFERSIZE; 307 buf = (void*)malloc(size_buf); 308 if (buf==NULL) 309 { 310 printf("Error allocating memory\n"); 311 return ZIP_INTERNALERROR; 312 } 313 314 if (zipfilenamearg==0) 315 { 316 zipok=0; 317 } 318 else 319 { 320 int i,len; 321 int dot_found=0; 322 323 zipok = 1 ; 324 strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME-1); 325 /* strncpy doesnt append the trailing NULL, of the string is too long. */ 326 filename_try[ MAXFILENAME ] = '\0'; 327 328 len=(int)strlen(filename_try); 329 for (i=0;i<len;i++) 330 if (filename_try[i]=='.') 331 dot_found=1; 332 333 if (dot_found==0) 334 strcat(filename_try,".zip"); 335 336 if (opt_overwrite==2) 337 { 338 /* if the file don't exist, we not append file */ 339 if (check_exist_file(filename_try)==0) 340 opt_overwrite=1; 341 } 342 else 343 if (opt_overwrite==0) 344 if (check_exist_file(filename_try)!=0) 345 { 346 char rep=0; 347 do 348 { 349 char answer[128]; 350 int ret; 351 printf("The file %s exists. Overwrite ? [y]es, [n]o, [a]ppend : ",filename_try); 352 ret = scanf("%1s",answer); 353 if (ret != 1) 354 { 355 exit(EXIT_FAILURE); 356 } 357 rep = answer[0] ; 358 if ((rep>='a') && (rep<='z')) 359 rep -= 0x20; 360 } 361 while ((rep!='Y') && (rep!='N') && (rep!='A')); 362 if (rep=='N') 363 zipok = 0; 364 if (rep=='A') 365 opt_overwrite = 2; 366 } 367 } 368 369 if (zipok==1) 370 { 371 zipFile zf; 372 int errclose; 373 # ifdef USEWIN32IOAPI 374 zlib_filefunc64_def ffunc; 375 fill_win32_filefunc64A(&ffunc); 376 zf = zipOpen2_64(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); 377 # else 378 zf = zipOpen64(filename_try,(opt_overwrite==2) ? 2 : 0); 379 # endif 380 381 if (zf == NULL) 382 { 383 printf("error opening %s\n",filename_try); 384 err= ZIP_ERRNO; 385 } 386 else 387 printf("creating %s\n",filename_try); 388 389 for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++) 390 { 391 if (!((((*(argv[i]))=='-') || ((*(argv[i]))=='/')) && 392 ((argv[i][1]=='o') || (argv[i][1]=='O') || 393 (argv[i][1]=='a') || (argv[i][1]=='A') || 394 (argv[i][1]=='p') || (argv[i][1]=='P') || 395 ((argv[i][1]>='0') || (argv[i][1]<='9'))) && 396 (strlen(argv[i]) == 2))) 397 { 398 FILE * fin; 399 int size_read; 400 const char* filenameinzip = argv[i]; 401 const char *savefilenameinzip; 402 zip_fileinfo zi; 403 unsigned long crcFile=0; 404 int zip64 = 0; 405 406 zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = 407 zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; 408 zi.dosDate = 0; 409 zi.internal_fa = 0; 410 zi.external_fa = 0; 411 filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); 412 413 /* 414 err = zipOpenNewFileInZip(zf,filenameinzip,&zi, 415 NULL,0,NULL,0,NULL / * comment * /, 416 (opt_compress_level != 0) ? Z_DEFLATED : 0, 417 opt_compress_level); 418 */ 419 if ((password != NULL) && (err==ZIP_OK)) 420 err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); 421 422 zip64 = isLargeFile(filenameinzip); 423 424 /* The path name saved, should not include a leading slash. */ 425 /*if it did, windows/xp and dynazip couldn't read the zip file. */ 426 savefilenameinzip = filenameinzip; 427 while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) 428 { 429 savefilenameinzip++; 430 } 431 432 /*should the zip file contain any path at all?*/ 433 if( opt_exclude_path ) 434 { 435 const char *tmpptr; 436 const char *lastslash = 0; 437 for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) 438 { 439 if( *tmpptr == '\\' || *tmpptr == '/') 440 { 441 lastslash = tmpptr; 442 } 443 } 444 if( lastslash != NULL ) 445 { 446 savefilenameinzip = lastslash+1; // base filename follows last slash. 447 } 448 } 449 450 /**/ 451 err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, 452 NULL,0,NULL,0,NULL /* comment*/, 453 (opt_compress_level != 0) ? Z_DEFLATED : 0, 454 opt_compress_level,0, 455 /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ 456 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, 457 password,crcFile, zip64); 458 459 if (err != ZIP_OK) 460 printf("error in opening %s in zipfile\n",filenameinzip); 461 else 462 { 463 fin = FOPEN_FUNC(filenameinzip,"rb"); 464 if (fin==NULL) 465 { 466 err=ZIP_ERRNO; 467 printf("error in opening %s for reading\n",filenameinzip); 468 } 469 } 470 471 if (err == ZIP_OK) 472 do 473 { 474 err = ZIP_OK; 475 size_read = (int)fread(buf,1,size_buf,fin); 476 if (size_read < size_buf) 477 if (feof(fin)==0) 478 { 479 printf("error in reading %s\n",filenameinzip); 480 err = ZIP_ERRNO; 481 } 482 483 if (size_read>0) 484 { 485 err = zipWriteInFileInZip (zf,buf,size_read); 486 if (err<0) 487 { 488 printf("error in writing %s in the zipfile\n", 489 filenameinzip); 490 } 491 492 } 493 } while ((err == ZIP_OK) && (size_read>0)); 494 495 if (fin) 496 fclose(fin); 497 498 if (err<0) 499 err=ZIP_ERRNO; 500 else 501 { 502 err = zipCloseFileInZip(zf); 503 if (err!=ZIP_OK) 504 printf("error in closing %s in the zipfile\n", 505 filenameinzip); 506 } 507 } 508 } 509 errclose = zipClose(zf,NULL); 510 if (errclose != ZIP_OK) 511 printf("error in closing %s\n",filename_try); 512 } 513 else 514 { 515 do_help(); 516 } 517 518 free(buf); 519 return 0; 520 } 521