~ubuntu-branches/ubuntu/precise/unzip/precise-proposed

« back to all changes in this revision

Viewing changes to aosvs/aosvs.c

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2004-06-06 17:57:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040606175746-nl7p2dgp3aobyc2c
Tags: upstream-5.51
ImportĀ upstreamĀ versionĀ 5.51

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (c) 1990-2004 Info-ZIP.  All rights reserved.
 
3
 
 
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
 
8
*/
 
9
/*---------------------------------------------------------------------------
 
10
 
 
11
  aosvs.c
 
12
 
 
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]
 
15
 
 
16
  Contains:  readdir()
 
17
             do_wild()
 
18
             open_outfile()
 
19
             mapattr()
 
20
             mapname()
 
21
             checkdir()
 
22
             close_outfile()
 
23
             version()             <-- GRR:  needs work!  (Unix, not AOS/VS)
 
24
             zvs_create()
 
25
             zvs_credir()
 
26
             ux_to_vs_name()
 
27
             dgdate()
 
28
 
 
29
  ---------------------------------------------------------------------------*/
 
30
 
 
31
 
 
32
#define UNZIP_INTERNAL
 
33
#include "unzip.h"
 
34
#include "aosvs/aosvs.h"
 
35
#include <packets/create.h>
 
36
#include <sys_calls.h>
 
37
#include <paru.h>
 
38
 
 
39
#define symlink(resname,linkname) \
 
40
  zvs_create(linkname,-1L,-1L,-1L,ux_to_vs_name(vs_resname,resname),$FLNK,-1,-1)
 
41
                                             *  file type */
 
42
 
 
43
#ifdef DIRENT
 
44
#  include <dirent.h>
 
45
#else
 
46
#  ifdef SYSV
 
47
#    ifdef SYSNDIR
 
48
#      include <sys/ndir.h>
 
49
#    else
 
50
#      include <ndir.h>
 
51
#    endif
 
52
#  else /* !SYSV */
 
53
#    ifndef NO_SYSDIR
 
54
#      include <sys/dir.h>
 
55
#    endif
 
56
#  endif /* ?SYSV */
 
57
#  ifndef dirent
 
58
#    define dirent direct
 
59
#  endif
 
60
#endif /* ?DIRENT */
 
61
 
 
62
static int            created_dir;          /* used in mapname(), checkdir() */
 
63
static int            renamed_fullpath;     /* ditto */
 
64
 
 
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
 
72
 
 
73
 
 
74
/***************************/
 
75
/* Strings used in aosvs.c */
 
76
/***************************/
 
77
 
 
78
static ZCONST char Far CannotDeleteOldFile[] =
 
79
  "error:  cannot delete old %s\n";
 
80
static ZCONST char Far CannotCreateFile[] = "error:  cannot create %s\n";
 
81
 
 
82
 
 
83
#ifndef SFX
 
84
#ifdef NO_DIR                  /* for AT&T 3B1 */
 
85
 
 
86
#define opendir(path) fopen(path,"r")
 
87
#define closedir(dir) fclose(dir)
 
88
typedef FILE DIR;
 
89
 
 
90
/*
 
91
 *  Apparently originally by Rich Salz.
 
92
 *  Cleaned up and modified by James W. Birdsall.
 
93
 */
 
94
struct dirent *readdir(dirp)
 
95
    DIR *dirp;
 
96
{
 
97
    static struct dirent entry;
 
98
 
 
99
    if (dirp == NULL)
 
100
        return NULL;
 
101
 
 
102
    for (;;)
 
103
        if (fread(&entry, sizeof (struct dirent), 1, dirp) == 0)
 
104
            return (struct dirent *)NULL;
 
105
        else if (entry.d_ino)
 
106
            return &entry;
 
107
 
 
108
} /* end function readdir() */
 
109
 
 
110
#endif /* NO_DIR */
 
111
 
 
112
 
 
113
/**********************/
 
114
/* Function do_wild() */   /* for porting:  dir separator; match(ignore_case) */
 
115
/**********************/
 
116
 
 
117
char *do_wild(__G__ wildspec)
 
118
    __GDEF
 
119
    ZCONST char *wildspec;  /* only used first time on a given dir */
 
120
{
 
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;
 
125
    struct dirent *file;
 
126
 
 
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[].
 
130
     */
 
131
    if (!notfirstcall) {    /* first call:  must initialize everything */
 
132
        notfirstcall = TRUE;
 
133
 
 
134
        if (!iswild(wildspec)) {
 
135
            strcpy(matchname, wildspec);
 
136
            have_dirname = FALSE;
 
137
            dir = NULL;
 
138
            return matchname;
 
139
        }
 
140
 
 
141
        /* break the wildspec into a directory part and a wildcard filename */
 
142
        if ((wildname = strrchr(wildspec, '/')) == (ZCONST char *)NULL) {
 
143
            dirname = ".";
 
144
            dirnamelen = 1;
 
145
            have_dirname = FALSE;
 
146
            wildname = wildspec;
 
147
        } else {
 
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 */
 
155
            }
 
156
            strncpy(dirname, wildspec, dirnamelen);
 
157
            dirname[dirnamelen] = '\0';   /* terminate for strcpy below */
 
158
            have_dirname = TRUE;
 
159
        }
 
160
 
 
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"));
 
171
                    if (have_dirname) {
 
172
                        strcpy(matchname, dirname);
 
173
                        strcpy(matchname+dirnamelen, file->d_name);
 
174
                    } else
 
175
                        strcpy(matchname, file->d_name);
 
176
                    return matchname;
 
177
                }
 
178
            }
 
179
            /* if we get to here directory is exhausted, so close it */
 
180
            closedir(wild_dir);
 
181
            wild_dir = (DIR *)NULL;
 
182
        }
 
183
 
 
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);
 
187
        return matchname;
 
188
    }
 
189
 
 
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 */
 
193
        if (have_dirname)
 
194
            free(dirname);
 
