2
Copyright (c) 1990-2004 Info-ZIP. All rights reserved.
4
See the accompanying file LICENSE, version 2000-Apr-09 or later
5
(the contents of which are also included in unzip.h) for terms of use.
6
If, for some reason, all these files are missing, the Info-ZIP license
7
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
9
/*---------------------------------------------------------------------------
13
AOS/VS-specific routines for use with Info-ZIP's UnZip 5.2 and later.
14
[GRR: copied from unix.c -> undoubtedly has unnecessary stuff: delete at will]
23
version() <-- GRR: needs work! (Unix, not AOS/VS)
29
---------------------------------------------------------------------------*/
32
#define UNZIP_INTERNAL
34
#include "aosvs/aosvs.h"
35
#include <packets/create.h>
36
#include <sys_calls.h>
39
#define symlink(resname,linkname) \
40
zvs_create(linkname,-1L,-1L,-1L,ux_to_vs_name(vs_resname,resname),$FLNK,-1,-1)
48
# include <sys/ndir.h>
58
# define dirent direct
62
static int created_dir; /* used in mapname(), checkdir() */
63
static int renamed_fullpath; /* ditto */
65
static ZEXTRAFLD zzextrafld; /* buffer for extra field containing
66
* ?FSTAT packet & ACL buffer */
67
static char vs_resname[2*$MXPL];
68
static char vs_path[2*$MXPL]; /* buf for AOS/VS pathname */
69
static char Vs_path[512]; /* should be big enough [GRR: ?] */
70
static P_CTIM zztimeblock; /* time block for file creation */
71
static ZVSCREATE_STRU zzcreatepacket; /* packet for sys_create(), any
74
/***************************/
75
/* Strings used in aosvs.c */
76
/***************************/
78
static ZCONST char Far CannotDeleteOldFile[] =
79
"error: cannot delete old %s\n";
80
static ZCONST char Far CannotCreateFile[] = "error: cannot create %s\n";
84
#ifdef NO_DIR /* for AT&T 3B1 */
86
#define opendir(path) fopen(path,"r")
87
#define closedir(dir) fclose(dir)
91
* Apparently originally by Rich Salz.
92
* Cleaned up and modified by James W. Birdsall.
94
struct dirent *readdir(dirp)
97
static struct dirent entry;
103
if (fread(&entry, sizeof (struct dirent), 1, dirp) == 0)
104
return (struct dirent *)NULL;
105
else if (entry.d_ino)
108
} /* end function readdir() */
113
/**********************/
114
/* Function do_wild() */ /* for porting: dir separator; match(ignore_case) */
115
/**********************/
117
char *do_wild(__G__ wildspec)
119
ZCONST char *wildspec; /* only used first time on a given dir */
121
static DIR *wild_dir = (DIR *)NULL;
122
static ZCONST char *wildname;
123
static char *dirname, matchname[FILNAMSIZ];
124
static int notfirstcall=FALSE, have_dirname, dirnamelen;
127
/* Even when we're just returning wildspec, we *always* do so in
128
* matchname[]--calling routine is allowed to append four characters
129
* to the returned string, and wildspec may be a pointer to argv[].
131
if (!notfirstcall) { /* first call: must initialize everything */
134
if (!iswild(wildspec)) {
135
strcpy(matchname, wildspec);
136
have_dirname = FALSE;
141
/* break the wildspec into a directory part and a wildcard filename */
142
if ((wildname = strrchr(wildspec, '/')) == (ZCONST char *)NULL) {
145
have_dirname = FALSE;
148
++wildname; /* point at character after '/' */
149
dirnamelen = wildname - wildspec;
150
if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
151
Info(slide, 0x201, ((char *)slide,
152
"warning: cannot allocate wildcard buffers\n"));
153
strcpy(matchname, wildspec);
154
return matchname; /* but maybe filespec was not a wildcard */
156
strncpy(dirname, wildspec, dirnamelen);
157
dirname[dirnamelen] = '\0'; /* terminate for strcpy below */
161
if ((wild_dir = opendir(dirname)) != (DIR *)NULL) {
162
while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
163
Trace((stderr, "do_wild: readdir returns %s\n",
164
FnFilter1(file->d_name)));
165
if (file->d_name[0] == '.' && wildname[0] != '.')
166
continue; /* Unix: '*' and '?' do not match leading dot */
167
if (match(file->d_name, wildname, 0) && /* 0 == case sens. */
168
/* skip "." and ".." directory entries */
169
strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {
170
Trace((stderr, "do_wild: match() succeeds\n"));
172
strcpy(matchname, dirname);
173
strcpy(matchname+dirnamelen, file->d_name);
175
strcpy(matchname, file->d_name);
179
/* if we get to here directory is exhausted, so close it */
181
wild_dir = (DIR *)NULL;
184
/* return the raw wildspec in case that works (e.g., directory not
185
* searchable, but filespec was not wild and file is readable) */
186
strcpy(matchname, wildspec);
190
/* last time through, might have failed opendir but returned raw wildspec */
191
if (wild_dir == (DIR *)NULL) {
192
notfirstcall = FALSE; /* nothing left to try--reset for new wildspec */
198
/* If we've gotten this far, we've read and matched at least one entry
199
* successfully (in a previous call), so dirname has been copied into
202
while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
203
Trace((stderr, "do_wild: readdir returns %s\n",
204
FnFilter1(file->d_name)));
205
if (file->d_name[0] == '.' && wildname[0] != '.')
206
continue; /* Unix: '*' and '?' do not match leading dot */
207
if (match(file->d_name, wildname, 0)) { /* 0 == don't ignore case */
208
Trace((stderr, "do_wild: match() succeeds\n"));
210
/* strcpy(matchname, dirname); */
211
strcpy(matchname+dirnamelen, file->d_name);
213
strcpy(matchname, file->d_name);
218
closedir(wild_dir); /* have read at least one entry; nothing left */
219
wild_dir = (DIR *)NULL;
220
notfirstcall = FALSE; /* reset for new wildspec */
225
} /* end function do_wild() */
233
/***************************/
234
/* Function open_outfile() */
235
/***************************/
237
int open_outfile(__G) /* return 1 if fail */
240
int errc = 1; /* init to show no success with AOS/VS info */
241
long dmm, ddd, dyy, dhh, dmin, dss;
246
return redirect_outfile(__G)==FALSE;
249
if (stat(G.filename, &G.statbuf) == 0 && unlink(G.filename) < 0) {
250
Info(slide, 0x401, ((char *)slide, LoadFarString(CannotDeleteOldFile),
251
FnFilter1(G.filename)));
255
/*---------------------------------------------------------------------------
256
If the file didn't already exist, we created it earlier. But we just
257
deleted it, which we still had to do in case we are overwriting an exis-
258
ting file. So we must create it now, again, to set the creation time
259
properly. (The creation time is the best functional approximation of
260
the Unix mtime. Really!)
262
If we stored this with an AOS/VS Zip that set the extra field to contain
263
the ?FSTAT packet and the ACL, we should use info from the ?FSTAT call
264
now. Otherwise (or if that fails), we should create anyway as best we
265
can from the normal Zip info.
267
In theory, we should look through an entire series of extra fields that
268
might exist for the same file, but we're not going to bother. If we set
269
up other types of extra fields, or if other environments we run into may
270
add their own stuff to existing entries in Zip files, we'll have to.
272
Note that all the packet types for sys_fstat() are the same size & mostly
273
have the same structure, with some fields being unused, etc. Ditto for
274
sys_create(). Thus, we assume a normal one here, not a dir/cpd or device
275
or IPC file, & make little adjustments as necessary. We will set ACLs
276
later (to reduce the chance of lacking access to what we create now); note
277
that for links the resolution name should be stored in the ACL field (once
278
we get Zip recognizing links OK).
279
---------------------------------------------------------------------------*/
281
if (G.extra_field != NULL) {
282
memcpy((char *) &zzextrafld, G.extra_field, sizeof(zzextrafld));
283
if (!memcmp(ZEXTRA_HEADID, zzextrafld.extra_header_id,
284
sizeof(zzextrafld.extra_header_id)) &&
285
!memcmp(ZEXTRA_SENTINEL, zzextrafld.extra_sentinel),
286
sizeof(zzextrafld.extra_sentinel))
288
zzcreatepacket.norm_create_packet.cftyp_format =
289
zzextrafld.fstat_packet.norm_fstat_packet.styp_format;
290
zzcreatepacket.norm_create_packet.cftyp_entry =
291
zzextrafld.fstat_packet.norm_fstat_packet.styp_type;
293
/* for DIRS/CPDs, the next one will give the hash frame size; for
294
* IPCs it will give the port number */
295
zzcreatepacket.norm_create_packet.ccps =
296
zzextrafld.fstat_packet.norm_fstat_packet.scps;
298
zzcreatepacket.norm_create_packet.ctim = &zztimeblock;
299
zztimeblock.tcth = zzextrafld.fstat_packet.norm_fstat_packet.stch;
301
/* access & modification times default to current */
302
zztimeblock.tath.long_time = zztimeblock.tmth.long_time = -1;
304
/* give it current process's ACL unless link; then give it
306
zzcreatepacket.norm_create_packet.cacp = (char *)(-1);
308
if (zzcreatepacket.norm_create_packet.cftyp_entry == $FLNK)
309
zzcreatepacket.norm_create_packet.cacp = zzextrafld.aclbuf;
311
zzcreatepacket.dir_create_packet.cmsh =
312
zzextrafld.fstat_packet.dir_fstat_packet.scsh;
313
if (zzcreatepacket.norm_create_packet.cftyp_entry != $FCPD) {
314
/* element size for normal files */
315
zzcreatepacket.norm_create_packet.cdel =
316
zzextrafld.fstat_packet.norm_fstat_packet.sdeh;
318
zzcreatepacket.norm_create_packet.cmil =
319
zzextrafld.fstat_packet.norm_fstat_packet.smil;
321
if ((errc = sys_create(ux_to_vs_name(vs_path, G.filename),
322
&zzcreatepacket)) != 0)
323
Info(slide, 0x201, ((char *)slide,
324
"error creating %s with AOS/VS info -\n\
325
will try again with ordinary Zip info\n",
326
FnFilter1(G.filename)));
330
/* do it the hard way if no AOS/VS info was stored or if we had problems */
332
dyy = (G.lrec.last_mod_dos_datetime >> 25) + 1980;
333
dmm = (G.lrec.last_mod_dos_datetime >> 21) & 0x0f;
334
ddd = (G.lrec.last_mod_dos_datetime >> 16) & 0x1f;
335
dhh = (G.lrec.last_mod_dos_datetime >> 11) & 0x1f;
336
dmin = (G.lrec.last_mod_dos_datetime >> 5) & 0x3f;
337
dss = (G.lrec.last_mod_dos_datetime << 1) & 0x3e;
339
if (zvs_create(G.filename, (((ulg)dgdate(dmm, ddd, dyy)) << 16) |
340
(dhh*1800L + dmin*30L + dss/2L), -1L, -1L, (char *) -1, -1, -1, -1))
342
Info(slide, 0x201, ((char *)slide, "error: %s: cannot create\n",
343
FnFilter1(G.filename)));
348
Trace((stderr, "open_outfile: doing fopen(%s) for writing\n",
349
FnFilter1(G.filename)));
350
if ((G.outfile = fopen(G.filename, FOPW)) == (FILE *)NULL) {
351
Info(slide, 0x401, ((char *)slide, LoadFarString(CannotCreateFile),
352
FnFilter1(G.filename)));
355
Trace((stderr, "open_outfile: fopen(%s) for writing succeeded\n",
356
FnFilter1(G.filename)));
359
#ifdef _IOFBF /* make output fully buffered (works just about like write()) */
360
setvbuf(G.outfile, (char *)slide, _IOFBF, WSIZE);
362
setbuf(G.outfile, (char *)slide);
364
#endif /* USE_FWRITE */
367
} /* end function open_outfile() */
373
/**********************/
374
/* Function mapattr() */
375
/**********************/
380
ulg tmp = G.crec.external_file_attributes;
382
G.pInfo->file_attr = 0;
383
/* initialized to 0 for check in "default" branch below... */
385
switch (G.pInfo->hostnum) {
387
tmp = (unsigned)(tmp>>17 & 7); /* Amiga RWE bits */
388
G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
392
if ((tmp & 0xF0000000L) != 0x40000000L)
393
tmp &= 0x01FFFFFFL; /* not a dir, mask all ftype bits */
395
tmp &= 0x41FFFFFFL; /* leave directory bit as set */
404
G.pInfo->file_attr = (unsigned)(tmp >> 16);
405
if (G.pInfo->file_attr != 0 || !G.extra_field) {
408
/* Some (non-Info-ZIP) implementations of Zip for Unix and
409
* VMS (and probably others ??) leave 0 in the upper 16-bit
410
* part of the external_file_attributes field. Instead, they
411
* store file permission attributes in some extra field.
412
* As a work-around, we search for the presence of one of
413
* these extra fields and fall back to the MSDOS compatible
414
* part of external_file_attributes if one of the known
415
* e.f. types has been detected.
416
* Later, we might implement extraction of the permission
417
* bits from the VMS extra field. But for now, the work-around
418
* should be sufficient to provide "readable" extracted files.
419
* (For ASI Unix e.f., an experimental remap from the e.f.
420
* mode value IS already provided!)
424
uch *ef = G.extra_field;
425
unsigned ef_len = G.crec.extra_field_length;
428
while (!r && ef_len >= EB_HEADSIZE) {
430
ebLen = (unsigned)makeword(ef+EB_LEN);
431
if (ebLen > (ef_len - EB_HEADSIZE))
432
/* discoverd some e.f. inconsistency! */
436
if (ebLen >= (EB_ASI_MODE+2)) {
438
(unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
439
/* force stop of loop: */
440
ef_len = (ebLen + EB_HEADSIZE);
443
/* else: fall through! */
445
/* "found nondecypherable e.f. with perm. attr" */
450
ef_len -= (ebLen + EB_HEADSIZE);
451
ef += (ebLen + EB_HEADSIZE);
457
/* all remaining cases: expand MSDOS read-only bit into write perms */
459
/* PKWARE's PKZip for Unix marks entries as FS_FAT_, but stores the
460
* Unix attributes in the upper 16 bits of the external attributes
461
* field, just like Info-ZIP's Zip for Unix. We try to use that
462
* value, after a check for consistency with the MSDOS attribute
465
G.pInfo->file_attr = (unsigned)(tmp >> 16);
472
/* Ensure that DOS subdir bit is set when the entry's name ends
473
* in a '/'. Some third-party Zip programs fail to set the subdir
474
* bit for directory entries.
476
if ((tmp & 0x10) == 0) {
477
extent fnlen = strlen(G.filename);
478
if (fnlen > 0 && G.filename[fnlen-1] == '/')
481
/* read-only bit --> write perms; subdir bit --> dir exec bit */
482
tmp = !(tmp & 1) << 1 | (tmp & 0x10) >> 4;
483
if ((G.pInfo->file_attr & 0700) == (unsigned)(0400 | tmp<<6))
484
/* keep previous G.pInfo->file_attr setting, when its "owner"
485
* part appears to be consistent with DOS attribute flags!
488
G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
490
} /* end switch (host-OS-created-by) */
492
/* for originating systems with no concept of "group," "other," "system": */
493
umask( (int)(tmp=umask(0)) ); /* apply mask to expanded r/w(/x) perms */
494
G.pInfo->file_attr &= ~tmp;
498
} /* end function mapattr() */
504
/************************/
505
/* Function mapname() */
506
/************************/
508
int mapname(__G__ renamed)
513
* MPN_OK - no problem detected
514
* MPN_INF_TRUNC - caution (truncated filename)
515
* MPN_INF_SKIP - info "skip entry" (dir doesn't exist)
516
* MPN_ERR_SKIP - error -> skip entry
517
* MPN_ERR_TOOLONG - error -> path is too long
518
* MPN_NOMEM - error (memory allocation failed) -> skip entry
519
* [also MPN_VOL_LABEL, MPN_CREATED_DIR]
522
char pathcomp[FILNAMSIZ]; /* path-component buffer */
523
char *pp, *cp=(char *)NULL; /* character pointers */
524
char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
525
#ifdef ACORN_FTYPE_NFS
526
char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */
527
RO_extra_block *ef_spark; /* pointer Acorn FTYPE ef block */
529
int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
531
register unsigned workch; /* hold the character being tested */
534
/*---------------------------------------------------------------------------
535
Initialize various pointers and counters and stuff.
536
---------------------------------------------------------------------------*/
538
if (G.pInfo->vollabel)
539
return MPN_VOL_LABEL; /* can't set disk volume labels in Unix */
541
/* can create path as long as not just freshening, or if user told us */
542
G.create_dirs = (!uO.fflag || renamed);
544
created_dir = FALSE; /* not yet */
546
/* user gave full pathname: don't prepend rootpath */
547
renamed_fullpath = (renamed && (*G.filename == '/'));
549
if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM)
550
return MPN_NOMEM; /* initialize path buffer, unless no memory */
552
*pathcomp = '\0'; /* initialize translation buffer */
553
pp = pathcomp; /* point to translation buffer */
554
if (uO.jflag) /* junking directories */
555
cp = (char *)strrchr(G.filename, '/');
556
if (cp == (char *)NULL) /* no '/' or not junking dirs */
557
cp = G.filename; /* point to internal zipfile-member pathname */
559
++cp; /* point to start of last component of path */
561
/*---------------------------------------------------------------------------
562
Begin main loop through characters in filename.
563
---------------------------------------------------------------------------*/
565
while ((workch = (uch)*cp++) != 0) {
568
case '/': /* can assume -j flag not given */
570
if (strcmp(pathcomp, ".") == 0) {
571
/* don't bother appending "./" to the path */
573
} else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
574
/* "../" dir traversal detected, skip over it */
576
killed_ddot = TRUE; /* set "show message" flag */
578
/* when path component is not empty, append it now */
579
if (*pathcomp != '\0' &&
580
((error = checkdir(__G__ pathcomp, APPEND_DIR))
581
& MPN_MASK) > MPN_INF_TRUNC)
583
pp = pathcomp; /* reset conversion buffer for next piece */
584
lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
587
case ';': /* VMS version (or DEC-20 attrib?) */
589
*pp++ = ';'; /* keep for now; remove VMS ";##" */
590
break; /* later, if requested */
592
#ifdef ACORN_FTYPE_NFS
593
case ',': /* NFS filetype extension */
595
*pp++ = ','; /* keep for now; may need to remove */
596
break; /* later, if requested */
600
case ' ': /* change spaces to underscore under */
601
*pp++ = '_'; /* MTS; leave as spaces under Unix */
606
/* allow European characters in filenames: */
607
if (isprint(workch) || (128 <= workch && workch <= 254))
608
*pp++ = (char)workch;
611
} /* end while loop */
613
/* Show warning when stripping insecure "parent dir" path components */
614
if (killed_ddot && QCOND2) {
615
Info(slide, 0, ((char *)slide,
616
"warning: skipped \"../\" path component(s) in %s\n",
617
FnFilter1(G.filename)));
618
if (!(error & ~MPN_MASK))
619
error = (error & MPN_MASK) | PK_WARN;
622
/*---------------------------------------------------------------------------
623
Report if directory was created (and no file to create: filename ended
624
in '/'), check name to be sure it exists, and combine path and name be-
626
---------------------------------------------------------------------------*/
628
if (G.filename[strlen(G.filename) - 1] == '/') {
629
checkdir(__G__ G.filename, GETPATH);
632
Info(slide, 0, ((char *)slide, " creating: %s\n",
633
FnFilter1(G.filename)));
635
/* set dir time (note trailing '/') */
636
return (error & ~MPN_MASK) | MPN_CREATED_DIR;
638
/* dir existed already; don't look for data to extract */
639
return (error & ~MPN_MASK) | MPN_INF_SKIP;
642
*pp = '\0'; /* done with pathcomp: terminate it */
644
/* if not saving them, remove VMS version numbers (appended ";###") */
645
if (!uO.V_flag && lastsemi) {
647
while (isdigit((uch)(*pp)))
649
if (*pp == '\0') /* only digits between ';' and end: nuke */
653
#ifdef ACORN_FTYPE_NFS
654
/* translate Acorn filetype information if asked to do so */
655
if (uO.acorn_nfs_ext &&
656
(ef_spark = (RO_extra_block *)
657
getRISCOSexfield(G.extra_field, G.lrec.extra_field_length))
658
!= (RO_extra_block *)NULL)
660
/* file *must* have a RISC OS extra field */
661
long ft = (long)makelong((ef_spark->loadaddr);
665
while (isxdigit((uch)(*pp))) ++pp;
666
if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */
668
if ((ft & 1<<31)==0) ft=0x000FFD00;
669
sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF);
671
#endif /* ACORN_FTYPE_NFS */
673
if (*pathcomp == '\0') {
674
Info(slide, 1, ((char *)slide, "mapname: conversion of %s failed\n",
675
FnFilter1(G.filename)));
676
return (error & ~MPN_MASK) | MPN_ERR_SKIP;
679
checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
680
checkdir(__G__ G.filename, GETPATH);
684
} /* end function mapname() */
689
#if 0 /*========== NOTES ==========*/
691
extract-to dir: a:path/
692
buildpath: path1/path2/ ... (NULL-terminated)
696
loop over chars in zipfile member name
697
checkdir(path component, COMPONENT | CREATEDIR) --> map as required?
698
(d:/tmp/unzip/) (disk:[tmp.unzip.)
699
(d:/tmp/unzip/jj/) (disk:[tmp.unzip.jj.)
700
(d:/tmp/unzip/jj/temp/) (disk:[tmp.unzip.jj.temp.)
701
finally add filename itself and check for existence? (could use with rename)
702
(d:/tmp/unzip/jj/temp/msg.outdir) (disk:[tmp.unzip.jj.temp]msg.outdir)
703
checkdir(name, GETPATH) --> copy path to name and free space
710
/***********************/
711
/* Function checkdir() */
712
/***********************/
714
int checkdir(__G__ pathcomp, flag)
720
* MPN_OK - no problem detected
721
* MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
722
* MPN_INF_SKIP - path doesn't exist, not allowed to create
723
* MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
724
* exists and is not a directory, but is supposed to be
725
* MPN_ERR_TOOLONG - path is too long
726
* MPN_NOMEM - can't allocate memory for filename buffers
729
static int rootlen = 0; /* length of rootpath */
730
static char *rootpath; /* user's "extract-to" directory */
731
static char *buildpath; /* full path (so far) to extracted file */
732
static char *end; /* pointer to end of buildpath ('\0') */
735
# define FUNCTION (flag & FN_MASK)
738
/*---------------------------------------------------------------------------
739
APPEND_DIR: append the path component to the path being built and check
740
for its existence. If doesn't exist and we are creating directories, do
741
so for this one; else signal success or error as appropriate.
742
---------------------------------------------------------------------------*/
744
if (FUNCTION == APPEND_DIR) {
745
int too_long = FALSE;
750
Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
751
while ((*end = *pathcomp++) != '\0')
753
#ifdef SHORT_NAMES /* path components restricted to 14 chars, typically */
754
if ((end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
755
*(end = old_end + FILENAME_MAX) = '\0';
758
/* GRR: could do better check, see if overrunning buffer as we go:
759
* check end-buildpath after each append, set warning variable if
760
* within 20 of FILNAMSIZ; then if var set, do careful check when
761
* appending. Clear variable when begin new path. */
763
if ((end-buildpath) > FILNAMSIZ-3) /* need '/', one-char name, '\0' */
764
too_long = TRUE; /* check if extracting directory? */
765
/* for AOS/VS, try to create so as to not use searchlist: */
766
if ( /*stat(buildpath, &G.statbuf)*/ 1) {
767
if (!G.create_dirs) { /* told not to create (freshening) */
769
return MPN_INF_SKIP; /* path doesn't exist: nothing to do */
772
Info(slide, 1, ((char *)slide,
773
"checkdir error: path too long: %s\n",
774
FnFilter1(buildpath)));
776
/* no room for filenames: fatal */
777
return MPN_ERR_TOOLONG;
779
/* create the directory */
780
if (zvs_credir(buildpath,-1L,-1L,-1L,(char *) -1,-1,0L,-1,-1) == -1)
782
Info(slide, 1, ((char *)slide,
783
"checkdir error: cannot create %s\n\
784
unable to process %s.\n",
785
FnFilter2(buildpath), FnFilter1(G.filename)));
787
/* path didn't exist, tried to create, failed */
791
} else if (!S_ISDIR(G.statbuf.st_mode)) {
792
Info(slide, 1, ((char *)slide,
793
"checkdir error: %s exists but is not directory\n\
794
unable to process %s.\n",
795
FnFilter2(buildpath), FnFilter1(G.filename)));
797
/* path existed but wasn't dir */
801
Info(slide, 1, ((char *)slide,
802
"checkdir error: path too long: %s\n", FnFilter1(buildpath)));
804
/* no room for filenames: fatal */
805
return MPN_ERR_TOOLONG;
809
Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
812
} /* end if (FUNCTION == APPEND_DIR) */
814
/*---------------------------------------------------------------------------
815
GETPATH: copy full path to the string pointed at by pathcomp, and free
817
---------------------------------------------------------------------------*/
819
if (FUNCTION == GETPATH) {
820
strcpy(pathcomp, buildpath);
821
Trace((stderr, "getting and freeing path [%s]\n",
822
FnFilter1(pathcomp)));
824
buildpath = end = (char *)NULL;
828
/*---------------------------------------------------------------------------
829
APPEND_NAME: assume the path component is the filename; append it and
830
return without checking for existence.
831
---------------------------------------------------------------------------*/
833
if (FUNCTION == APPEND_NAME) {
838
Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
839
while ((*end = *pathcomp++) != '\0') {
841
#ifdef SHORT_NAMES /* truncate name at 14 characters, typically */
842
if ((end-old_end) > FILENAME_MAX) /* GRR: proper constant? */
843
*(end = old_end + FILENAME_MAX) = '\0';
845
if ((end-buildpath) >= FILNAMSIZ) {
847
Info(slide, 1, ((char *)slide,
848
"checkdir warning: path too long; truncating\n\
850
FnFilter1(G.filename), FnFilter2(buildpath)));
851
return MPN_INF_TRUNC; /* filename truncated */
854
Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
855
/* could check for existence here, prompt for new name... */
859
/*---------------------------------------------------------------------------
860
INIT: allocate and initialize buffer space for the file currently being
861
extracted. If file was renamed with an absolute path, don't prepend the
863
---------------------------------------------------------------------------*/
865
/* GRR: for VMS and TOPS-20, add up to 13 to strlen */
867
if (FUNCTION == INIT) {
868
Trace((stderr, "initializing buildpath to "));
869
if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+1))
872
if ((rootlen > 0) && !renamed_fullpath) {
873
strcpy(buildpath, rootpath);
874
end = buildpath + rootlen;
879
Trace((stderr, "[%s]\n", FnFilter1(buildpath)));
883
/*---------------------------------------------------------------------------
884
ROOT: if appropriate, store the path in rootpath and create it if
885
necessary; else assume it's a zipfile member and return. This path
886
segment gets used in extracting all members from every zipfile specified
888
---------------------------------------------------------------------------*/
890
#if (!defined(SFX) || defined(SFX_EXDIR))
891
if (FUNCTION == ROOT) {
892
Trace((stderr, "initializing root path to [%s]\n",
893
FnFilter1(pathcomp)));
894
if (pathcomp == (char *)NULL) {
898
if (rootlen > 0) /* rootpath was already set, nothing to do */
900
if ((rootlen = strlen(pathcomp)) > 0) {
903
if ((tmproot = (char *)malloc(rootlen+2)) == (char *)NULL) {
907
strcpy(tmproot, pathcomp);
908
if (tmproot[rootlen-1] == '/') {
909
tmproot[--rootlen] = '\0';
911
if (rootlen > 0 && (stat(tmproot, &G.statbuf) ||
912
!S_ISDIR(G.statbuf.st_mode)))
913
{ /* path does not exist */
914
if (!G.create_dirs /* || iswild(tmproot) */ ) {
917
/* skip (or treat as stored file) */
920
/* create the directory (could add loop here scanning tmproot
921
* to create more than one level, but why really necessary?) */
922
if (zvs_credir(tmproot,-1L,-1L,-1L,(char *) -1,-1,0L,-1,-1)
925
Info(slide, 1, ((char *)slide,
926
"checkdir: cannot create extraction directory: %s\n",
927
FnFilter1(tmproot)));
930
/* path didn't exist, tried to create, and failed: */
931
/* file exists, or 2+ subdir levels required */
935
tmproot[rootlen++] = '/';
936
tmproot[rootlen] = '\0';
937
if ((rootpath = (char *)realloc(tmproot, rootlen+1)) == NULL) {
942
Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
946
#endif /* !SFX || SFX_EXDIR */
948
/*---------------------------------------------------------------------------
949
END: free rootpath, immediately prior to program exit.
950
---------------------------------------------------------------------------*/
952
if (FUNCTION == END) {
953
Trace((stderr, "freeing rootpath\n"));
961
return MPN_INVALID; /* should never reach */
963
} /* end function checkdir() */
969
/****************************/
970
/* Function close_outfile() */
971
/****************************/
973
void close_outfile(__G) /* GRR: change to return PK-style warning level */
979
/*---------------------------------------------------------------------------
980
If symbolic links are supported, allocate storage for a symlink control
981
structure, put the uncompressed "data" and other required info in it, and
982
add the structure to the "deferred symlinks" chain. Since we know it's a
983
symbolic link to start with, we shouldn't have to worry about overflowing
984
unsigned ints with unsigned longs.
985
---------------------------------------------------------------------------*/
989
unsigned ucsize = (unsigned)G.lrec.ucsize;
990
extent slnk_entrysize = sizeof(slinkentry) + ucsize +
992
slinkentry *slnk_entry;
994
if ((unsigned)slnk_entrysize < ucsize) {
995
Info(slide, 0x201, ((char *)slide,
996
"warning: symbolic link (%s) failed: mem alloc overflow\n",
997
FnFilter1(G.filename)));
1001
if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) {
1002
Info(slide, 0x201, ((char *)slide,
1003
"warning: symbolic link (%s) failed: no mem\n",
1004
FnFilter1(G.filename)));
1007
slnk_entry->next = NULL;
1008
slnk_entry->targetlen = ucsize;
1009
slnk_entry->attriblen = 0; /* don't set attributes for symlinks */
1010
slnk_entry->target = slnk_entry->buf;
1011
slnk_entry->fname = slnk_entry->target + ucsize + 1;
1012
strcpy(slnk_entry->fname, G.filename);
1014
/* reopen the "link data" file for reading */
1015
G.outfile = fopen(G.filename, FOPR);
1018
fread(slnk_entry->target, 1, ucsize, G.outfile) != (int)ucsize)
1020
Info(slide, 0x201, ((char *)slide,
1021
"warning: symbolic link (%s) failed\n",
1022
FnFilter1(G.filename)));
1027
fclose(G.outfile); /* close "link" file for good... */
1028
slnk_entry->target[ucsize] = '\0';
1030
Info(slide, 0, ((char *)slide, "-> %s ",
1031
FnFilter1(slnk_entry->target)));
1032
/* add this symlink record to the list of deferred symlinks */
1033
if (G.slink_last != NULL)
1034
G.slink_last->next = slnk_entry;
1036
G.slink_head = slnk_entry;
1037
G.slink_last = slnk_entry;
1040
#endif /* SYMLINKS */
1042
/*---------------------------------------------------------------------------
1043
Change the file permissions from default ones to those stored in the
1045
---------------------------------------------------------------------------*/
1048
if (chmod(G.filename, 0xffff & G.pInfo->file_attr))
1049
perror("chmod (file attributes) error");
1052
/*---------------------------------------------------------------------------
1053
AOS/VS only allows setting file times at creation but has its own permis-
1054
sions scheme which is better invoked here if the necessary information
1055
was in fact stored. In theory, we should look through an entire series
1056
of extra fields that might exist for the same file, but we're not going
1057
to bother. If we set up other types of extra fields, or if we run into
1058
other environments that add their own stuff to existing entries in ZIP
1059
files, we'll have to. NOTE: already copied extra-field stuff into
1060
zzextrafld structure when file was created.
1061
---------------------------------------------------------------------------*/
1063
if (G.extra_field != NULL) {
1064
if (!memcmp(ZEXTRA_HEADID, zzextrafld.extra_header_id,
1065
sizeof(zzextrafld.extra_header_id)) &&
1066
!memcmp(ZEXTRA_SENTINEL, zzextrafld.extra_sentinel,
1067
sizeof(zzextrafld.extra_sentinel)) &&
1068
zzextrafld.fstat_packet.norm_fstat_packet.styp_type != $FLNK)
1069
/* (AOS/VS links don't have ACLs) */
1071
/* vs_path was set (in this case) when we created the file */
1072
if (sys_sacl(vs_path, zzextrafld.aclbuf)) {
1073
Info(slide, 0x201, ((char *)slide,
1074
"error: cannot set ACL for %s\n", FnFilter1(G.filename)));
1075
perror("sys_sacl()");
1079
} /* end function close_outfile() */
1086
/************************/
1087
/* Function version() */
1088
/************************/
1093
#if (defined(__GNUC__) && defined(NX_CURRENT_COMPILER_RELEASE))
1094
char cc_namebuf[40];
1095
char cc_versbuf[40];
1097
#if (defined(CRAY) && defined(_RELEASE))
1098
char cc_versbuf[40];
1101
#if ((defined(CRAY) || defined(cray)) && defined(_UNICOS))
1102
char os_namebuf[40];
1104
#if defined(__NetBSD__)
1105
char os_namebuf[40];
1109
/* Pyramid, NeXT have problems with huge macro expansion, too: no Info() */
1110
sprintf((char *)slide, LoadFarString(CompiledWith),
1113
# ifdef NX_CURRENT_COMPILER_RELEASE
1114
(sprintf(cc_namebuf, "NeXT DevKit %d.%02d ",
1115
NX_CURRENT_COMPILER_RELEASE/100, NX_CURRENT_COMPILER_RELEASE%100),
1117
(strlen(__VERSION__) > 8)? "(gcc)" :
1118
(sprintf(cc_versbuf, "(gcc %s)", __VERSION__), cc_versbuf),
1120
"gcc ", __VERSION__,
1123
# if defined(CRAY) && defined(_RELEASE)
1124
"cc ", (sprintf(cc_versbuf, "version %d", _RELEASE), cc_versbuf),
1128
# define IZ_CC_NAME "cc "
1130
IZ_CC_NAME, __VERSION__
1133
# define IZ_CC_NAME "cc"
1138
#endif /* ?__GNUC__ */
1141
# define IZ_OS_NAME "Unix"
1145
#if defined(sgi) || defined(__sgi)
1146
" (Silicon Graphics IRIX)",
1151
" (Sun SPARC/Solaris)",
1152
# else /* may or may not be SunOS */
1156
# if defined(sun386) || defined(i386)
1159
# if defined(mc68020) || defined(__mc68020__)
1161
# else /* mc68010 or mc68000: Sun 2 or earlier */
1179
#if defined(CRAY) || defined(cray)
1181
(sprintf(os_namebuf, " (Cray UNICOS release %d)", _UNICOS), os_namebuf),
1186
#if defined(uts) || defined(UTS)
1191
" (NeXTStep/black)",
1193
" (NeXTStep for Intel)",
1195
#else /* the next dozen or so are somewhat order-dependent */
1214
(sprintf(os_namebuf, " (NetBSD 0.8%c)", (char)(NetBSD0_8 - 1 + 'A')),
1218
(sprintf(os_namebuf, " (NetBSD 0.9%c)", (char)(NetBSD0_9 - 1 + 'A')),
1222
(sprintf(os_namebuf, " (NetBSD 1.0%c)", (char)(NetBSD1_0 - 1 + 'A')),
1225
(BSD4_4 == 0.5)? " (NetBSD before 0.9)" : " (NetBSD 1.1 or later)",
1231
(BSD4_4 == 0.5)? " (FreeBSD 1.x)" : " (FreeBSD 2.0 or later)",
1234
(BSD4_4 == 0.5)? " (BSD/386 1.0)" : " (BSD/386 1.1 or later)",
1237
(BSD4_4 == 1)? " (386BSD, post-4.4 release)" : " (386BSD)",
1239
#if defined(i486) || defined(__i486) || defined(__i486__)
1242
#if defined(i386) || defined(__i386) || defined(__i386__)
1254
# else /* __alpha? */
1273
#endif /* Pyramid */
1277
#endif /* BSDI BSD/386 */
1279
#endif /* FreeBSD */
1280
#endif /* SCO Xenix */
1281
#endif /* SCO Unix */
1301
(*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
1303
} /* end function version() */
1311
/* ===================================================================
1313
* Function to create a file with specified times. The times should be sent
1314
* as long ints in DG time format; use -1 to set to the current times. You
1315
* may also specify a pointer to the ACL, the file type (see PARU.H, and do
1316
* not specify dirs or links), the element size, and the max index level.
1317
* For all of these parameters you may use -1 to specify the default.
1319
* Returns 0 if no error, or the error code returned by ?CREATE.
1323
* 31-may-94 dbl: added call to convert pathname to AOS/VS
1328
int zvs_create(ZCONST char *fname, long cretim, long modtim, long acctim,
1329
char *pacl, int ftyp, int eltsize, int maxindlev)
1334
pcr_stru.cftyp_format = 0; /* unspecified record format */
1335
if (ftyp == -1) /* default file type to UNX */
1336
pcr_stru.cftyp_entry = $FUNX;
1338
pcr_stru.cftyp_entry = ftyp;
1339
pcr_stru.ctim = &pct_stru;
1340
pcr_stru.cacp = pacl;
1341
pcr_stru.cdel = eltsize;
1342
pcr_stru.cmil = maxindlev;
1344
pct_stru.tcth.long_time = cretim;
1345
pct_stru.tath.long_time = acctim;
1346
pct_stru.tmth.long_time = modtim;
1348
return (sys_create(ux_to_vs_name(Vs_path, fname), &pcr_stru));
1350
} /* end zvs_create() */
1354
/* ===================================================================
1356
* Function to create a dir as specified. The times should be sent
1357
* as long ints in DG time format; use -1 to set to the current times. You
1358
* may also specify a pointer to the ACL, the file type (either $FDIR or $FCPD; see PARU.H),
1359
* the max # blocks (if a CPD), the hash frame size, and the max index level.
1360
* For all of these parameters (except for the CPD's maximum blocks),
1361
* you may use -1 to specify the default.
1363
* (The System Call Dictionary says both that you may specify a
1364
* maximum-index-level value up to the maximum, with 0 for a contiguous
1365
* directory, and that 3 is always used for this whatever you specify.)
1367
* If you specify anything other than CPD for the file type, DIR will
1370
* Returns 0 if no error, or the error code returned by ?CREATE.
1378
int zvs_credir(ZCONST char *dname, long cretim, long modtim, long acctim,
1379
char *pacl, int ftyp, long maxblocks, int hashfsize,
1382
P_CREATE_DIR pcr_stru;
1385
if (ftyp != $FCPD) /* default file type to UNX */
1386
pcr_stru.cftyp_entry = $FDIR;
1389
pcr_stru.cftyp_entry = ftyp;
1390
pcr_stru.cmsh = maxblocks;
1393
pcr_stru.ctim = &pct_stru;
1394
pcr_stru.cacp = pacl;
1395
pcr_stru.chfs = hashfsize;
1396
pcr_stru.cmil = maxindlev;
1398
pct_stru.tcth.long_time = cretim;
1399
pct_stru.tath.long_time = acctim;
1400
pct_stru.tmth.long_time = modtim;
1402
return (sys_create(ux_to_vs_name(Vs_path, dname), &pcr_stru));
1404
} /* end zvs_credir() */
1408
/* ===================================================================
1409
* UX_TO_VS_NAME() - makes a somewhat dumb pass at converting a Unix
1410
* filename to an AOS/VS filename. This should
1411
* be just about adequate to handle the results
1412
* of similarly-simple AOS/VS-to-Unix conversions
1413
* in the ZIP program. It does not guarantee a
1414
* legal AOS/VS filename for every Unix filename;
1415
* conspicuous examples would be names with
1416
* embedded ./ and ../ (which will receive no
1417
* special treatment).
1419
* RETURNS: pointer to the result (which is an input parameter)
1421
* NOTE: calling code is responsible for making sure
1422
* the output buffer is big enough!
1428
char *ux_to_vs_name(char *outname, ZCONST char *inname)
1430
ZCONST char *ip=inname, *op=outname;
1437
} else if (ip[1] == '.' && ip[2] == '/') {
1447
"0123456789_$?.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
1454
} while (*(ip++) != '\0');
1458
} /* end ux_to_vs_name() */
1462
/* =================================================================== */
1465
Two functions do encode/decode dates in DG system format.
1468
long value,year,month,day;
1470
value=dgdate(month,day,year);
1471
undgdate(value,&month,&day,&year); [GRR: not used in UnZip: removed]
1475
1. DG date functions only work on dates within the range
1476
Jan 1, 1968 through Dec 31, 2099. I have tested these
1477
functions through the same range with exact agreement.
1478
For dates outside of that range, the DG system calls
1479
may return different values than these functions.
1481
2. dgundate() accepts values between 0 and 48213 inclusive.
1482
These correspond to 12/31/1967 and 12/31/2099.
1484
3. Both functions assume the data is in the native OS byte
1485
order. So if you're reading or writing these fields from
1486
a file that has been passed between AOS/VS and PC-DOS you
1487
will need to swap byte order.
1489
4. With reference to byte order, the entire range of values
1490
supported by these functions will fit into an unsigned
1491
short int. In most cases the input or output will be
1492
in that variable type. You are better off casting the
1493
value to/from unsigned short so you only need to concern
1494
yourself with swapping two bytes instead of four.
1496
Written by: Stanley J. Gula
1498
529 Main Street, Suite 1
1499
Indian Orchard, MA 01151
1501
Copyright (c) 1990 US&T, Inc.
1502
All rights reserved.
1504
I hereby release these functions into the public
1505
domain. You may use these routines freely as long
1506
as the US&T copyright remains intact in the source
1509
Stanley J. Gula July 24, 1990
1512
long motable[13]={0,31,59,90,120,151,181,212,243,273,304,334,365};
1515
366, 731, 1096, 1461, 1827, 2192, 2557, 2922, 3288, 3653,
1516
4018, 4383, 4749, 5114, 5479, 5844, 6210, 6575, 6940, 7305,
1517
7671, 8036, 8401, 8766, 9132, 9497, 9862,10227,10593,10958,
1518
11323,11688,12054,12419,12784,13149,13515,13880,14245,14610,
1519
14976,15341,15706,16071,16437,16802,17167,17532,17898,18263,
1520
18628,18993,19359,19724,20089,20454,20820,21185,21550,21915,
1521
22281,22646,23011,23376,23742,24107,24472,24837,25203,25568,
1522
25933,26298,26664,27029,27394,27759,28125,28490,28855,29220,
1523
29586,29951,30316,30681,31047,31412,31777,32142,32508,32873,
1524
33238,33603,33969,34334,34699,35064,35430,35795,36160,36525,
1525
36891,37256,37621,37986,38352,38717,39082,39447,39813,40178,
1526
40543,40908,41274,41639,42004,42369,42735,43100,43465,43830,
1527
44196,44561,44926,45291,45657,46022,46387,46752,47118,47483,
1530
/* Given y,m,d return # of days since 12/31/67 */
1531
long int dgdate(short mm, short dd, short yy)
1536
if (mm<1 || mm>12 || dd<1 || dd>31 || yy<1968 || yy>2099)
1539
/* Figure in whole years since 1968 + whole months plus days */
1540
temp=365L*(long)(yy-1968) + motable[mm-1] + (long)dd;
1542
/* Adjust for leap years - note we don't account for skipped leap
1543
year in years divisible by 1000 but not by 4000. We're correct
1544
through the year 2099 */
1547
/* Correct for this year */
1548
/* In leap years, if date is 3/1 or later, bump */
1549
if ((yy%4==0) && (mm>2))