1 /*	$NetBSD: miniunz.c,v 1.1.1.1 2006/01/14 20:10:58 christos Exp $	*/
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 */
change_file_date(filename,dosdate,tmu_date)51 void 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 
mymkdir(dirname)92 int 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 
makedir(newdir)106 int 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 
do_banner()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 
do_help()157 void 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 
do_list(uf)170 int 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 
do_extract_currentfile(uf,popt_extract_without_path,popt_overwrite,password)243 int 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 
do_extract(uf,opt_extract_without_path,opt_overwrite,password)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_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 
do_extract_onefile(uf,filename,opt_extract_without_path,opt_overwrite,password)443 int 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 
main(argc,argv)466 int 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