195
        return (char *)NULL;
 
196
    }
 
197
 
 
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
 
200
     * matchname already.
 
201
     */
 
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"));
 
209
            if (have_dirname) {
 
210
                /* strcpy(matchname, dirname); */
 
211
                strcpy(matchname+dirnamelen, file->d_name);
 
212
            } else
 
213
                strcpy(matchname, file->d_name);
 
214
            return matchname;
 
215
        }
 
216
    }
 
217
 
 
218
    closedir(wild_dir);     /* have read at least one entry; nothing left */
 
219
    wild_dir = (DIR *)NULL;
 
220
    notfirstcall = FALSE;   /* reset for new wildspec */
 
221
    if (have_dirname)
 
222
        free(dirname);
 
223
    return (char *)NULL;
 
224
 
 
225
} /* end function do_wild() */
 
226
 
 
227
#endif /* !SFX */
 
228
 
 
229
 
 
230
 
 
231
 
 
232
 
 
233
/***************************/
 
234
/* Function open_outfile() */
 
235
/***************************/
 
236
 
 
237
int open_outfile(__G)         /* return 1 if fail */
 
238
    __GDEF
 
239
{
 
240
    int errc = 1;    /* init to show no success with AOS/VS info */
 
241
    long dmm, ddd, dyy, dhh, dmin, dss;
 
242
 
 
243
 
 
244
#ifdef DLL
 
245
    if (G.redirect_data)
 
246
        return redirect_outfile(__G)==FALSE;
 
247
#endif
 
248
 
 
249
    if (stat(G.filename, &G.statbuf) == 0 && unlink(G.filename) < 0) {
 
250
        Info(slide, 0x401, ((char *)slide, LoadFarString(CannotDeleteOldFile),
 
251
          FnFilter1(G.filename)));
 
252
        return 1;
 
253
    }
 
254
 
 
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!)
 
261
 
 
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.
 
266
 
 
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.
 
271
 
 
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
  ---------------------------------------------------------------------------*/
 
280
 
 
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))
 
287
        {
 
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;
 
292
 
 
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;
 
297
 
 
298
            zzcreatepacket.norm_create_packet.ctim = &zztimeblock;
 
299
            zztimeblock.tcth = zzextrafld.fstat_packet.norm_fstat_packet.stch;
 
300
 
 
301
            /* access & modification times default to current */
 
302
            zztimeblock.tath.long_time = zztimeblock.tmth.long_time = -1;
 
303
 
 
304
            /* give it current process's ACL unless link; then give it
 
305
             * resolution name */
 
306
            zzcreatepacket.norm_create_packet.cacp = (char *)(-1);
 
307
 
 
308
            if (zzcreatepacket.norm_create_packet.cftyp_entry == $FLNK)
 
309
                zzcreatepacket.norm_create_packet.cacp = zzextrafld.aclbuf;
 
310
 
 
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;
 
317
            }
 
318
            zzcreatepacket.norm_create_packet.cmil =
 
319
              zzextrafld.fstat_packet.norm_fstat_packet.smil;
 
320
 
 
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)));
 
327
        }
 
328
    }
 
329
 
 
330
    /* do it the hard way if no AOS/VS info was stored or if we had problems */
 
331
    if (errc) {
 
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;
 
338
 
 
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))
 
341
        {
 
342
            Info(slide, 0x201, ((char *)slide, "error: %s: cannot create\n",
 
343
              FnFilter1(G.filename)));
 
344
            return 1;
 
345
        }
 
346
    }
 
347
 
 
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)));
 
353
        return 1;
 
354
    }
 
355
    Trace((stderr, "open_outfile:  fopen(%s) for writing succeeded\n",
 
356
      FnFilter1(G.filename)));
 
357
 
 
358
#ifdef USE_FWRITE
 
359
#ifdef _IOFBF  /* make output fully buffered (works just about like write()) */
 
360
    setvbuf(G.outfile, (char *)slide, _IOFBF, WSIZE);
 
361
#else
 
362
    setbuf(G.outfile, (char *)slide);
 
363
#endif
 
364
#endif /* USE_FWRITE */
 
365
    return 0;
 
366
 
 
367
} /* end function open_outfile() */
 
368
 
 
369
 
 
370
 
 
371
 
 
372
 
 
373
/**********************/
 
374
/* Function mapattr() */
 
375
/**********************/
 
376
 
 
377
int mapattr(__G)
 
378
    __GDEF
 
