1 /******************************************************************************
2  * HPTZIP --- wrapper of zlib library for manipulating with zip archivs
3  ******************************************************************************
4  * hptzip.c : functions for pack and unpack files from zip archive
5  *
6  * by Max Chernogor <mihz@mail.ru>, 2:464/108@fidonet
7  *
8  *****************************************************************************
9  * $Id$
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <time.h>
16 
17 #include "zip.h"
18 #include "unzip.h"
19 
20 #include <errno.h>
21 #include <fcntl.h>
22 
23 #ifdef unix
24 # include <unistd.h>
25 # include <utime.h>
26 #else
27 # include <direct.h>
28 # include <io.h>
29 #endif
30 #ifdef WIN32
31 #include <huskylib/unused.h>
32 #define USEWIN32IOAPI
33 #include "iowin32.h"
34 #endif
35 
36 #define DLLEXPORT
37 #include <huskylib/huskyext.h>
38 #include "hptzip.h"
39 
40 #ifdef ZLIBDL
41 #include "hptzipdl.h"
42 crc32_func          *dl_crc32 = NULL;
43 get_crc_table_func  *dl_get_crc_table = NULL;
44 inflateInit2__func  *dl_inflateInit2_ = NULL;
45 inflate_func        *dl_inflate = NULL;
46 inflateEnd_func     *dl_inflateEnd = NULL;
47 deflateInit2__func  *dl_deflateInit2_ = NULL;
48 deflate_func        *dl_deflate = NULL;
49 deflateEnd_func     *dl_deflateEnd = NULL;
50 #endif
51 
52 #define CASESENSITIVITY (0)
53 #define WRITEBUFFERSIZE (16384)
54 #define MAXFILENAME (256)
55 
56 char destdir[MAXFILENAME];
57 size_t dsLen;
58 
59 
60 
61 /* change_file_date : change the date/time of a file
62     filename : the filename of the file where date/time must be modified
63     dosdate : the new date at the MSDos format (4 bytes)
64     tmu_date : the SAME new date at the tm_unz format */
change_file_date(const char * filename,uLong dosdate,tm_unz tmu_date)65 void change_file_date(const char *filename,
66                       uLong dosdate,
67                       tm_unz tmu_date)
68 {
69 #ifdef WIN32
70   HANDLE hFile;
71   FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
72 
73   unused(tmu_date);
74 
75   hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE,
76                       0,NULL,OPEN_EXISTING,0,NULL);
77   GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
78   DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
79   LocalFileTimeToFileTime(&ftLocal,&ftm);
80   SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
81   CloseHandle(hFile);
82 #else
83 #ifdef unix
84   struct utimbuf ut;
85   struct tm newdate;
86   newdate.tm_sec = tmu_date.tm_sec;
87   newdate.tm_min=tmu_date.tm_min;
88   newdate.tm_hour=tmu_date.tm_hour;
89   newdate.tm_mday=tmu_date.tm_mday;
90   newdate.tm_mon=tmu_date.tm_mon;
91   if (tmu_date.tm_year > 1900)
92       newdate.tm_year=tmu_date.tm_year - 1900;
93   else
94       newdate.tm_year=tmu_date.tm_year ;
95   newdate.tm_isdst=-1;
96 
97   ut.actime=ut.modtime=mktime(&newdate);
98   utime(filename,&ut);
99 #endif
100 #endif
101 }
102 
103 #ifdef WIN32
filetime(char * f,tm_zip * tmzip,uLong * dt)104 uLong filetime(char *f,         /* name of file to get info on */
105                tm_zip *tmzip,   /* return value: access, modific. and creation times */
106                uLong *dt)       /* dostime */
107 {
108   int ret = 0;
109 
110   unused(tmzip);
111 
112   {
113       FILETIME ftLocal;
114       HANDLE hFind;
115       WIN32_FIND_DATA  ff32;
116 
117       hFind = FindFirstFile(f,&ff32);
118       if (hFind != INVALID_HANDLE_VALUE)
119       {
120         FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
121         FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
122         FindClose(hFind);
123         ret = 1;
124       }
125   }
126   return ret;
127 }
128 #else
129 #ifdef unix
filetime(f,tmzip,dt)130 uLong filetime(f, tmzip, dt)
131     char *f;                /* name of file to get info on */
132     tm_zip *tmzip;             /* return value: access, modific. and creation times */
133     uLong *dt;             /* dostime */
134 {
135   int ret=0;
136   struct stat s;        /* results of stat() */
137   struct tm* filedate;
138   time_t tm_t=0;
139 
140   if (strcmp(f,"-")!=0)
141   {
142     char name[MAXFILENAME+1];
143     int len = strlen(f);
144 
145     strncpy(name, f,MAXFILENAME-1);
146     /* strncpy doesnt append the trailing NULL, of the string is too long. */
147     name[ MAXFILENAME ] = '\0';
148 
149     if (name[len - 1] == '/')
150       name[len - 1] = '\0';
151     /* not all systems allow stat'ing a file with / appended */
152     if (stat(name,&s)==0)
153     {
154       tm_t = s.st_mtime;
155       ret = 1;
156     }
157   }
158   filedate = localtime(&tm_t);
159 
160   tmzip->tm_sec  = filedate->tm_sec;
161   tmzip->tm_min  = filedate->tm_min;
162   tmzip->tm_hour = filedate->tm_hour;
163   tmzip->tm_mday = filedate->tm_mday;
164   tmzip->tm_mon  = filedate->tm_mon ;
165   tmzip->tm_year = filedate->tm_year;
166 
167   return ret;
168 }
169 #else
filetime(f,tmzip,dt)170 uLong filetime(f, tmzip, dt)
171     char *f;                /* name of file to get info on */
172     tm_zip *tmzip;             /* return value: access, modific. and creation times */
173     uLong *dt;             /* dostime */
174 {
175     return 0;
176 }
177 #endif
178 #endif
179 
180 
181 
182 
check_exist_file(const char * filename)183 int check_exist_file(const char* filename)
184 {
185     FILE* ftestexist;
186     int ret = 1;
187     ftestexist = fopen(filename,"rb");
188     if (ftestexist==NULL)
189         ret = 0;
190     else
191         fclose(ftestexist);
192     return ret;
193 }
194 
195 /* calculate the CRC32 of a file,
196    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)197 int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc)
198 {
199    unsigned long calculate_crc=0;
200    int err=ZIP_OK;
201    FILE * fin = fopen(filenameinzip,"rb");
202    unsigned long size_read = 0;
203    unsigned long total_read = 0;
204    if (fin==NULL)
205    {
206        err = ZIP_ERRNO;
207    }
208 
209     if (err == ZIP_OK)
210         do
211         {
212             err = ZIP_OK;
213             size_read = (int)fread(buf,1,size_buf,fin);
214             if (size_read < size_buf)
215                 if (feof(fin)==0)
216             {
217                 printf("error in reading %s\n",filenameinzip);
218                 err = ZIP_ERRNO;
219             }
220 
221             if (size_read>0)
222                 calculate_crc = crc32(calculate_crc, (const Bytef *)buf, size_read);
223             total_read += size_read;
224 
225         } while ((err == ZIP_OK) && (size_read>0));
226 
227     if (fin)
228         fclose(fin);
229 
230     *result_crc=calculate_crc;
231     printf("file %s crc %lx\n",filenameinzip,calculate_crc);
232     return err;
233 }
234 
235 
236 
do_extract_currentfile(unzFile uf,const int * popt_extract_without_path,int * popt_overwrite,const char * password)237 int do_extract_currentfile(unzFile uf,
238                            const int* popt_extract_without_path,
239                            int* popt_overwrite,
240                            const char* password)
241 {
242     char filename_inzip[MAXFILENAME];
243     char* filename_withoutpath;
244     char* p;
245     int err=UNZ_OK;
246     FILE *fout=NULL;
247     void* buf;
248     uInt size_buf;
249 
250     unz_file_info file_info;
251 #if 0
252     uLong ratio=0;
253 #endif
254     err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
255 
256     if (err!=UNZ_OK)
257     {
258         printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
259         return err;
260     }
261 
262     size_buf = WRITEBUFFERSIZE;
263     buf = (void*)malloc(size_buf);
264     if (buf==NULL)
265     {
266         printf("Error allocating memory\n");
267         return UNZ_INTERNALERROR;
268     }
269 
270     p = filename_withoutpath = filename_inzip;
271     while ((*p) != '\0')
272     {
273         if (((*p)=='/') || ((*p)=='\\'))
274             filename_withoutpath = p+1;
275         p++;
276     }
277 
278     if ((*filename_withoutpath)=='\0')
279     {
280         if ((*popt_extract_without_path)==0)
281         {
282             /* printf("creating directory: %s\n",filename_inzip);
283             mymkdir(filename_inzip); */
284         }
285     }
286     else
287     {
288         char* write_filename;
289         int skip=0;
290 
291         if ((*popt_extract_without_path)==1)
292         {
293             destdir[dsLen] = '\0';
294             strcat(destdir,filename_withoutpath);
295             write_filename = destdir;
296         }
297         else
298         {
299             write_filename = filename_inzip;
300         }
301 
302         err = unzOpenCurrentFilePassword(uf,password);
303         if (err!=UNZ_OK)
304         {
305             printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err);
306         }
307 
308         if (((*popt_overwrite)==0) && (err==UNZ_OK))
309         {
310             char rep=0;
311             FILE* ftestexist;
312             ftestexist = fopen(write_filename,"rb");
313             if (ftestexist!=NULL)
314             {
315                 fclose(ftestexist);
316                 do
317                 {
318                     char answer[128];
319                     printf("The file %s exist. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename);
320                     scanf("%1s",answer);
321                     rep = answer[0] ;
322                     if ((rep>='a') && (rep<='z'))
323                         rep -= 0x20;
324                 }
325                 while ((rep!='Y') && (rep!='N') && (rep!='A'));
326             }
327 
328             if (rep == 'N')
329                 skip = 1;
330 
331             if (rep == 'A')
332                 *popt_overwrite=1;
333         }
334 
335         if ((skip==0) && (err==UNZ_OK))
336         {
337             fout=fopen(write_filename,"wb");
338 
339             /* some zipfile don't contain directory alone before file */
340             if ((fout==NULL) && ((*popt_extract_without_path)==0) &&
341                                 (filename_withoutpath!=(char*)filename_inzip))
342             {
343                 /* char c=*(filename_withoutpath-1);
344                 *(filename_withoutpath-1)='\0';
345                 makedir(write_filename);
346                 *(filename_withoutpath-1)=c;
347                 fout=fopen(write_filename,"wb"); */
348             }
349 
350             if (fout==NULL)
351             {
352                 printf("error opening %s\n",write_filename);
353             }
354         }
355 
356         if (fout!=NULL)
357         {
358             /*printf(" extracting: %s\n",write_filename);*/
359 
360             do
361             {
362                 err = unzReadCurrentFile(uf,buf,size_buf);
363                 if (err<0)
364                 {
365                     printf("error %d with zipfile in unzReadCurrentFile\n",err);
366                     break;
367                 }
368                 if (err>0)
369                     if (fwrite(buf,err,1,fout)!=1)
370                     {
371                         printf("error in writing extracted file\n");
372                         err=UNZ_ERRNO;
373                         break;
374                     }
375             }
376             while (err>0);
377             if (fout)
378                     fclose(fout);
379 
380             if (err==0)
381                 change_file_date(write_filename,file_info.dosDate,
382                                  file_info.tmu_date);
383         }
384 
385         if (err==UNZ_OK)
386         {
387             err = unzCloseCurrentFile (uf);
388             if (err!=UNZ_OK)
389             {
390                 printf("error %d with zipfile in unzCloseCurrentFile\n",err);
391             }
392         }
393         else
394             unzCloseCurrentFile(uf); /* don't lose the error */
395     }
396 
397     free(buf);
398     return err;
399 }
400 
401 
do_extract(unzFile uf,int opt_extract_without_path,int opt_overwrite,const char * password)402 int do_extract(unzFile uf,
403                int opt_extract_without_path,
404                int opt_overwrite,
405                const char* password)
406 {
407     uLong i;
408     unz_global_info gi;
409     int err;
410 #if 0
411     FILE* fout=NULL;
412 #endif
413     err = unzGetGlobalInfo (uf,&gi);
414     if (err!=UNZ_OK)
415         printf("error %d with zipfile in unzGetGlobalInfo \n",err);
416 
417     for (i=0;i<gi.number_entry;i++)
418     {
419         if (do_extract_currentfile(uf,&opt_extract_without_path,
420                                       &opt_overwrite,
421                                       password) != UNZ_OK)
422             break;
423 
424         if ((i+1)<gi.number_entry)
425         {
426             err = unzGoToNextFile(uf);
427             if (err!=UNZ_OK)
428             {
429                 printf("error %d with zipfile in unzGoToNextFile\n",err);
430                 break;
431             }
432         }
433     }
434 
435     return 0;
436 }
437 
do_extract_onefile(unzFile uf,const char * filename,int opt_extract_without_path,int opt_overwrite,const char * password)438 int do_extract_onefile(unzFile uf,
439                        const char* filename,
440                        int opt_extract_without_path,
441                        int opt_overwrite,
442                        const char* password)
443 {
444 #if 0
445     int err = UNZ_OK;
446 #endif
447     if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK)
448     {
449         /*printf("file %s not found in the zipfile\n",filename);*/
450         return 2;
451     }
452 
453     if (do_extract_currentfile(uf,&opt_extract_without_path,
454                                       &opt_overwrite,
455                                       password) == UNZ_OK)
456         return 0;
457     else
458         return 1;
459 }
460 
461 
UnPackWithZlib(char * zipfilename,char * filename_to_extract,char * dest_dir)462 int UnPackWithZlib(char * zipfilename, char * filename_to_extract, char * dest_dir)
463 {
464     unzFile uf=NULL;
465     int nRet  = 0;
466 
467     if (zipfilename!=NULL)
468     {
469 
470         #ifdef USEWIN32IOAPI
471         zlib_filefunc_def ffunc;
472         #endif
473 
474         #ifdef USEWIN32IOAPI
475         fill_win32_filefunc(&ffunc);
476         uf = unzOpen2(zipfilename,&ffunc);
477         #else
478         uf = unzOpen(zipfilename);
479         #endif
480     }
481 
482     if (uf==NULL)
483     {
484         printf("Cannot open %s\n",zipfilename);
485         return 1;
486     }
487 
488     /*printf("%s opened\n",zipfilename);*/
489 
490     strcpy(destdir,dest_dir);
491     dsLen = strlen( dest_dir );
492 
493     if (filename_to_extract == NULL)
494         nRet = do_extract(uf,1,1,NULL);
495     else
496         nRet = do_extract_onefile(uf,filename_to_extract,1,1,NULL);
497 
498     unzCloseCurrentFile(uf);
499     unzClose(uf);
500     return nRet;
501 }
502 
PackWithZlib(char * zipfilenamearg,char * filenameinzip)503 int PackWithZlib(char * zipfilenamearg, char * filenameinzip)
504 {
505 
506     int opt_overwrite=2;
507     int opt_compress_level=Z_DEFAULT_COMPRESSION;
508     int err=0;
509     int size_buf=0;
510     void* buf=NULL;
511     const char* password=NULL;
512 
513     size_buf = WRITEBUFFERSIZE;
514 
515     buf = (void*)malloc(size_buf);
516     if (buf==NULL)
517     {
518         printf("Error allocating memory\n");
519         return ZIP_INTERNALERROR;
520     }
521 
522 
523     /* if the file don't exist, we not append file */
524     if (check_exist_file(zipfilenamearg)==0)
525         opt_overwrite=1;
526 
527     if(filenameinzip)
528     {
529         char *basename = strrchr(filenameinzip,PATH_DELIM);
530         zipFile zf;
531 #ifdef USEWIN32IOAPI
532         zlib_filefunc_def ffunc;
533         fill_win32_filefunc(&ffunc);
534         zf = zipOpen2(zipfilenamearg,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc);
535 #else
536         zf = zipOpen(zipfilenamearg,(opt_overwrite==2) ? 2 : 0);
537 #endif
538 
539         if (zf == NULL)
540         {
541             printf("error opening %s\n",zipfilenamearg);
542             err= ZIP_ERRNO;
543         }
544         else
545 /*
546             printf("creating %s\n",zipfilenamearg);
547 */
548         {
549             FILE * fin = NULL;
550             int size_read;
551             zip_fileinfo zi;
552             unsigned long crcFile=0;
553 
554             zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
555                 zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
556             zi.dosDate = 0;
557             zi.internal_fa = 0;
558             zi.external_fa = 0;
559             filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
560 
561             if ((password != NULL) && (err==ZIP_OK))
562                 err = getFileCrc(filenameinzip,buf,size_buf,&crcFile);
563 
564             basename++; /* skip pathdelim */
565             err = zipOpenNewFileInZip3(zf,basename,&zi,
566                 NULL,0,NULL,0,NULL /* comment*/,
567                 (opt_compress_level != 0) ? Z_DEFLATED : 0,
568                 opt_compress_level,0,
569                 /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
570                 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
571                 password,crcFile);
572 
573             if (err != ZIP_OK)
574                 printf("error in opening %s in zipfile\n",basename);
575             else
576             {
577                 fin = fopen(filenameinzip,"rb");
578                 if (fin==NULL)
579                 {
580                     err=ZIP_ERRNO;
581                     printf("error in opening %s for reading\n",filenameinzip);
582                 }
583             }
584 
585             if (err == ZIP_OK)
586             {
587                 do
588                 {
589                     err = ZIP_OK;
590                     size_read = (int)fread(buf,1,size_buf,fin);
591                     if (size_read < size_buf)
592                         if (feof(fin)==0)
593                         {
594                             printf("error in reading %s\n",filenameinzip);
595                             err = ZIP_ERRNO;
596                         }
597 
598                         if (size_read>0)
599                         {
600                             err = zipWriteInFileInZip (zf,buf,size_read);
601                             if (err<0)
602                             {
603                                 printf("error in writing %s in the zipfile\n",
604                                     basename);
605                             }
606 
607                         }
608                 } while ((err == ZIP_OK) && (size_read>0));
609             }
610             if (fin)
611                 fclose(fin);
612 
613             if (err<0)
614                 err=ZIP_ERRNO;
615             else
616             {
617                 err = zipCloseFileInZip(zf);
618                 if (err!=ZIP_OK)
619                     printf("error in closing %s in the zipfile\n",
620                     basename);
621             }
622         }
623         if (zipClose(zf,NULL) != ZIP_OK)
624             printf("error in closing %s\n",zipfilenamearg);
625     }
626 
627     free(buf);
628     return err;
629 }
630 
631 /* initialize zlib */
init_hptzip(void)632 int init_hptzip(void) {
633 #ifndef ZLIBDL
634   /* always successful if not dynamic loading */
635   return 1;
636 #elif defined(WIN32)
637   HINSTANCE hl = LoadLibrary("zlib.dll");
638   if (hl) {
639     dl_crc32 = (void*)GetProcAddress(hl, "crc32");
640     dl_get_crc_table = (void*)GetProcAddress(hl, "get_crc_table");
641     dl_inflateInit2_ = (void*)GetProcAddress(hl, "inflateInit2_");
642     dl_inflate = (void*)GetProcAddress(hl, "inflate");
643     dl_inflateEnd = (void*)GetProcAddress(hl, "inflateEnd");
644     dl_deflateInit2_ = (void*)GetProcAddress(hl, "deflateInit2_");
645     dl_deflate = (void*)GetProcAddress(hl, "deflate");
646     dl_deflateEnd = (void*)GetProcAddress(hl, "deflateEnd");
647   }
648   return dl_crc32 && dl_get_crc_table
649          && dl_inflateInit2_ && dl_inflate && dl_inflateEnd
650          && dl_deflateInit2_ && dl_deflate && dl_deflateEnd;
651 #else
652 #  error "ZLIBDL is not supported for this system"
653 #endif
654 }
655