Fossil SCM

fossil-scm / compat / zlib / contrib / minizip / miniunz.c
Blame History Raw 648 lines
1
/*
2
miniunz.c
3
sample part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
4
5
Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
6
7
Modifications of Unzip for Zip64
8
Copyright (C) 2007-2008 Even Rouault
9
10
Modifications for Zip64 support on both zip and unzip
11
Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
12
*/
13
14
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
15
#ifndef __USE_FILE_OFFSET64
16
#define __USE_FILE_OFFSET64
17
#endif
18
#ifndef __USE_LARGEFILE64
19
#define __USE_LARGEFILE64
20
#endif
21
#ifndef _LARGEFILE64_SOURCE
22
#define _LARGEFILE64_SOURCE
23
#endif
24
#ifndef _FILE_OFFSET_BIT
25
#define _FILE_OFFSET_BIT 64
26
#endif
27
#endif
28
29
#if defined(__APPLE__) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64)
30
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
31
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
32
#define FTELLO_FUNC(stream) ftello(stream)
33
#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
34
#else
35
#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
36
#define FTELLO_FUNC(stream) ftello64(stream)
37
#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
38
#endif
39
40
41
#ifndef _CRT_SECURE_NO_WARNINGS
42
# define _CRT_SECURE_NO_WARNINGS
43
#endif
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
#include <sys/stat.h>
51
52
#ifdef _WIN32
53
# include <direct.h>
54
# include <io.h>
55
#else
56
# include <unistd.h>
57
# include <utime.h>
58
#endif
59
60
61
#include "unzip.h"
62
63
#define CASESENSITIVITY (0)
64
#define WRITEBUFFERSIZE (8192)
65
#define MAXFILENAME (256)
66
67
#ifdef _WIN32
68
#define USEWIN32IOAPI
69
#include "iowin32.h"
70
#endif
71
/*
72
mini unzip, demo of unzip package
73
74
usage :
75
Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir]
76
77
list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT
78
if it exists
79
*/
80
81
82
/* change_file_date : change the date/time of a file
83
filename : the filename of the file where date/time must be modified
84
dosdate : the new date at the MSDOS format (4 bytes)
85
tmu_date : the SAME new date at the tm_unz format */
86
static void change_file_date(const char *filename, uLong dosdate, tm_unz tmu_date) {
87
#ifdef _WIN32
88
(void)tmu_date;
89
HANDLE hFile;
90
FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
91
92
hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE,
93
0,NULL,OPEN_EXISTING,0,NULL);
94
GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
95
DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
96
LocalFileTimeToFileTime(&ftLocal,&ftm);
97
SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
98
CloseHandle(hFile);
99
#elif defined(__unix__) || defined(__unix) || defined(__APPLE__)
100
(void)dosdate;
101
struct utimbuf ut;
102
struct tm newdate;
103
newdate.tm_sec = tmu_date.tm_sec;
104
newdate.tm_min=tmu_date.tm_min;
105
newdate.tm_hour=tmu_date.tm_hour;
106
newdate.tm_mday=tmu_date.tm_mday;
107
newdate.tm_mon=tmu_date.tm_mon;
108
if (tmu_date.tm_year > 1900)
109
newdate.tm_year=tmu_date.tm_year - 1900;
110
else
111
newdate.tm_year=tmu_date.tm_year ;
112
newdate.tm_isdst=-1;
113
114
ut.actime=ut.modtime=mktime(&newdate);
115
utime(filename,&ut);
116
#else
117
(void)filename;
118
(void)dosdate;
119
(void)tmu_date;
120
#endif
121
}
122
123
124
/* mymkdir and change_file_date are not 100 % portable
125
As I don't know well Unix, I wait feedback for the unix portion */
126
127
static int mymkdir(const char* dirname) {
128
int ret=0;
129
#ifdef _WIN32
130
ret = _mkdir(dirname);
131
#elif defined(__unix__) || defined(__unix) || defined(__APPLE__)
132
ret = mkdir (dirname,0775);
133
#else
134
(void)dirname;
135
#endif
136
return ret;
137
}
138
139
static int makedir(const char *newdir) {
140
char *buffer ;
141
char *p;
142
size_t len = strlen(newdir);
143
144
if (len == 0)
145
return 0;
146
147
buffer = (char*)malloc(len+1);
148
if (buffer==NULL)
149
{
150
printf("Error allocating memory\n");
151
return UNZ_INTERNALERROR;
152
}
153
memcpy(buffer,newdir,len+1);
154
155
if (buffer[len-1] == '/') {
156
buffer[len-1] = '\0';
157
}
158
if (mymkdir(buffer) == 0)
159
{
160
free(buffer);
161
return 1;
162
}
163
164
p = buffer+1;
165
while (1)
166
{
167
char hold;
168
169
while(*p && *p != '\\' && *p != '/')
170
p++;
171
hold = *p;
172
*p = 0;
173
if ((mymkdir(buffer) == -1) && (errno == ENOENT))
174
{
175
printf("couldn't create directory %s\n",buffer);
176
free(buffer);
177
return 0;
178
}
179
if (hold == 0)
180
break;
181
*p++ = hold;
182
}
183
free(buffer);
184
return 1;
185
}
186
187
static void do_banner(void) {
188
printf("MiniUnz 1.1, demo of zLib + Unz package written by Gilles Vollant\n");
189
printf("more info at https://www.winimage.com/zLibDll/unzip.html\n\n");
190
}
191
192
static void do_help(void) {
193
printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \
194
" -e Extract without pathname (junk paths)\n" \
195
" -x Extract with pathname\n" \
196
" -v list files\n" \
197
" -l list files\n" \
198
" -d directory to extract into\n" \
199
" -o overwrite files without prompting\n" \
200
" -p extract encrypted file using password\n\n");
201
}
202
203
static void Display64BitsSize(ZPOS64_T n, int size_char) {
204
/* to avoid compatibility problem , we do here the conversion */
205
char number[21];
206
int offset=19;
207
int pos_string = 19;
208
number[20]=0;
209
for (;;) {
210
number[offset]=(char)((n%10)+'0');
211
if (number[offset] != '0')
212
pos_string=offset;
213
n/=10;
214
if (offset==0)
215
break;
216
offset--;
217
}
218
{
219
int size_display_string = 19-pos_string;
220
while (size_char > size_display_string)
221
{
222
size_char--;
223
printf(" ");
224
}
225
}
226
227
printf("%s",&number[pos_string]);
228
}
229
230
static int do_list(unzFile uf) {
231
uLong i;
232
unz_global_info64 gi;
233
int err;
234
235
err = unzGetGlobalInfo64(uf,&gi);
236
if (err!=UNZ_OK)
237
printf("error %d with zipfile in unzGetGlobalInfo\n",err);
238
printf(" Length Method Size Ratio Date Time CRC-32 Name\n");
239
printf(" ------ ------ ---- ----- ---- ---- ------ ----\n");
240
for (i=0;i<gi.number_entry;i++)
241
{
242
char filename_inzip[65536+1];
243
unz_file_info64 file_info;
244
uLong ratio=0;
245
const char *string_method = "";
246
char charCrypt=' ';
247
err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
248
if (err!=UNZ_OK)
249
{
250
printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
251
break;
252
}
253
if (file_info.uncompressed_size>0)
254
ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size);
255
256
/* display a '*' if the file is encrypted */
257
if ((file_info.flag & 1) != 0)
258
charCrypt='*';
259
260
if (file_info.compression_method==0)
261
string_method="Stored";
262
else
263
if (file_info.compression_method==Z_DEFLATED)
264
{
265
uInt iLevel=(uInt)((file_info.flag & 0x6)/2);
266
if (iLevel==0)
267
string_method="Defl:N";
268
else if (iLevel==1)
269
string_method="Defl:X";
270
else if ((iLevel==2) || (iLevel==3))
271
string_method="Defl:F"; /* 2:fast , 3 : extra fast*/
272
}
273
else
274
if (file_info.compression_method==Z_BZIP2ED)
275
{
276
string_method="BZip2 ";
277
}
278
else
279
string_method="Unkn. ";
280
281
Display64BitsSize(file_info.uncompressed_size,7);
282
printf(" %6s%c",string_method,charCrypt);
283
Display64BitsSize(file_info.compressed_size,7);
284
printf(" %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n",
285
ratio,
286
(uLong)file_info.tmu_date.tm_mon + 1,
287
(uLong)file_info.tmu_date.tm_mday,
288
(uLong)file_info.tmu_date.tm_year % 100,
289
(uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min,
290
(uLong)file_info.crc,filename_inzip);
291
if ((i+1)<gi.number_entry)
292
{
293
err = unzGoToNextFile(uf);
294
if (err!=UNZ_OK)
295
{
296
printf("error %d with zipfile in unzGoToNextFile\n",err);
297
break;
298
}
299
}
300
}
301
302
return 0;
303
}
304
305
306
static int do_extract_currentfile(unzFile uf, const int* popt_extract_without_path, int* popt_overwrite, const char* password) {
307
char filename_inzip[65536+1];
308
char* filename_withoutpath;
309
char* p;
310
int err=UNZ_OK;
311
FILE *fout=NULL;
312
void* buf;
313
uInt size_buf;
314
315
unz_file_info64 file_info;
316
err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
317
318
if (err!=UNZ_OK)
319
{
320
printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
321
return err;
322
}
323
324
size_buf = WRITEBUFFERSIZE;
325
buf = (void*)malloc(size_buf);
326
if (buf==NULL)
327
{
328
printf("Error allocating memory\n");
329
return UNZ_INTERNALERROR;
330
}
331
332
p = filename_withoutpath = filename_inzip;
333
while ((*p) != '\0')
334
{
335
if (((*p)=='/') || ((*p)=='\\'))
336
filename_withoutpath = p+1;
337
p++;
338
}
339
340
if ((*filename_withoutpath)=='\0')
341
{
342
if ((*popt_extract_without_path)==0)
343
{
344
printf("creating directory: %s\n",filename_inzip);
345
mymkdir(filename_inzip);
346
}
347
}
348
else
349
{
350
const char* write_filename;
351
int skip=0;
352
353
if ((*popt_extract_without_path)==0)
354
write_filename = filename_inzip;
355
else
356
write_filename = filename_withoutpath;
357
358
if (write_filename[0]!='\0')
359
{
360
const char* relative_check = write_filename;
361
while (relative_check[1]!='\0')
362
{
363
if (relative_check[0]=='.' && relative_check[1]=='.')
364
write_filename = relative_check;
365
relative_check++;
366
}
367
}
368
369
while (write_filename[0]=='/' || write_filename[0]=='.')
370
write_filename++;
371
372
err = unzOpenCurrentFilePassword(uf,password);
373
if (err!=UNZ_OK)
374
{
375
printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err);
376
}
377
378
if (((*popt_overwrite)==0) && (err==UNZ_OK))
379
{
380
char rep=0;
381
FILE* ftestexist;
382
ftestexist = FOPEN_FUNC(write_filename,"rb");
383
if (ftestexist!=NULL)
384
{
385
fclose(ftestexist);
386
do
387
{
388
char answer[128];
389
int ret;
390
391
printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename);
392
ret = scanf("%1s",answer);
393
if (ret != 1)
394
{
395
exit(EXIT_FAILURE);
396
}
397
rep = answer[0] ;
398
if ((rep>='a') && (rep<='z'))
399
rep -= 0x20;
400
}
401
while ((rep!='Y') && (rep!='N') && (rep!='A'));
402
}
403
404
if (rep == 'N')
405
skip = 1;
406
407
if (rep == 'A')
408
*popt_overwrite=1;
409
}
410
411
if ((skip==0) && (err==UNZ_OK))
412
{
413
fout=FOPEN_FUNC(write_filename,"wb");
414
/* some zipfile don't contain directory alone before file */
415
if ((fout==NULL) && ((*popt_extract_without_path)==0) &&
416
(filename_withoutpath!=(char*)filename_inzip))
417
{
418
char c=*(filename_withoutpath-1);
419
*(filename_withoutpath-1)='\0';
420
makedir(write_filename);
421
*(filename_withoutpath-1)=c;
422
fout=FOPEN_FUNC(write_filename,"wb");
423
}
424
425
if (fout==NULL)
426
{
427
printf("error opening %s\n",write_filename);
428
}
429
}
430
431
if (fout!=NULL)
432
{
433
printf(" extracting: %s\n",write_filename);
434
435
do
436
{
437
err = unzReadCurrentFile(uf,buf,size_buf);
438
if (err<0)
439
{
440
printf("error %d with zipfile in unzReadCurrentFile\n",err);
441
break;
442
}
443
if (err>0)
444
if (fwrite(buf,(unsigned)err,1,fout)!=1)
445
{
446
printf("error in writing extracted file\n");
447
err=UNZ_ERRNO;
448
break;
449
}
450
}
451
while (err>0);
452
if (fout)
453
fclose(fout);
454
455
if (err==0)
456
change_file_date(write_filename,file_info.dosDate,
457
file_info.tmu_date);
458
}
459
460
if (err==UNZ_OK)
461
{
462
err = unzCloseCurrentFile (uf);
463
if (err!=UNZ_OK)
464
{
465
printf("error %d with zipfile in unzCloseCurrentFile\n",err);
466
}
467
}
468
else
469
unzCloseCurrentFile(uf); /* don't lose the error */
470
}
471
472
free(buf);
473
return err;
474
}
475
476
477
static int do_extract(unzFile uf, int opt_extract_without_path, int opt_overwrite, const char* password) {
478
uLong i;
479
unz_global_info64 gi;
480
int err;
481
482
err = unzGetGlobalInfo64(uf,&gi);
483
if (err!=UNZ_OK)
484
{
485
printf("error %d with zipfile in unzGetGlobalInfo\n",err);
486
return err;
487
}
488
489
for (i=0;i<gi.number_entry;i++)
490
{
491
err = do_extract_currentfile(uf,&opt_extract_without_path,
492
&opt_overwrite,
493
password);
494
if (err != UNZ_OK)
495
break;
496
497
if ((i+1)<gi.number_entry)
498
{
499
err = unzGoToNextFile(uf);
500
if (err!=UNZ_OK)
501
{
502
printf("error %d with zipfile in unzGoToNextFile\n",err);
503
break;
504
}
505
}
506
}
507
508
return err;
509
}
510
511
static int do_extract_onefile(unzFile uf, const char* filename, int opt_extract_without_path, int opt_overwrite, const char* password) {
512
if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK)
513
{
514
printf("file %s not found in the zipfile\n",filename);
515
return 2;
516
}
517
518
return do_extract_currentfile(uf,&opt_extract_without_path,
519
&opt_overwrite,
520
password);
521
}
522
523
524
int main(int argc, char *argv[]) {
525
const char *zipfilename=NULL;
526
const char *filename_to_extract=NULL;
527
const char *password=NULL;
528
char filename_try[MAXFILENAME+16] = "";
529
int i;
530
int ret_value=0;
531
int opt_do_list=0;
532
int opt_do_extract=1;
533
int opt_do_extract_withoutpath=0;
534
int opt_overwrite=0;
535
int opt_extractdir=0;
536
const char *dirname=NULL;
537
unzFile uf=NULL;
538
539
do_banner();
540
if (argc==1)
541
{
542
do_help();
543
return 0;
544
}
545
else
546
{
547
for (i=1;i<argc;i++)
548
{
549
if ((*argv[i])=='-')
550
{
551
const char *p=argv[i]+1;
552
553
while ((*p)!='\0')
554
{
555
char c=*(p++);
556
if ((c=='l') || (c=='L'))
557
opt_do_list = 1;
558
if ((c=='v') || (c=='V'))
559
opt_do_list = 1;
560
if ((c=='x') || (c=='X'))
561
opt_do_extract = 1;
562
if ((c=='e') || (c=='E'))
563
opt_do_extract = opt_do_extract_withoutpath = 1;
564
if ((c=='o') || (c=='O'))
565
opt_overwrite=1;
566
if ((c=='d') || (c=='D'))
567
{
568
opt_extractdir=1;
569
dirname=argv[i+1];
570
}
571
572
if (((c=='p') || (c=='P')) && (i+1<argc))
573
{
574
password=argv[i+1];
575
i++;
576
}
577
}
578
}
579
else
580
{
581
if (zipfilename == NULL)
582
zipfilename = argv[i];
583
else if ((filename_to_extract==NULL) && (!opt_extractdir))
584
filename_to_extract = argv[i] ;
585
}
586
}
587
}
588
589
if (zipfilename!=NULL)
590
{
591
592
# ifdef USEWIN32IOAPI
593
zlib_filefunc64_def ffunc;
594
# endif
595
596
strncpy(filename_try, zipfilename,MAXFILENAME-1);
597
/* strncpy doesn't append the trailing NULL, of the string is too long. */
598
filename_try[ MAXFILENAME ] = '\0';
599
600
# ifdef USEWIN32IOAPI
601
fill_win32_filefunc64A(&ffunc);
602
uf = unzOpen2_64(zipfilename,&ffunc);
603
# else
604
uf = unzOpen64(zipfilename);
605
# endif
606
if (uf==NULL)
607
{
608
strcat(filename_try,".zip");
609
# ifdef USEWIN32IOAPI
610
uf = unzOpen2_64(filename_try,&ffunc);
611
# else
612
uf = unzOpen64(filename_try);
613
# endif
614
}
615
}
616
617
if (uf==NULL)
618
{
619
printf("Cannot open %s or %s.zip\n",zipfilename,zipfilename);
620
return 1;
621
}
622
printf("%s opened\n",filename_try);
623
624
if (opt_do_list==1)
625
ret_value = do_list(uf);
626
else if (opt_do_extract==1)
627
{
628
#ifdef _WIN32
629
if (opt_extractdir && _chdir(dirname))
630
#else
631
if (opt_extractdir && chdir(dirname))
632
#endif
633
{
634
printf("Error changing into %s, aborting\n", dirname);
635
exit(-1);
636
}
637
638
if (filename_to_extract == NULL)
639
ret_value = do_extract(uf, opt_do_extract_withoutpath, opt_overwrite, password);
640
else
641
ret_value = do_extract_onefile(uf, filename_to_extract, opt_do_extract_withoutpath, opt_overwrite, password);
642
}
643
644
unzClose(uf);
645
646
return ret_value;
647
}
648

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button