379
{
 
380
    ulg tmp = G.crec.external_file_attributes;
 
381
 
 
382
    G.pInfo->file_attr = 0;
 
383
    /* initialized to 0 for check in "default" branch below... */
 
384
 
 
385
    switch (G.pInfo->hostnum) {
 
386
        case AMIGA_:
 
387
            tmp = (unsigned)(tmp>>17 & 7);   /* Amiga RWE bits */
 
388
            G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
 
389
            break;
 
390
        case THEOS_:
 
391
            tmp &= 0xF1FFFFFFL;
 
392
            if ((tmp & 0xF0000000L) != 0x40000000L)
 
393
                tmp &= 0x01FFFFFFL;     /* not a dir, mask all ftype bits */
 
394
            else
 
395
                tmp &= 0x41FFFFFFL;     /* leave directory bit as set */
 
396
            /* fall through! */
 
397
        case UNIX_:
 
398
        case VMS_:
 
399
        case ACORN_:
 
400
        case ATARI_:
 
401
        case BEOS_:
 
402
        case QDOS_:
 
403
        case TANDEM_:
 
404
            G.pInfo->file_attr = (unsigned)(tmp >> 16);
 
405
            if (G.pInfo->file_attr != 0 || !G.extra_field) {
 
406
                return 0;
 
407
            } else {
 
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!)
 
421
                 */
 
422
                ush ebID;
 
423
                unsigned ebLen;
 
424
                uch *ef = G.extra_field;
 
425
                unsigned ef_len = G.crec.extra_field_length;
 
426
                int r = FALSE;
 
427
 
 
428
                while (!r && ef_len >= EB_HEADSIZE) {
 
429
                    ebID = makeword(ef);
 
430
                    ebLen = (unsigned)makeword(ef+EB_LEN);
 
431
                    if (ebLen > (ef_len - EB_HEADSIZE))
 
432
                        /* discoverd some e.f. inconsistency! */
 
433
                        break;
 
434
                    switch (ebID) {
 
435
                      case EF_ASIUNIX:
 
436
                        if (ebLen >= (EB_ASI_MODE+2)) {
 
437
                            G.pInfo->file_attr =
 
438
                              (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
 
439
                            /* force stop of loop: */
 
440
                            ef_len = (ebLen + EB_HEADSIZE);
 
441
                            break;
 
442
                        }
 
443
                        /* else: fall through! */
 
444
                      case EF_PKVMS:
 
445
                        /* "found nondecypherable e.f. with perm. attr" */
 
446
                        r = TRUE;
 
447
                      default:
 
448
                        break;
 
449
                    }
 
450
                    ef_len -= (ebLen + EB_HEADSIZE);
 
451
                    ef += (ebLen + EB_HEADSIZE);
 
452
                }
 
453
                if (!r)
 
454
                    return 0;
 
455
            }
 
456
            /* fall through! */
 
457
        /* all remaining cases:  expand MSDOS read-only bit into write perms */
 
458
        case FS_FAT_:
 
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
 
463
             * bits (see below).
 
464
             */
 
465
            G.pInfo->file_attr = (unsigned)(tmp >> 16);
 
466
            /* fall through! */
 
467
        case FS_HPFS_:
 
468
        case FS_NTFS_:
 
469
        case MAC_:
 
470
        case TOPS20_:
 
471
        default:
 
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.
 
475
             */
 
476
            if ((tmp & 0x10) == 0) {
 
477
                extent fnlen = strlen(G.filename);
 
478
                if (fnlen > 0 && G.filename[fnlen-1] == '/')
 
479
                    tmp |= 0x10;
 
480
            }
 
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!
 
486
                 */
 
487
                return 0;
 
488
            G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
 
489
            break;
 
490
    } /* end switch (host-OS-created-by) */
 
491
 
 
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;
 
495
 
 
496
    return 0;
 
497
 
 
498
} /* end function mapattr() */
 
499
 
 
500
 
 
501
 
 
502
 
 
503
 
 
504
/************************/
 
505
/*  Function mapname()  */
 
506
/************************/
 
507
 
 
508
int mapname(__G__ renamed)
 
509
    __GDEF
 
510
    int renamed;
 
511
/*
 
512
 * returns:
 
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]
 
520
 */
 
521
{
 
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 */
 
528
#endif
 
529
    int killed_ddot = FALSE;       /* is set when skipping "../" pathcomp */
 
530
    int error = MPN_OK;
 
531
    register unsigned workch;      /* hold the character being tested */
 
532
 
 
533
 
 
534
/*---------------------------------------------------------------------------
 
535
    Initialize various pointers and counters and stuff.
 
536
  ---------------------------------------------------------------------------*/
 
537
 
 
538
    if (G.pInfo->vollabel)
 
539
        return MPN_VOL_LABEL;   /* can't set disk volume labels in Unix */
 
540
 
 
541
    /* can create path as long as not just freshening, or if user told us */
 
542
    G.create_dirs = (!uO.fflag || renamed);
 
543
 
 
544
    created_dir = FALSE;        /* not yet */
 
545
 
 
546
    /* user gave full pathname:  don't prepend rootpath */
 
547
    renamed_fullpath = (renamed && (*G.filename == '/'));
 
548
 
 
549
    if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM)
 
550
        return MPN_NOMEM;       /* initialize path buffer, unless no memory */
 
551
 
 
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 */
 
558
    else
 
559
        ++cp;                   /* point to start of last component of path */
 
560
 
 
561
/*---------------------------------------------------------------------------
 
562
    Begin main loop through characters in filename.
 
563
  ---------------------------------------------------------------------------*/
 
564
 
 
565
    while ((workch = (uch)*cp++) != 0) {
 
566
 
 
567
        switch (workch) {
 
568
            case '/':             /* can assume -j flag not given */
 
569
                *pp = '\0';
 
570
                if (strcmp(pathcomp, ".") == 0) {
 
571
                    /* don't bother appending "./" to the path */
 
572
                    *pathcomp = '\0';
 
573
                } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
 
574
                    /* "../" dir traversal detected, skip over it */
 
575
                    *pathcomp = '\0';
 
576
                    killed_ddot = TRUE;     /* set "show message" flag */
 
577
                }
 
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)
 
582
                    return error;
 
583
                pp = pathcomp;    /* reset conversion buffer for next piece */
 
584
                lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
 
585
                break;
 
586
 
 
587
            case ';':             /* VMS version (or DEC-20 attrib?) */
 
588
                lastsemi = pp;
 
589
                *pp++ = ';';      /* keep for now; remove VMS ";##" */
 
590
                break;            /*  later, if requested */
 
591
 
 
592
#ifdef ACORN_FTYPE_NFS
 
593
            case ',':             /* NFS filetype extension */
 
594
                lastcomma = pp;
 
595
                *pp++ = ',';      /* keep for now; may need to remove */
 
596
                break;            /*  later, if requested */
 
597
#endif
 
598
 
 
599
#ifdef MTS
 
600
            case ' ':             /* change spaces to underscore under */
 
601
                *pp++ = '_';      /*  MTS; leave as spaces under Unix */
 
602
                break;
 
603
#endif
 
604
 
 
605
            default:
 
606
                /* allow European characters in filenames: */
 
607
                if (isprint(workch) || (128 <= workch && workch <= 254))
 
608
                    *pp++ = (char)workch;
 
609
        } /* end switch */
 
610
 
 
611
    } /* end while loop */
 
612
 
 
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;
 
620
    }
 
621
 
 
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-
 
