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