-
Notifications
You must be signed in to change notification settings - Fork 0
/
zipup.c
1922 lines (1727 loc) · 54.9 KB
/
zipup.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
zipup.c - Zip 3
Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
See the accompanying file LICENSE, version 2007-Mar-4 or later
(the contents of which are also included in zip.h) for terms of use.
If, for some reason, all these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
*/
/*
* zipup.c by Mark Adler and Jean-loup Gailly.
*/
#define __ZIPUP_C
/* Found that for at least unix port zip.h has to be first or ctype.h will
define off_t and when using 64-bit file environment off_t in other files
is 8 bytes while off_t here is 4 bytes, and this makes the zlist struct
different sizes and needless to say leads to segmentation faults. Putting
zip.h first seems to fix this. 8/14/04 EG */
#include "zip.h"
#include <ctype.h>
#include <errno.h>
#ifndef UTIL /* This module contains no code for Zip Utilities */
#include "revision.h"
#include "crc32.h"
#include "crypt.h"
#ifdef USE_ZLIB
# include "zlib.h"
#endif
#ifdef BZIP2_SUPPORT
# ifdef BZIP2_USEBZIP2DIR
# include "bzip2/bzlib.h"
# else
# include "bzlib.h"
# endif
#endif
#ifdef OS2
# include "os2/os2zip.h"
#endif
#if defined(MMAP)
# include <sys/mman.h>
# ifndef PAGESIZE /* used to be SYSV, what about pagesize on SVR3 ? */
# define PAGESIZE getpagesize()
# endif
# if defined(NO_VALLOC) && !defined(valloc)
# define valloc malloc
# endif
#endif
/* Use the raw functions for MSDOS and Unix to save on buffer space.
They're not used for VMS since it doesn't work (raw is weird on VMS).
*/
#ifdef AMIGA
# include "amiga/zipup.h"
#endif /* AMIGA */
#ifdef AOSVS
# include "aosvs/zipup.h"
#endif /* AOSVS */
#ifdef ATARI
# include "atari/zipup.h"
#endif
#ifdef __BEOS__
# include "beos/zipup.h"
#endif
#ifdef __ATHEOS__
# include "atheos/zipup.h"
#endif /* __ATHEOS__ */
#ifdef __human68k__
# include "human68k/zipup.h"
#endif /* __human68k__ */
#ifdef MACOS
# include "macos/zipup.h"
#endif
#ifdef DOS
# include "msdos/zipup.h"
#endif /* DOS */
#ifdef NLM
# include "novell/zipup.h"
# include <nwfattr.h>
#endif
#ifdef OS2
# include "os2/zipup.h"
#endif /* OS2 */
#ifdef RISCOS
# include "acorn/zipup.h"
#endif
#ifdef TOPS20
# include "tops20/zipup.h"
#endif
#ifdef UNIX
# include "unix/zipup.h"
#endif
#ifdef CMS_MVS
# include "zipup.h"
#endif /* CMS_MVS */
#ifdef TANDEM
# include "zipup.h"
#endif /* TANDEM */
#ifdef VMS
# include "vms/zipup.h"
#endif /* VMS */
#ifdef QDOS
# include "qdos/zipup.h"
#endif /* QDOS */
#ifdef WIN32
# include "win32/zipup.h"
#endif
#ifdef THEOS
# include "theos/zipup.h"
#endif
/* Local functions */
#ifndef RISCOS
local int suffixes OF((char *, char *));
#else
local int filetypes OF((char *, char *));
#endif
local unsigned file_read OF((char *buf, unsigned size));
#ifdef USE_ZLIB
local int zl_deflate_init OF((int pack_level));
#else /* !USE_ZLIB */
# ifdef ZP_NEED_MEMCOMPR
local unsigned mem_read OF((char *buf, unsigned size));
# endif
#endif /* ?USE_ZLIB */
/* zip64 support 08/29/2003 R.Nausedat */
local zoff_t filecompress OF((struct zlist far *z_entry, int *cmpr_method));
#ifdef BZIP2_SUPPORT
local zoff_t bzfilecompress OF((struct zlist far *z_entry, int *cmpr_method));
#endif
/* Deflate "internal" global data (currently not in zip.h) */
#if defined(MMAP) || defined(BIG_MEM)
# ifdef USE_ZLIB
local uch *window = NULL; /* Used to read all input file at once */
local ulg window_size; /* size of said window */
# else /* !USE_ZLIB */
extern uch *window; /* Used to read all input file at once */
#endif /* ?USE_ZLIB */
#endif /* MMAP || BIG_MEM */
#ifndef USE_ZLIB
extern ulg window_size; /* size of said window */
unsigned (*read_buf) OF((char *buf, unsigned size)) = file_read;
/* Current input function. Set to mem_read for in-memory compression */
#endif /* !USE_ZLIB */
/* Local data */
local ulg crc; /* crc on uncompressed file data */
local ftype ifile; /* file to compress */
#if defined(MMAP) || defined(BIG_MEM)
local ulg remain;
/* window bytes not yet processed.
* special value "(ulg)-1L" reserved to signal normal reads.
*/
#endif /* MMAP || BIG_MEM */
#ifdef USE_ZLIB
local int deflInit = FALSE; /* flag: zlib deflate is initialized */
local z_stream zstrm; /* zlib's data interface structure */
local char *f_ibuf = NULL;
local char *f_obuf = NULL;
#else /* !USE_ZLIB */
local char file_outbuf[1024]; /* output buffer for compression to file */
# ifdef ZP_NEED_MEMCOMPR
local char *in_buf;
/* Current input buffer, in_buf is used only for in-memory compression. */
local unsigned in_offset;
/* Current offset in input buffer. in_offset is used only for in-memory
* compression. On 16 bit machines, the buffer is limited to 64K.
*/
local unsigned in_size; /* size of current input buffer */
# endif /* ZP_NEED_MEMCOMPR */
#endif /* ?USE_ZLIB */
#ifdef BZIP2_SUPPORT
local int bzipInit; /* flag: bzip2lib is initialized */
local bz_stream bstrm; /* zlib's data interface structure */
# if !defined(USE_ZLIB)
local char *f_ibuf = NULL;
local char *f_obuf = NULL;
# endif /* !USE_ZLIB */
#endif /* BZIP2_SUPPORT */
#ifdef DEBUG
zoff_t isize; /* input file size. global only for debugging */
#else /* !DEBUG */
local zoff_t isize; /* input file size. global only for debugging */
#endif /* ?DEBUG */
/* If file_read detects binary it sets this flag - 12/16/04 EG */
local int file_binary = 0; /* first buf */
local int file_binary_final = 0; /* for bzip2 for entire file. assume text until find binary */
/* moved check to function 3/14/05 EG */
int is_seekable(y)
FILE *y;
{
zoff_t pos;
#ifdef BROKEN_FSEEK
if (!fseekable(y)) {
return 0;
}
#endif
pos = zftello(y);
if (zfseeko(y, pos, SEEK_SET)) {
return 0;
}
return 1;
}
int percent(n, m)
uzoff_t n;
uzoff_t m; /* n is the original size, m is the new size */
/* Return the percentage compression from n to m using only integer
operations */
{
zoff_t p;
#if 0
if (n > 0xffffffL) /* If n >= 16M */
{ /* then divide n and m by 256 */
n += 0x80; n >>= 8;
m += 0x80; m >>= 8;
}
return n > m ? (int)(1 + (200 * (n - m)/n)) / 2 : 0;
#endif
/* 2004-12-01 SMS.
* Changed to do big-n test only for small zoff_t.
* Changed big-n arithmetic to accomodate apparently negative values
* when a small zoff_t value exceeds 2G.
* Increased the reduction divisor from 256 to 512 to avoid the sign bit
* in a reduced intermediate, allowing signed arithmetic for the final
* result (which is no longer artificially limited to non-negative
* values).
* Note that right shifts must be on unsigned values to avoid undesired
* sign extension.
*/
/* Handle n = 0 case and account for int maybe being 16-bit. 12/28/2004 EG
*/
#define PC_MAX_SAFE 0x007fffffL /* 9 clear bits at high end. */
#define PC_MAX_RND 0xffffff00L /* 8 clear bits at low end. */
if (sizeof(uzoff_t) < 8) /* Don't fiddle with big zoff_t. */
{
if ((ulg)n > PC_MAX_SAFE) /* Reduce large values. (n > m) */
{
if ((ulg)n < PC_MAX_RND) /* Divide n by 512 with rounding, */
n = ((ulg)n + 0x100) >> 9; /* if boost won't overflow. */
else /* Otherwise, use max value. */
n = PC_MAX_SAFE;
if ((ulg)m < PC_MAX_RND) /* Divide m by 512 with rounding, */
m = ((ulg)m + 0x100) >> 9; /* if boost won't overflow. */
else /* Otherwise, use max value. */
m = PC_MAX_SAFE;
}
}
if (n != 0)
p = ((200 * ((zoff_t)n - (zoff_t)m) / (zoff_t)n) + 1) / 2;
else
p = 0;
return (int)p; /* Return (rounded) % reduction. */
}
#ifndef RISCOS
local int suffixes(a, s)
char *a; /* name to check suffix of */
char *s; /* list of suffixes separated by : or ; */
/* Return true if a ends in any of the suffixes in the list s. */
{
int m; /* true if suffix matches so far */
char *p; /* pointer into special */
char *q; /* pointer into name a */
#ifdef QDOS
short dlen = devlen(a);
a = a + dlen;
#endif
m = 1;
#ifdef VMS
if( (q = strrchr(a,';')) != NULL ) /* Cut out VMS file version */
--q;
else
q = a + strlen(a) - 1;
#else /* !VMS */
q = a + strlen(a) - 1;
#endif /* ?VMS */
for (p = s + strlen(s) - 1; p >= s; p--)
if (*p == ':' || *p == ';')
{
if (m)
return 1;
else
{
m = 1;
#ifdef VMS
if( (q = strrchr(a,';')) != NULL ) /* Cut out VMS file version */
--q;
else
q = a + strlen(a) - 1;
#else /* !VMS */
q = a + strlen(a) - 1;
#endif /* ?VMS */
}
}
else
{
m = m && q >= a && case_map(*p) == case_map(*q);
q--;
}
return m;
}
#else /* RISCOS */
local int filetypes(a, s)
char *a; /* extra field of file to check filetype of */
char *s; /* list of filetypes separated by : or ; */
/* Return true if a is any of the filetypes in the list s. */
{
char *p; /* pointer into special */
char typestr[4]; /* filetype hex string taken from a */
if ((((unsigned*)a)[2] & 0xFFF00000) != 0xFFF00000) {
/* The file is not filestamped, always try to compress it */
return 0;
}
sprintf(typestr,"%.3X",(((unsigned*)a)[2] & 0x000FFF00) >> 8);
for (p=s;p<=s+strlen(s)-3;p+=3) { /* p+=3 to skip 3 hex type */
while (*p==':' || *p==';')
p++;
if (typestr[0] == toupper(p[0]) &&
typestr[1] == toupper(p[1]) &&
typestr[2] == toupper(p[2]))
return 1;
}
return 0;
}
#endif /* ?RISCOS */
/* Note: a zip "entry" includes a local header (which includes the file
name), an encryption header if encrypting, the compressed data
and possibly an extended local header. */
int zipup(z)
struct zlist far *z; /* zip entry to compress */
/* Compress the file z->name into the zip entry described by *z and write
it to the file *y. Encrypt if requested. Return an error code in the
ZE_ class. Also, update tempzn by the number of bytes written. */
/* y is now global */
{
iztimes f_utim; /* UNIX GMT timestamps, filled by filetime() */
ulg tim; /* time returned by filetime() */
ulg a = 0L; /* attributes returned by filetime() */
char *b; /* malloc'ed file buffer */
extent k = 0; /* result of zread */
int l = 0; /* true if this file is a symbolic link */
int m; /* method for this entry */
zoff_t o = 0, p; /* offsets in zip file */
zoff_t q = (zoff_t) -3; /* size returned by filetime */
uzoff_t uq; /* unsigned q */
zoff_t s = 0; /* size of compressed data */
int r; /* temporary variable */
int isdir; /* set for a directory name */
int set_type = 0; /* set if file type (ascii/binary) unknown */
zoff_t last_o; /* used to detect wrap around */
ush tempext = 0; /* temp copies of extra fields */
ush tempcext = 0;
char *tempextra = NULL;
char *tempcextra = NULL;
#ifdef WINDLL
# ifdef ZIP64_SUPPORT
extern _int64 filesize64;
extern unsigned long low;
extern unsigned long high;
# endif
#endif
z->nam = strlen(z->iname);
isdir = z->iname[z->nam-1] == (char)0x2f; /* ascii[(unsigned)('/')] */
file_binary = -1; /* not set, set after first read */
file_binary_final = 0; /* not set, set after first read */
#if defined(UNICODE_SUPPORT) && defined(WIN32)
if (!no_win32_wide)
tim = filetimew(z->namew, &a, &q, &f_utim);
else
tim = filetime(z->name, &a, &q, &f_utim);
#else
tim = filetime(z->name, &a, &q, &f_utim);
#endif
if (tim == 0 || q == (zoff_t) -3)
return ZE_OPEN;
/* q is set to -1 if the input file is a device, -2 for a volume label */
if (q == (zoff_t) -2) {
isdir = 1;
q = 0;
} else if (isdir != ((a & MSDOS_DIR_ATTR) != 0)) {
/* don't overwrite a directory with a file and vice-versa */
return ZE_MISS;
}
/* reset dot_count for each file */
if (!display_globaldots)
dot_count = -1;
/* display uncompressed size */
uq = ((uzoff_t) q > (uzoff_t) -3) ? 0 : (uzoff_t) q;
if (noisy && display_usize) {
fprintf(mesg, " (");
DisplayNumString( mesg, uq );
fprintf(mesg, ")");
mesg_line_started = 1;
fflush(mesg);
}
if (logall && display_usize) {
fprintf(logfile, " (");
DisplayNumString( logfile, uq );
fprintf(logfile, ")");
logfile_line_started = 1;
fflush(logfile);
}
/* initial z->len so if error later have something */
z->len = uq;
z->att = (ush)UNKNOWN; /* will be changed later */
z->atx = 0; /* may be changed by set_extra_field() */
/* Free the old extra fields which are probably obsolete */
/* Should probably read these and keep any we don't update. 12/30/04 EG */
if (extra_fields == 2) {
/* If keeping extra fields, make copy before clearing for set_extra_field()
A better approach is to modify the port code, but maybe later */
if (z->ext) {
if ((tempextra = malloc(z->ext)) == NULL) {
ZIPERR(ZE_MEM, "extra fields copy");
}
memcpy(tempextra, z->extra, z->ext);
tempext = z->ext;
}
if (z->cext) {
if ((tempcextra = malloc(z->cext)) == NULL) {
ZIPERR(ZE_MEM, "extra fields copy");
}
memcpy(tempcextra, z->cextra, z->cext);
tempcext = z->cext;
}
}
if (z->ext) {
free((zvoid *)(z->extra));
}
if (z->cext && z->extra != z->cextra) {
free((zvoid *)(z->cextra));
}
z->extra = z->cextra = NULL;
z->ext = z->cext = 0;
#if defined(MMAP) || defined(BIG_MEM)
remain = (ulg)-1L; /* changed only for MMAP or BIG_MEM */
#endif /* MMAP || BIG_MEM */
#if (!defined(USE_ZLIB) || defined(MMAP) || defined(BIG_MEM))
window_size = 0L;
#endif /* !USE_ZLIB || MMAP || BIG_MEM */
/* Select method based on the suffix and the global method */
#ifndef RISCOS
m = special != NULL && suffixes(z->name, special) ? STORE : method;
#else /* RISCOS must set m after setting extra field */
m = method;
#endif /* ?RISCOS */
/* For now force deflate if using descriptors. Instead zip and unzip
could check bytes read against compressed size in each data descriptor
found and skip over any that don't match. This is how at least one
other zipper does it. To be added later. Until then it
probably doesn't hurt to force deflation when streaming. 12/30/04 EG
*/
/* Now is a good time. For now allow storing for testing. 12/16/05 EG */
/* By release need to force deflation based on reports some inflate
streamed data to find the end of the data */
/* Need to handle bzip2 */
#ifdef NO_STREAMING_STORE
if (use_descriptors && m == STORE)
{
m = DEFLATE;
}
#endif
/* Open file to zip up unless it is stdin */
if (strcmp(z->name, "-") == 0)
{
ifile = (ftype)zstdin;
#if defined(MSDOS) || defined(__human68k__)
if (isatty(zstdin) == 0) /* keep default mode if stdin is a terminal */
setmode(zstdin, O_BINARY);
#endif
z->tim = tim;
}
else
{
#if !(defined(VMS) && defined(VMS_PK_EXTRA))
if (extra_fields) {
/* create extra field and change z->att and z->atx if desired */
set_extra_field(z, &f_utim);
# ifdef QLZIP
if(qlflag)
a |= (S_IXUSR) << 16; /* Cross compilers don't set this */
# endif
# ifdef RISCOS
m = special != NULL && filetypes(z->extra, special) ? STORE : method;
# endif /* RISCOS */
/* For now allow store for testing */
#ifdef NO_STREAMING_STORE
/* For now force deflation if using data descriptors. */
if (use_descriptors && m == STORE)
{
m = DEFLATE;
}
#endif
}
#endif /* !(VMS && VMS_PK_EXTRA) */
l = issymlnk(a);
if (l) {
ifile = fbad;
m = STORE;
}
else if (isdir) { /* directory */
ifile = fbad;
m = STORE;
q = 0;
}
#ifdef THEOS
else if (((a >> 16) & S_IFMT) == S_IFLIB) { /* library */
ifile = fbad;
m = STORE;
q = 0;
}
#endif
else {
#ifdef CMS_MVS
if (bflag) {
if ((ifile = zopen(z->name, fhowb)) == fbad)
return ZE_OPEN;
}
else
#endif /* CMS_MVS */
#if defined(UNICODE_SUPPORT) && defined(WIN32)
if (!no_win32_wide) {
if ((ifile = zwopen(z->namew, fhow)) == fbad)
return ZE_OPEN;
} else {
if ((ifile = zopen(z->name, fhow)) == fbad)
return ZE_OPEN;
}
#else
if ((ifile = zopen(z->name, fhow)) == fbad)
return ZE_OPEN;
#endif
}
z->tim = tim;
#if defined(VMS) && defined(VMS_PK_EXTRA)
/* vms_get_attributes must be called after vms_open() */
if (extra_fields) {
/* create extra field and change z->att and z->atx if desired */
vms_get_attributes(ifile, z, &f_utim);
}
#endif /* VMS && VMS_PK_EXTRA */
#if defined(MMAP) || defined(BIG_MEM)
/* Map ordinary files but not devices. This code should go in fileio.c */
if (!translate_eol && m != STORE && q != -1L && (ulg)q > 0 &&
(ulg)q + MIN_LOOKAHEAD > (ulg)q) {
# ifdef MMAP
/* Map the whole input file in memory */
if (window != NULL)
free(window); /* window can't be a mapped file here */
window_size = (ulg)q + MIN_LOOKAHEAD;
remain = window_size & (PAGESIZE-1);
/* If we can't touch the page beyond the end of file, we must
* allocate an extra page.
*/
if (remain > MIN_LOOKAHEAD) {
window = (uch*)mmap(0, window_size, PROT_READ, MAP_PRIVATE, ifile, 0);
} else {
window = (uch*)valloc(window_size - remain + PAGESIZE);
if (window != NULL) {
window = (uch*)mmap((char*)window, window_size - remain, PROT_READ,
MAP_PRIVATE | MAP_FIXED, ifile, 0);
} else {
window = (uch*)(-1);
}
}
if (window == (uch*)(-1)) {
Trace((mesg, " mmap failure on %s\n", z->name));
window = NULL;
window_size = 0L;
remain = (ulg)-1L;
} else {
remain = (ulg)q;
}
# else /* !MMAP, must be BIG_MEM */
/* Read the whole input file at once */
window_size = (ulg)q + MIN_LOOKAHEAD;
window = window ? (uch*) realloc(window, (unsigned)window_size)
: (uch*) malloc((unsigned)window_size);
/* Just use normal code if big malloc or realloc fails: */
if (window != NULL) {
remain = (ulg)zread(ifile, (char*)window, q+1);
if (remain != (ulg)q) {
fprintf(mesg, " q=%lu, remain=%lu ", (ulg)q, remain);
error("can't read whole file at once");
}
} else {
window_size = 0L;
}
# endif /* ?MMAP */
}
#endif /* MMAP || BIG_MEM */
} /* strcmp(z->name, "-") == 0 */
if (extra_fields == 2) {
unsigned len;
char *p;
/* step through old extra fields and copy over any not already
in new extra fields */
p = copy_nondup_extra_fields(tempextra, tempext, z->extra, z->ext, &len);
free(z->extra);
z->ext = len;
z->extra = p;
p = copy_nondup_extra_fields(tempcextra, tempcext, z->cextra, z->cext, &len);
free(z->cextra);
z->cext = len;
z->cextra = p;
if (tempext)
free(tempextra);
if (tempcext)
free(tempcextra);
}
if (q == 0)
m = STORE;
if (m == BEST)
m = DEFLATE;
/* Do not create STORED files with extended local headers if the
* input size is not known, because such files could not be extracted.
* So if the zip file is not seekable and the input file is not
* on disk, obey the -0 option by forcing deflation with stored block.
* Note however that using "zip -0" as filter is not very useful...
* ??? to be done.
*/
/* An alternative used by others is to allow storing but on reading do
* a second check when a signature is found. This is simply to check
* the compressed size to the bytes read since the start of the file data.
* If this is the right signature then the compressed size should match
* the size of the compressed data to that point. If not look for the
* next signature. We should do this. 12/31/04 EG
*
* For reading and testing we should do this, but should not write
* stored streamed data unless for testing as finding the end of
* streamed deflated data can be done by inflating. 6/26/06 EG
*/
/* Fill in header information and write local header to zip file.
* This header will later be re-written since compressed length and
* crc are not yet known.
*/
/* (Assume ext, cext, com, and zname already filled in.) */
#if defined(OS2) || defined(WIN32)
# ifdef WIN32_OEM
/* When creating OEM-coded names on Win32, the entries must always be marked
as "created on MSDOS" (OS_CODE = 0), because UnZip needs to handle archive
entry names just like those created by Zip's MSDOS port.
*/
z->vem = (ush)(dosify ? 20 : 0 + Z_MAJORVER * 10 + Z_MINORVER);
# else
z->vem = (ush)(z->dosflag ? (dosify ? 20 : /* Made under MSDOS by PKZIP 2.0 */
(0 + Z_MAJORVER * 10 + Z_MINORVER))
: OS_CODE + Z_MAJORVER * 10 + Z_MINORVER);
/* For a plain old (8+3) FAT file system, we cheat and pretend that the file
* was not made on OS2/WIN32 but under DOS. unzip is confused otherwise.
*/
# endif
#else /* !(OS2 || WIN32) */
z->vem = (ush)(dosify ? 20 : OS_CODE + Z_MAJORVER * 10 + Z_MINORVER);
#endif /* ?(OS2 || WIN32) */
z->ver = (ush)(m == STORE ? 10 : 20); /* Need PKUNZIP 2.0 except for store */
#ifdef BZIP2_SUPPORT
if (method == BZIP2)
z->ver = (ush)(m == STORE ? 10 : 46);
#endif
z->crc = 0; /* to be updated later */
/* Assume first that we will need an extended local header: */
if (isdir)
/* If dir then q = 0 and extended header not needed */
z->flg = 0;
else
z->flg = 8; /* to be updated later */
#if CRYPT
if (!isdir && key != NULL) {
z->flg |= 1;
/* Since we do not yet know the crc here, we pretend that the crc
* is the modification time:
*/
z->crc = z->tim << 16;
/* More than pretend. File is encrypted using crypt header with that. */
}
#endif /* CRYPT */
z->lflg = z->flg;
z->how = (ush)m; /* may be changed later */
z->siz = (zoff_t)(m == STORE && q >= 0 ? q : 0); /* will be changed later */
z->len = (zoff_t)(q != -1L ? q : 0); /* may be changed later */
if (z->att == (ush)UNKNOWN) {
z->att = BINARY; /* set sensible value in header */
set_type = 1;
}
/* Attributes from filetime(), flag bits from set_extra_field(): */
#if defined(DOS) || defined(OS2) || defined(WIN32)
z->atx = z->dosflag ? a & 0xff : a | (z->atx & 0x0000ff00);
#else
z->atx = dosify ? a & 0xff : a | (z->atx & 0x0000ff00);
#endif /* DOS || OS2 || WIN32 */
if ((r = putlocal(z, PUTLOCAL_WRITE)) != ZE_OK) {
if (ifile != fbad)
zclose(ifile);
return r;
}
/* now get split information set by bfwrite() */
z->off = current_local_offset;
/* disk local header was written to */
z->dsk = current_local_disk;
tempzn += 4 + LOCHEAD + z->nam + z->ext;
#if CRYPT
if (!isdir && key != NULL) {
crypthead(key, z->crc);
z->siz += RAND_HEAD_LEN; /* to be updated later */
tempzn += RAND_HEAD_LEN;
}
#endif /* CRYPT */
if (ferror(y)) {
if (ifile != fbad)
zclose(ifile);
ZIPERR(ZE_WRITE, "unexpected error on zip file");
}
last_o = o;
o = zftello(y); /* for debugging only, ftell can fail on pipes */
if (ferror(y))
clearerr(y);
if (o != -1 && last_o > o) {
fprintf(mesg, "last %s o %s\n", zip_fzofft(last_o, NULL, NULL),
zip_fzofft(o, NULL, NULL));
ZIPERR(ZE_BIG, "seek wrap - zip file too big to write");
}
/* Write stored or deflated file to zip file */
isize = 0L;
crc = CRCVAL_INITIAL;
if (isdir) {
/* nothing to write */
}
else if (m != STORE) {
if (set_type) z->att = (ush)UNKNOWN;
/* ... is finally set in file compression routine */
#ifdef BZIP2_SUPPORT
if (m == BZIP2) {
s = bzfilecompress(z, &m);
}
else
#endif /* BZIP2_SUPPORT */
{
s = filecompress(z, &m);
}
#ifndef PGP
if (z->att == (ush)BINARY && translate_eol && file_binary) {
if (translate_eol == 1)
zipwarn("has binary so -l ignored", "");
else
zipwarn("has binary so -ll ignored", "");
}
else if (z->att == (ush)BINARY && translate_eol) {
if (translate_eol == 1)
zipwarn("-l used on binary file - corrupted?", "");
else
zipwarn("-ll used on binary file - corrupted?", "");
}
#endif
}
else
{
if ((b = malloc(SBSZ)) == NULL)
return ZE_MEM;
if (l) {
k = rdsymlnk(z->name, b, SBSZ);
/*
* compute crc first because zfwrite will alter the buffer b points to !!
*/
crc = crc32(crc, (uch *) b, k);
if (zfwrite(b, 1, k) != k)
{
free((zvoid *)b);
return ZE_TEMP;
}
isize = k;
#ifdef MINIX
q = k;
#endif /* MINIX */
}
else
{
while ((k = file_read(b, SBSZ)) > 0 && k != (extent) EOF)
{
if (zfwrite(b, 1, k) != k)
{
if (ifile != fbad)
zclose(ifile);
free((zvoid *)b);
return ZE_TEMP;
}
if (!display_globaldots) {
if (dot_size > 0) {
/* initial space */
if (noisy && dot_count == -1) {
#ifndef WINDLL
putc(' ', mesg);
fflush(mesg);
#else
fprintf(stdout,"%c",' ');
#endif
dot_count++;
}
dot_count++;
if (dot_size <= (dot_count + 1) * SBSZ) dot_count = 0;
}
if ((verbose || noisy) && dot_size && !dot_count) {
#ifndef WINDLL
putc('.', mesg);
fflush(mesg);
#else
fprintf(stdout,"%c",'.');
#endif
mesg_line_started = 1;
}
}
}
}
free((zvoid *)b);
s = isize;
}
if (ifile != fbad && zerr(ifile)) {
perror("\nzip warning");
if (logfile)
fprintf(logfile, "\nzip warning: %s\n", strerror(errno));
zipwarn("could not read input file: ", z->oname);
}
if (ifile != fbad)
zclose(ifile);
#ifdef MMAP
if (remain != (ulg)-1L) {
munmap((caddr_t) window, window_size);
window = NULL;
}
#endif /*MMAP */
tempzn += s;
p = tempzn; /* save for future fseek() */
#if (!defined(MSDOS) || defined(OS2))
#if !defined(VMS) && !defined(CMS_MVS) && !defined(__mpexl)
/* Check input size (but not in VMS -- variable record lengths mess it up)
* and not on MSDOS -- diet in TSR mode reports an incorrect file size)
*/
#ifndef TANDEM /* Tandem EOF does not match byte count unless Unstructured */
if (!translate_eol && q != -1L && isize != q)
{
Trace((mesg, " i=%lu, q=%lu ", isize, q));
zipwarn(" file size changed while zipping ", z->name);
}
#endif /* !TANDEM */
#endif /* !VMS && !CMS_MVS && !__mpexl */
#endif /* (!MSDOS || OS2) */
if (isdir)
{
/* A directory */
z->siz = 0;
z->len = 0;
z->how = STORE;
z->ver = 10;
/* never encrypt directory so don't need extended local header */
z->flg &= ~8;
z->lflg &= ~8;
}
else
{
/* Try to rewrite the local header with correct information */
z->crc = crc;
z->siz = s;
#if CRYPT
if (!isdir && key != NULL)
z->siz += RAND_HEAD_LEN;
#endif /* CRYPT */
z->len = isize;
/* if can seek back to local header */
#ifdef BROKEN_FSEEK
if (use_descriptors || !fseekable(y) || zfseeko(y, z->off, SEEK_SET))
#else
if (use_descriptors || zfseeko(y, z->off, SEEK_SET))
#endif
{
if (z->how != (ush) m)
error("can't rewrite method");
if (m == STORE && q < 0)
ZIPERR(ZE_PARMS, "zip -0 not supported for I/O on pipes or devices");
if ((r = putextended(z)) != ZE_OK)
return r;
/* if Zip64 and not seekable then Zip64 data descriptor */
#ifdef ZIP64_SUPPORT
tempzn += (zip64_entry ? 24L : 16L);
#else
tempzn += 16L;
#endif
z->flg = z->lflg; /* if z->flg modified by deflate */
} else {
/* ftell() not as useful across splits */
if (bytes_this_entry != (uzoff_t)(key ? s + 12 : s)) {
fprintf(mesg, " s=%s, actual=%s ",
zip_fzofft(s, NULL, NULL), zip_fzofft(bytes_this_entry, NULL, NULL));
error("incorrect compressed size");