625
    fore exiting.
 
626
  ---------------------------------------------------------------------------*/
 
627
 
 
628
    if (G.filename[strlen(G.filename) - 1] == '/') {
 
629
        checkdir(__G__ G.filename, GETPATH);
 
630
        if (created_dir) {
 
631
            if (QCOND2) {
 
632
                Info(slide, 0, ((char *)slide, "   creating: %s\n",
 
633
                  FnFilter1(G.filename)));
 
634
            }
 
635
            /* set dir time (note trailing '/') */
 
636
            return (error & ~MPN_MASK) | MPN_CREATED_DIR;
 
637
        }
 
638
        /* dir existed already; don't look for data to extract */
 
639
        return (error & ~MPN_MASK) | MPN_INF_SKIP;
 
640
    }
 
641
 
 
642
    *pp = '\0';                   /* done with pathcomp:  terminate it */
 
643
 
 
644
    /* if not saving them, remove VMS version numbers (appended ";###") */
 
645
    if (!uO.V_flag && lastsemi) {
 
646
        pp = lastsemi + 1;
 
647
        while (isdigit((uch)(*pp)))
 
648
            ++pp;
 
649
        if (*pp == '\0')          /* only digits between ';' and end:  nuke */
 
650
            *lastsemi = '\0';
 
651
    }
 
652
 
 
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)
 
659
    {
 
660
        /* file *must* have a RISC OS extra field */
 
661
        long ft = (long)makelong((ef_spark->loadaddr);
 
662
        /*32-bit*/
 
663
        if (lastcomma) {
 
664
            pp = lastcomma + 1;
 
665
            while (isxdigit((uch)(*pp))) ++pp;
 
666
            if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */
 
667
        }
 
668
        if ((ft & 1<<31)==0) ft=0x000FFD00;
 
669
        sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF);
 
670
    }
 
671
#endif /* ACORN_FTYPE_NFS */
 
672
 
 
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;
 
677
    }
 
678
 
 
679
    checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
 
680
    checkdir(__G__ G.filename, GETPATH);
 
681
 
 
682
    return error;
 
683
 
 
684
} /* end function mapname() */
 
685
 
 
686
 
 
687
 
 
688
 
 
689
#if 0  /*========== NOTES ==========*/
 
690
 
 
691
  extract-to dir:      a:path/
 
692
  buildpath:           path1/path2/ ...   (NULL-terminated)
 
693
  pathcomp:                filename
 
694
 
 
695
  mapname():
 
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
 
704
 
 
705
#endif /* 0 */
 
706
 
 
707
 
 
708
 
 
709
 
 
710
/***********************/
 
711
/* Function checkdir() */
 
712
/***********************/
 
713
 
 
714
int checkdir(__G__ pathcomp, flag)
 
715
    __GDEF
 
716
    char *pathcomp;
 
717
    int flag;
 
718
/*
 
719
 * returns:
 
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
 
727
 */
 
728
{
 
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') */
 
733
 
 
734
#   define FN_MASK   7
 
735
#   define FUNCTION  (flag & FN_MASK)
 
736
 
 
737
 
 
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
  ---------------------------------------------------------------------------*/
 
743
 
 
744
    if (FUNCTION == APPEND_DIR) {
 
745
        int too_long = FALSE;
 
746
#ifdef SHORT_NAMES
 
747
        char *old_end = end;
 
748
#endif
 
749
 
 
750
        Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
 
751
        while ((*end = *pathcomp++) != '\0')
 
752
            ++end;
 
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';
 
756
#endif
 
757
 
 
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. */
 
762
 
 
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) */
 
768
                free(buildpath);
 
769
                return MPN_INF_SKIP;    /* path doesn't exist: nothing to do */
 
770
            }
 
771
            if (too_long) {
 
772
                Info(slide, 1, ((char *)slide,
 
773
                  "checkdir error:  path too long: %s\n",
 
774
                  FnFilter1(buildpath)));
 
775
                free(buildpath);
 
776
                /* no room for filenames:  fatal */
 
777
                return MPN_ERR_TOOLONG;
 
778
            }
 
779
            /* create the directory */
 
780
            if (zvs_credir(buildpath,-1L,-1L,-1L,(char *) -1,-1,0L,-1,-1) == -1)
 
781
            {
 
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)));
 
786
                free(buildpath);
 
787
                /* path didn't exist, tried to create, failed */
 
788
                return MPN_ERR_SKIP;
 
789
            }
 
790
            created_dir = TRUE;
 
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)));
 
796
            free(buildpath);
 
797
            /* path existed but wasn't dir */
 
798
            return MPN_ERR_SKIP;
 
799
        }
 
800
        if (too_long) {
 
801
            Info(slide, 1, ((char *)slide,
 
802
              "checkdir error:  path too long: %s\n", FnFilter1(buildpath)));
 
803
            free(buildpath);
 
804
            /* no room for filenames:  fatal */
 
805
            return MPN_ERR_TOOLONG;
 
806
        }
 
807
        *end++ = '/';
 
808
        *end = '\0';
 
809
        Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
 
810
        return MPN_OK;
 
811
 
 
812
    } /* end if (FUNCTION == APPEND_DIR) */
 
813
 
 
814
/*---------------------------------------------------------------------------
 
815
    GETPATH:  copy full path to the string pointed at by pathcomp, and free
 
816
    buildpath.
 
817
  ---------------------------------------------------------------------------*/
 
818
 
 
819
    if (FUNCTION == GETPATH) {
 
820
        strcpy(pathcomp, buildpath);
 
821
        Trace((stderr, "getting and freeing path [%s]\n",
 
822
          FnFilter1(pathcomp)));
 
823
        free(buildpath);
 
824
        buildpath = end = (char *)NULL;
 
825
        return MPN_OK;
 
826
    }
 
827
 
 
828
/*---------------------------------------------------------------------------
 
829
    APPEND_NAME:  assume the path component is the filename; append it and
 
830
    return without checking for existence.
 
831
  ---------------------------------------------------------------------------*/
 
