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