832
 
 
833
    if (FUNCTION == APPEND_NAME) {
 
834
#ifdef SHORT_NAMES
 
835
        char *old_end = end;
 
836
#endif
 
837
 
 
838
        Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
 
839
        while ((*end = *pathcomp++) != '\0') {
 
840
            ++end;
 
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';
 
844
#endif
 
845
            if ((end-buildpath) >= FILNAMSIZ) {
 
846
                *--end = '\0';
 
847
                Info(slide, 1, ((char *)slide,
 
848
                  "checkdir warning:  path too long; truncating\n\
 
849
                   %s\n                -> %s\n",
 
850
                  FnFilter1(G.filename), FnFilter2(buildpath)));
 
851
                return MPN_INF_TRUNC;   /* filename truncated */
 
852
            }
 
853
        }
 
854
        Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
 
855
        /* could check for existence here, prompt for new name... */
 
856
        return MPN_OK;
 
857
    }
 
858
 
 
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
 
862
    extract-to path.
 
863
  ---------------------------------------------------------------------------*/
 
864
 
 
865
/* GRR:  for VMS and TOPS-20, add up to 13 to strlen */
 
866
 
 
867
    if (FUNCTION == INIT) {
 
868
        Trace((stderr, "initializing buildpath to "));
 
869
        if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+1))
 
870
            == (char *)NULL)
 
871
            return MPN_NOMEM;
 
872
        if ((rootlen > 0) && !renamed_fullpath) {
 
873
            strcpy(buildpath, rootpath);
 
874
            end = buildpath + rootlen;
 
875
        } else {
 
876
            *buildpath = '\0';
 
877
            end = buildpath;
 
878
        }
 
879
        Trace((stderr, "[%s]\n", FnFilter1(buildpath)));
 
880
        return MPN_OK;
 
881
    }
 
882
 
 
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
 
887
    on the command line.
 
888
  ---------------------------------------------------------------------------*/
 
889
 
 
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) {
 
895
            rootlen = 0;
 
896
            return MPN_OK;
 
897
        }
 
898
        if (rootlen > 0)        /* rootpath was already set, nothing to do */
 
899
            return MPN_OK;
 
900
        if ((rootlen = strlen(pathcomp)) > 0) {
 
901
            char *tmproot;
 
902
 
 
903
            if ((tmproot = (char *)malloc(rootlen+2)) == (char *)NULL) {
 
904
                rootlen = 0;
 
905
                return MPN_NOMEM;
 
906
            }
 
907
            strcpy(tmproot, pathcomp);
 
908
            if (tmproot[rootlen-1] == '/') {
 
909
                tmproot[--rootlen] = '\0';
 
910
            }
 
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) */ ) {
 
915
                    free(tmproot);
 
916
                    rootlen = 0;
 
917
                    /* skip (or treat as stored file) */
 
918
                    return MPN_INF_SKIP;
 
919
                }
 
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)
 
923
                    == -1)
 
924
                {
 
925
                    Info(slide, 1, ((char *)slide,
 
926
                      "checkdir:  cannot create extraction directory: %s\n",
 
927
                      FnFilter1(tmproot)));
 
928
                    free(tmproot);
 
929
                    rootlen = 0;
 
930
                    /* path didn't exist, tried to create, and failed: */
 
931
                    /* file exists, or 2+ subdir levels required */
 
932
                    return MPN_ERR_SKIP;
 
933
                }
 
934
            }
 
935
            tmproot[rootlen++] = '/';
 
936
            tmproot[rootlen] = '\0';
 
937
            if ((rootpath = (char *)realloc(tmproot, rootlen+1)) == NULL) {
 
938
                free(tmproot);
 
939
                rootlen = 0;
 
940
                return MPN_NOMEM;
 
941
            }
 
942
            Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
 
943
        }
 
944
        return MPN_OK;
 
945
    }
 
946
#endif /* !SFX || SFX_EXDIR */
 
947
 
 
948
/*---------------------------------------------------------------------------
 
949
    END:  free rootpath, immediately prior to program exit.
 
950
  ---------------------------------------------------------------------------*/
 
951
 
 
952
    if (FUNCTION == END) {
 
953
        Trace((stderr, "freeing rootpath\n"));
 
954
        if (rootlen > 0) {
 
955
            free(rootpath);
 
956
            rootlen = 0;
 
957
        }
 
958
        return MPN_OK;
 
959
    }
 
960
 
 
961
    return MPN_INVALID; /* should never reach */
 
962
 
 
963
} /* end function checkdir() */
 
964
 
 
965
 
 
966
 
 
967
 
 
968
 
 
969
/****************************/
 
970
/* Function close_outfile() */
 
971
/****************************/
 
972
 
 
973
void close_outfile(__G)    /* GRR: change to return PK-style warning level */
 
974
    __GDEF
 
975
{
 
976
 
 
977
    fclose(G.outfile);
 
978
 
 
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
  ---------------------------------------------------------------------------*/
 
986
 
 
987
#ifdef SYMLINKS
 
988
    if (G.symlnk) {
 
989
        unsigned ucsize = (unsigned)G.lrec.ucsize;
 
990
        extent slnk_entrysize = sizeof(slinkentry) + ucsize +
 
991
                                strlen(G.filename);
 
992
        slinkentry *slnk_entry;
 
993
 
 
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)));
 
998
            return;
 
999
        }
 
1000
 
 
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)));
 
1005
            return;
 
1006
        }
 
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);
 
1013
 
 
1014
        /* reopen the "link data" file for reading */
 
1015
        G.outfile = fopen(G.filename, FOPR);
 
1016
 
 
1017
        if (!G.outfile ||
 
1018
            fread(slnk_entry->target, 1, ucsize, G.outfile) != (int)ucsize)
 
1019
        {
 
1020
            Info(slide, 0x201, ((char *)slide,
 
1021
              "warning:  symbolic link (%s) failed\n",
 
1022
              FnFilter1(G.filename)));
 
1023
            free(slnk_entry);
 
1024
            fclose(G.outfile);
 
1025
            return;
 
1026
        }
 
1027
        fclose(G.outfile);                  /* close "link" file for good... */
 
1028
        slnk_entry->target[ucsize] = '\0';
 
1029
        if (QCOND2)
 
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;
 
1035
        else
 
1036
            G.slink_head = slnk_entry;
 
1037
        G.slink_last = slnk_entry;
 
1038
        return;
 
1039
    }
 
1040
#endif /* SYMLINKS */
 
1041
 
 
1042
/*---------------------------------------------------------------------------
 
1043
    Change the file permissions from default ones to those stored in the
 
1044
    zipfile.
 
1045
  ---------------------------------------------------------------------------*/
 
1046
 
 
1047
#ifndef NO_CHMOD
 
1048
    if (chmod(G.filename, 0xffff & G.pInfo->file_attr))
 
1049
        perror("chmod (file attributes) error");
 
1050
#endif
 
1051
 
 
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
  ---------------------------------------------------------------------------*/
 
1062
 
 
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) */
 
1070
        {
 
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()");
 
1076
            }
 
1077
        }
 
1078
    }
 
1079
} /* end function close_outfile() */
 
1080
 
 
1081
 
 
1082
 
 
1083
 
 
1084
#ifndef SFX
 
1085
 
 
1086
/************************/
 
1087
/*  Function version()  */
 
1088
/************************/
 
1089
 
 
1090
void version(__G)
 
1091
    __GDEF
 
1092
{
 
1093
#if (defined(__GNUC__) && defined(NX_CURRENT_COMPILER_RELEASE))
 
1094
    char cc_namebuf[40];
 
1095
    char cc_versbuf[40];
 
1096
#else
 
1097
#if (defined(CRAY) && defined(_RELEASE))
 
1098
    char cc_versbuf[40];
 
1099
#endif
 
1100
#endif
 
1101
#if ((defined(CRAY) || defined(cray)) && defined(_UNICOS))
 
1102
    char os_namebuf[40];
 
1103
#else
 
1104
#if defined(__NetBSD__)
 
1105
    char os_namebuf[40];
 
1106
#endif
 
1107
#endif
 
1108
 
 
1109
    /* Pyramid, NeXT have problems with huge macro expansion, too:  no Info() */
 
1110
    sprintf((char *)slide, LoadFarString(CompiledWith),
 
1111
 
 
1112
#ifdef __GNUC__
 
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),
 
1116
       cc_namebuf),
 
1117
      (strlen(__VERSION__) > 8)? "(gcc)" :
 
1118
        (sprintf(cc_versbuf, "(gcc %s)", __VERSION__), cc_versbuf),
 
1119
#  else
 
1120
      "gcc ", __VERSION__,
 
1121
#  endif
 
1122
#else
 
1123
#  if defined(CRAY) && defined(_RELEASE)
 
1124
      "cc ", (sprintf(cc_versbuf, "version %d", _RELEASE), cc_versbuf),
 
1125
#  else
 
1126
#  ifdef __VERSION__
 
1127
#   ifndef IZ_CC_NAME
 
1128
#    define IZ_CC_NAME "cc "
 
1129
#   endif
 
1130
      IZ_CC_NAME, __VERSION__
 
1131
#  else
 
1132
#   ifndef IZ_CC_NAME
 
1133
#    define IZ_CC_NAME "cc"
 
1134
#   endif
 
1135
      IZ_CC_NAME, "",
 
1136
#  endif
 
1137
#  endif
 
1138
#endif /* ?__GNUC__ */
 
1139
 
 
1140
#ifndef IZ_OS_NAME
 
1141
#  define IZ_OS_NAME "Unix"
 
1142
#endif
 
1143
      IZ_OS_NAME,
 
1144
 
 
1145
#if defined(sgi) || defined(__sgi)
 
1146
      " (Silicon Graphics IRIX)",
 
1147
#else
 
1148
#ifdef sun
 
1149
#  ifdef sparc
 
1150
#    ifdef __SVR4
 
1151
      " (Sun SPARC/Solaris)",
 
1152
#    else /* may or may not be SunOS */
 
1153
      " (Sun SPARC)",
 
1154
#    endif
 
1155
#  else
 
1156
#  if defined(sun386) || defined(i386)
 
1157
      " (Sun 386i)",
 
1158
#  else
 
1159
#  if defined(mc68020) || defined(__mc68020__)
 
1160
      " (Sun 3)",
 
1161
#  else /* mc68010 or mc68000:  Sun 2 or earlier */
 
1162
      " (Sun 2)",
 
1163
#  endif
 
1164
#  endif
 
1165
#  endif
 
1166
#else
 
1167
#ifdef __hpux
 
1168
      " (HP/UX)",
 
1169
#else
 
1170
#ifdef __osf__
 
1171
      " (DEC OSF/1)",
 
1172
#else
 
1173
#ifdef _AIX
 
1174
      " (IBM AIX)",
 
1175
#else
 
1176
#ifdef aiws
 
1177
      " (IBM RT/AIX)",
 
1178
#else
 
1179
#if defined(CRAY) || defined(cray)
 
1180
#  ifdef _UNICOS
 
1181
      (sprintf(os_namebuf, " (Cray UNICOS release %d)", _UNICOS), os_namebuf),
 
1182
#  else
 
1183
      " (Cray UNICOS)",
 
1184
#  endif
 
1185
#else
 
1186
#if defined(uts) || defined(UTS)
 
1187
      " (Amdahl UTS)",
 
1188
#else
 
1189
#ifdef NeXT
 
1190
#  ifdef mc68000
 
1191
      " (NeXTStep/black)",
 
1192
#  else
 
1193
      " (NeXTStep for Intel)",
 
1194
#  endif
 
1195
#else              /* the next dozen or so are somewhat order-dependent */
 
1196
#ifdef LINUX
 
1197
#  ifdef __ELF__
 
1198
      " (Linux ELF)",
 
1199
#  else
 
1200
      " (Linux a.out)",
 
1201
#  endif
 
1202
#else
 
1203
#ifdef MINIX
 
1204
      " (Minix)",
 
1205
#else
 
1206
#ifdef M_UNIX
 
1207
      " (SCO Unix)",
 
1208
#else
 
1209
#ifdef M_XENIX
 
1210
      " (SCO Xenix)",
 
1211
#else
 
1212
#ifdef __NetBSD__
 
1213
#  ifdef NetBSD0_8
 
1214
      (sprintf(os_namebuf, " (NetBSD 0.8%c)", (char)(NetBSD0_8 - 1 + 'A')),
 
1215
       os_namebuf),
 
1216
#  else
 
1217
#  ifdef NetBSD0_9
 
1218
      (sprintf(os_namebuf, " (NetBSD 0.9%c)", (char)(NetBSD0_9 - 1 + 'A')),
 
1219
       os_namebuf),
 
1220
#  else
 
1221
#  ifdef NetBSD1_0
 
1222
      (sprintf(os_namebuf, " (NetBSD 1.0%c)", (char)(NetBSD1_0 - 1 + 'A')),
 
1223
       os_namebuf),
 
1224
#  else
 
1225
      (BSD4_4 == 0.5)? " (NetBSD before 0.9)" : " (NetBSD 1.1 or later)",
 
1226
#  endif
 
1227
#  endif
 
1228
#  endif
 
1229
#else
 
1230
#ifdef __FreeBSD__
 
1231
      (BSD4_4 == 0.5)? " (FreeBSD 1.x)" : " (FreeBSD 2.0 or later)",
 
1232
#else
 
1233
#ifdef __bsdi__
 
1234
      (BSD4_4 == 0.5)? " (BSD/386 1.0)" : " (BSD/386 1.1 or later)",
 
1235
#else
 
1236
#ifdef __386BSD__
 
1237
      (BSD4_4 == 1)? " (386BSD, post-4.4 release)" : " (386BSD)",
 
1238
#else
 
1239
#if defined(i486) || defined(__i486) || defined(__i486__)
 
1240
      " (Intel 486)",
 
1241
#else
 
1242
#if defined(i386) || defined(__i386) || defined(__i386__)
 
1243
      " (Intel 386)",
 
1244
#else
 
1245
#ifdef pyr
 
1246
      " (Pyramid)",
 
1247
#else
 
1248
#ifdef ultrix
 
1249
#  ifdef mips
 
1250
      " (DEC/MIPS)",
 
1251
#  else
 
1252
#  ifdef vax
 
1253
      " (DEC/VAX)",
 
1254
#  else /* __alpha? */
 
1255
      " (DEC/Alpha)",
 
1256
#  endif
 
1257
#  endif
 
1258
#else
 
1259
#ifdef gould
 
1260
      " (Gould)",
 
1261
#else
 
1262
#ifdef MTS
 
1263
      " (MTS)",
 
1264
#else
 
1265
#ifdef __convexc__
 
1266
      " (Convex)",
 
1267
#else
 
1268
      "",
 
1269
#endif /* Convex */
 
1270
#endif /* MTS */
 
1271
#endif /* Gould */
 
1272
#endif /* DEC */
 
1273
#endif /* Pyramid */
 
1274
#endif /* 386 */
 
1275
#endif /* 486 */
 
1276
#endif /* 386BSD */
 
1277
#endif /* BSDI BSD/386 */
 
1278
#endif /* NetBSD */
 
1279
#endif /* FreeBSD */
 
1280
#endif /* SCO Xenix */
 
1281
#endif /* SCO Unix */
 
1282
#endif /* Minix */
 
1283
#endif /* Linux */
 
1284
#endif /* NeXT */
 
1285
#endif /* Amdahl */
 
1286
#endif /* Cray */
 
1287
#endif /* RT/AIX */
 
1288
#endif /* AIX */
 
1289
#endif /* OSF/1 */
 
1290
#endif /* HP/UX */
 
1291
#endif /* Sun */
 
1292
#endif /* SGI */
 
1293
 
 
1294
#ifdef __DATE__
 
1295
      " on ", __DATE__
 
1296
#else
 
1297
      "", ""
 
1298
#endif
 
1299
    );
 
1300
 
 
1301
    (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
 
1302
 
 
1303
} /* end function version() */
 
1304
 
 
1305
#endif /* !SFX */
 
1306
 
 
1307
 
 
1308
 
 
1309
 
 
1310
 
 
1311
/* ===================================================================
 
1312
 * ZVS_CREATE()
 
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.
 
1318
 *
 
1319
 * Returns 0 if no error, or the error code returned by ?CREATE.
 
1320
 *
 
1321
 *    HISTORY:
 
1322
 *        15-dec-93 dbl
 
1323
 *        31-may-94 dbl: added call to convert pathname to AOS/VS
 
1324
 *
 
1325
 *
 
1326
 */
 
1327
 
 
1328
int zvs_create(ZCONST char *fname, long cretim, long modtim, long acctim,
 
1329
               char *pacl, int ftyp, int eltsize, int maxindlev)
 
1330
{
 
1331
    P_CREATE    pcr_stru;
 
1332
    P_CTIM      pct_stru;
 
1333
 
 
1334
    pcr_stru.cftyp_format = 0;           /* unspecified record format */
 
1335
    if (ftyp == -1)                      /* default file type to UNX */
 
1336
        pcr_stru.cftyp_entry = $FUNX;
 
1337
    else
 
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;
 
1343
 
 
1344
    pct_stru.tcth.long_time = cretim;
 
1345
    pct_stru.tath.long_time = acctim;
 
1346
    pct_stru.tmth.long_time = modtim;
 
1347
 
 
1348
    return (sys_create(ux_to_vs_name(Vs_path, fname), &pcr_stru));
 
1349
 
 
1350
} /* end zvs_create() */
 
1351
 
 
1352
 
 
1353
 
 
1354
/* ===================================================================
 
1355
 * ZVS_CREDIR()
 
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.
 
1362
 *
 
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.)
 
1366
 *
 
1367
 * If you specify anything other than CPD for the file type, DIR will
 
1368
 * be used.
 
1369
 *
 
1370
 * Returns 0 if no error, or the error code returned by ?CREATE.
 
1371
 *
 
1372
 *    HISTORY:
 
1373
 *        1-jun-94 dbl
 
1374
 *
 
1375
 *
 
1376
 */
 
1377
 
 
1378
int zvs_credir(ZCONST char *dname, long cretim, long modtim, long acctim,
 
1379
               char *pacl, int ftyp, long maxblocks, int hashfsize,
 
1380
               int maxindlev)
 
1381
{
 
1382
    P_CREATE_DIR    pcr_stru;
 
1383
    P_CTIM          pct_stru;
 
1384
 
 
1385
    if (ftyp != $FCPD)                      /* default file type to UNX */
 
1386
        pcr_stru.cftyp_entry = $FDIR;
 
1387
    else
 
1388
    {
 
1389
        pcr_stru.cftyp_entry = ftyp;
 
1390
        pcr_stru.cmsh = maxblocks;
 
1391
    }
 
1392
 
 
1393
    pcr_stru.ctim = &pct_stru;
 
1394
    pcr_stru.cacp = pacl;
 
1395
    pcr_stru.chfs = hashfsize;
 
1396
    pcr_stru.cmil = maxindlev;
 
1397
 
 
1398
    pct_stru.tcth.long_time = cretim;
 
1399
    pct_stru.tath.long_time = acctim;
 
1400
    pct_stru.tmth.long_time = modtim;
 
1401
 
 
1402
    return (sys_create(ux_to_vs_name(Vs_path, dname), &pcr_stru));
 
1403
 
 
1404
} /* end zvs_credir() */
 
1405
 
 
1406
 
 
1407
 
 
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).
 
1418
 *
 
1419
 *       RETURNS: pointer to the result (which is an input parameter)
 
1420
 *
 
1421
 *       NOTE: calling code is responsible for making sure
 
1422
 *           the output buffer is big enough!
 
1423
 *
 
1424
 *       HISTORY:
 
1425
 *           31-may-94 dbl
 
1426
 *
 
1427
 */
 
1428
char *ux_to_vs_name(char *outname, ZCONST char *inname)
 
1429
{
 
1430
    ZCONST char *ip=inname, *op=outname;
 
1431
 
 
1432
 
 
1433
    if (ip[0] == '.') {
 
1434
        if (ip[1] == '/') {
 
1435
            *(op++) = '=';
 
1436
            ip += 2;
 
1437
        } else if (ip[1] == '.'  &&  ip[2] == '/') {
 
1438
            *(op++) = '^';
 
1439
            ip += 3;
 
1440
        }
 
1441
    }
 
1442
 
 
1443
    do {
 
1444
        if (*ip == '/')
 
1445
            *(op++) = ':';
 
1446
        else if (strchr(
 
1447
           "0123456789_$?.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
 
1448
           *ip) != NULL)
 
1449
        {
 
1450
            *(op++) = *ip;
 
1451
        } else
 
1452
            *(op++) = '?';
 
1453
 
 
1454
    } while (*(ip++) != '\0');
 
1455
 
 
1456
    return outname;
 
1457
 
 
1458
} /* end ux_to_vs_name() */
 
1459
 
 
1460
 
 
1461
 
 
1462
/* =================================================================== */
 
1463
 
 
1464
/* DGDATE
 
1465
   Two functions do encode/decode dates in DG system format.
 
1466
 
 
1467
   Usage:
 
1468
    long value,year,month,day;
 
1469
 
 
1470
    value=dgdate(month,day,year);
 
1471
    undgdate(value,&month,&day,&year);   [GRR:  not used in UnZip: removed]
 
1472
 
 
1473
   Notes:
 
1474
 
 
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.
 
1480
 
 
1481
   2. dgundate() accepts values between 0 and 48213 inclusive.
 
1482
      These correspond to 12/31/1967 and 12/31/2099.
 
1483
 
 
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.
 
1488
 
 
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.
 
1495
 
 
1496
  Written by: Stanley J. Gula
 
1497
              US&T, Inc.
 
1498
              529 Main Street, Suite 1
 
1499
              Indian Orchard, MA 01151
 
1500
              (413)-543-3672
 
1501
              Copyright (c) 1990 US&T, Inc.
 
1502
              All rights reserved.
 
1503
 
 
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
 
1507
              code.
 
1508
 
 
1509
              Stanley J. Gula     July 24, 1990
 
1510
*/
 
1511
 
 
1512
long motable[13]={0,31,59,90,120,151,181,212,243,273,304,334,365};
 
1513
 
 
1514
long yrtable[132]={
 
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,
 
1528
    47848,48213};
 
1529
 
 
1530
/* Given y,m,d return # of days since 12/31/67 */
 
1531
long int dgdate(short mm, short dd, short yy)
 
1532
{
 
1533
    long int temp;
 
1534
    short ytmp;
 
1535
 
 
1536
    if (mm<1 || mm>12 || dd<1 || dd>31 || yy<1968 || yy>2099)
 
1537
        return 0L;
 
1538
 
 
1539
    /* Figure in whole years since 1968 + whole months plus days */
 
1540
    temp=365L*(long)(yy-1968) + motable[mm-1] + (long)dd;
 
1541
 
 
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 */
 
1545
    temp+=(yy-1965)/4;
 
1546
 
 
1547
    /* Correct for this year */
 
1548
    /* In leap years, if date is 3/1 or later, bump */
 
1549
    if ((yy%4==0) && (mm>2))
 
1550
        temp++;
 
1551
 
 
1552
    return temp;
 
1553
}