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

« back to all changes in this revision

Viewing changes to amiga/amiga.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-2003 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
  amiga.c
 
12
 
 
13
  Amiga-specific routines for use with Info-ZIP's UnZip 5.1 and later.
 
14
  See History.5xx for revision history.
 
15
 
 
16
  Contents:   do_wild()
 
17
              mapattr()
 
18
              mapname()
 
19
              checkdir()
 
20
              close_outfile()
 
21
              stamp_file()
 
22
              _abort()                (Aztec C only)
 
23
             [dateformat()]           (currently not used)
 
24
              screensize()
 
25
              version()
 
26
 
 
27
  ------------------------------------------------------------------------*/
 
28
 
 
29
 
 
30
#define UNZIP_INTERNAL
 
31
#ifdef AZTEC_C
 
32
#  define NO_FCNTL_H
 
33
#endif
 
34
#include "unzip.h"
 
35
#include "unzvers.h"
 
36
 
 
37
/* Globular varibundus -- now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h */
 
38
 
 
39
/* static int created_dir; */      /* used in mapname(), checkdir() */
 
40
/* static int renamed_fullpath; */ /* ditto */
 
41
 
 
42
#define PERMS   0777
 
43
#define MKDIR(path,mode) mkdir(path)
 
44
 
 
45
 
 
46
#ifndef S_ISCRIPT          /* not having one implies you have none */
 
47
#  define S_IARCHIVE 0020  /* not modified since this bit was last set */
 
48
#  define S_IREAD    0010  /* can be opened for reading */
 
49
#  define S_IWRITE   0004  /* can be opened for writing */
 
50
#  define S_IDELETE  0001  /* can be deleted */
 
51
#endif /* S_ISCRIPT */
 
52
 
 
53
#ifndef S_IRWD
 
54
#  define S_IRWD     0015  /* useful combo of Amiga privileges */
 
55
#endif /* !S_IRWD */
 
56
 
 
57
#ifndef S_IHIDDEN
 
58
#  define S_IHIDDEN  0200  /* hidden supported in future AmigaDOS (someday) */
 
59
#endif /* !S_HIDDEN */
 
60
 
 
61
#ifndef SFX
 
62
/* Make sure the number here matches unzvers.h in the *EXACT* form */
 
63
/* UZ_MAJORVER "." UZ_MINORVER UZ_PATCHLEVEL vvvv  No non-digits!  */
 
64
const char version_id[]  = "\0$VER: UnZip " UZ_VER_STRING " ("
 
65
#include "env:VersionDate"
 
66
   ")\r\n";
 
67
#endif /* SFX */
 
68
 
 
69
 
 
70
static int ispattern(ZCONST char *p)
 
71
{
 
72
    register char c;
 
73
    while (c = *p++)
 
74
        if (c == '\\') {
 
75
            if (!*++p)
 
76
                return FALSE;
 
77
        } else if (c == '?' || c == '*')
 
78
            return TRUE;
 
79
        else if (c == '[') {
 
80
            for (;;) {
 
81
                if (!(c = *p++))
 
82
                    return FALSE;
 
83
                else if (c == '\\') {
 
84
                    if (!*++p)
 
85
                        return FALSE;
 
86
                } else if (c == ']')
 
87
                    return TRUE;
 
88
            }
 
89
        }
 
90
    return FALSE;
 
91
}
 
92
 
 
93
/**********************/
 
94
/* Function do_wild() */
 
95
/**********************/
 
96
 
 
97
char *do_wild(__G__ wildspec)
 
98
    __GDEF
 
99
    ZCONST char *wildspec;  /* only used first time on a given dir */
 
100
{
 
101
/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h:
 
102
    static DIR *wild_dir = NULL;
 
103
    static ZCONST char *wildname;
 
104
    static char *dirname, matchname[FILNAMSIZ];
 
105
    static int notfirstcall = FALSE, dirnamelen;
 
106
*/
 
107
    struct dirent *file;
 
108
    BPTR lok = 0;
 
109
 
 
110
    /* Even when we're just returning wildspec, we *always* do so in
 
111
     * matchname[]--calling routine is allowed to append four characters
 
112
     * to the returned string, and wildspec may be a pointer to argv[].
 
113
     */
 
114
    if (!G.notfirstcall) {      /* first call:  must initialize everything */
 
115
        G.notfirstcall = TRUE;
 
116
 
 
117
        /* avoid needless readdir() scans: */
 
118
        if (!ispattern(wildspec) ||
 
119
                (lok = Lock((char *)wildspec, ACCESS_READ))) {
 
120
            if (lok) UnLock(lok);       /* ^^ we ignore wildcard chars if */
 
121
            G.dirnamelen = 0;           /* the name matches a real file   */
 
122
            strcpy(G.matchname, wildspec);
 
123
            return G.matchname;
 
124
        }
 
125
 
 
126
        /* break the wildspec into a directory part and a wildcard filename */
 
127
        if ((G.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL &&
 
128
            (G.wildname = (ZCONST char *)strrchr(wildspec, ':')) == NULL) {
 
129
            G.dirname = "";             /* current dir */
 
130
            G.dirnamelen = 0;
 
131
            G.wildname = wildspec;
 
132
        } else {
 
133
            ++G.wildname;     /* point at character after '/' or ':' */
 
134
            G.dirnamelen = G.wildname - wildspec;
 
135
            if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == NULL) {
 
136
                Info(slide, 1, ((char *)slide,
 
137
                     "warning:  cannot allocate wildcard buffers\n"));
 
138
                strcpy(G.matchname, wildspec);
 
139
                return G.matchname; /* but maybe filespec was not a wildcard */
 
140
            }
 
141
            strncpy(G.dirname, wildspec, G.dirnamelen);
 
142
            G.dirname[G.dirnamelen] = 0;
 
143
        }
 
144
 
 
145
        if ((G.wild_dir = opendir(G.dirname)) != NULL) {
 
146
            while ((file = readdir(G.wild_dir)) != NULL) {
 
147
                if (match(file->d_name, G.wildname, 1)) {  /* ignore case */
 
148
                    strcpy(G.matchname, G.dirname);
 
149
                    strcpy(G.matchname + G.dirnamelen, file->d_name);
 
150
                    return G.matchname;
 
151
                }
 
152
            }
 
153
            /* if we get to here directory is exhausted, so close it */
 
154
            closedir(G.wild_dir);
 
155
            G.wild_dir = NULL;
 
156
        }
 
157
 
 
158
        /* return the raw wildspec in case that works (e.g., directory not
 
159
         * searchable, but filespec was not wild and file is readable) */
 
160
        strcpy(G.matchname, wildspec);
 
161
        return G.matchname;
 
162
    }
 
163
 
 
164
    /* last time through, might have failed opendir but returned raw wildspec */
 
165
    if (G.wild_dir == NULL) {
 
166
        G.notfirstcall = FALSE;    /* nothing left to try -- reset */
 
167
        if (G.dirnamelen > 0)
 
168
            free(G.dirname);
 
169
        return (char *)NULL;
 
170
    }
 
171
 
 
172
    /* If we've gotten this far, we've read and matched at least one entry
 
173
     * successfully (in a previous call), so dirname has been copied into
 
174
     * matchname already.
 
175
     */
 
176
    while ((file = readdir(G.wild_dir)) != NULL)
 
177
        if (match(file->d_name, G.wildname, 1)) {   /* 1 == ignore case */
 
178
            /* strcpy(G.matchname, dirname); */
 
179
            strcpy(G.matchname + G.dirnamelen, file->d_name);
 
180
            return G.matchname;
 
181
        }
 
182
 
 
183
    closedir(G.wild_dir);  /* have read at least one dir entry; nothing left */
 
184
    G.wild_dir = NULL;
 
185
    G.notfirstcall = FALSE; /* reset for new wildspec */
 
186
    if (G.dirnamelen > 0)
 
187
        free(G.dirname);
 
188
    return (char *)NULL;
 
189
 
 
190
} /* end function do_wild() */
 
191
 
 
192
 
 
193
 
 
194
 
 
195
/**********************/
 
196
/* Function mapattr() */
 
197
/**********************/
 
198
 
 
199
int mapattr(__G)      /* Amiga version */
 
200
    __GDEF
 
201
{
 
202
    ulg  tmp = G.crec.external_file_attributes;
 
203
 
 
204
 
 
205
    /* Amiga attributes = hsparwed = hidden, script, pure, archive,
 
206
     * read, write, execute, delete */
 
207
 
 
208
    switch (G.pInfo->hostnum) {
 
209
        case AMIGA_:
 
210
            if ((tmp & 1) == (tmp>>18 & 1))
 
211
                tmp ^= 0x000F0000;      /* PKAZip compatibility kluge */
 
212
            /* turn off archive bit for restored Amiga files */
 
213
            G.pInfo->file_attr = (unsigned)((tmp>>16) & (~S_IARCHIVE));
 
214
            break;
 
215
 
 
216
        case UNIX_:   /* preserve read, write, execute:  use logical-OR of */
 
217
        case VMS_:    /* user, group, and other; if writable, set delete bit */
 
218
        case ACORN_:
 
219
        case ATARI_:
 
220
        case BEOS_:
 
221
        case QDOS_:
 
222
        case TANDEM_:
 
223
            {
 
224
              unsigned uxattr = (unsigned)(tmp >> 16);
 
225
              int r = FALSE;
 
226
 
 
227
              if (uxattr == 0 && G.extra_field) {
 
228
                /* Some (non-Info-ZIP) implementations of Zip for Unix and
 
229
                   VMS (and probably others ??) leave 0 in the upper 16-bit
 
230
                   part of the external_file_attributes field. Instead, they
 
231
                   store file permission attributes in some extra field.
 
232
                   As a work-around, we search for the presence of one of
 
233
                   these extra fields and fall back to the MSDOS compatible
 
234
                   part of external_file_attributes if one of the known
 
235
                   e.f. types has been detected.
 
236
                   Later, we might implement extraction of the permission
 
237
                   bits from the VMS extra field. But for now, the work-around
 
238
                   should be sufficient to provide "readable" extracted files.
 
239
                   (For ASI Unix e.f., an experimental remap of the e.f.
 
240
                   mode value IS already provided!)
 
241
                 */
 
242
                ush ebID;
 
243
                unsigned ebLen;
 
244
                uch *ef = G.extra_field;
 
245
                unsigned ef_len = G.crec.extra_field_length;
 
246
 
 
247
                while (!r && ef_len >= EB_HEADSIZE) {
 
248
                    ebID = makeword(ef);
 
249
                    ebLen = (unsigned)makeword(ef+EB_LEN);
 
250
                    if (ebLen > (ef_len - EB_HEADSIZE))
 
251
                        /* discoverd some e.f. inconsistency! */
 
252
                        break;
 
253
                    switch (ebID) {
 
254
                      case EF_ASIUNIX:
 
255
                        if (ebLen >= (EB_ASI_MODE+2)) {
 
256
                            uxattr =
 
257
                              (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
 
258
                            /* force stop of loop: */
 
259
                            ef_len = (ebLen + EB_HEADSIZE);
 
260
                            break;
 
261
                        }
 
262
                        /* else: fall through! */
 
263
                      case EF_PKVMS:
 
264
                        /* "found nondecypherable e.f. with perm. attr" */
 
265
                        r = TRUE;
 
266
                      default:
 
267
                        break;
 
268
                    }
 
269
                    ef_len -= (ebLen + EB_HEADSIZE);
 
270
                    ef += (ebLen + EB_HEADSIZE);
 
271
                }
 
272
              }
 
273
              if (!r) {
 
274
                uxattr = (( uxattr>>6 | uxattr>>3 | uxattr) & 07) << 1;
 
275
                G.pInfo->file_attr = (unsigned)(uxattr&S_IWRITE ?
 
276
                                                uxattr|S_IDELETE : uxattr);
 
277
                break;
 
278
              }
 
279
            }
 
280
            /* fall through! */
 
281
 
 
282
        /* all other platforms:  assume read-only bit in DOS half of attribute
 
283
         * word is set correctly ==> will become READ or READ+WRITE+DELETE */
 
284
        case FS_FAT_:
 
285
        case FS_HPFS_:  /* can add S_IHIDDEN check to MSDOS/OS2/NT eventually */
 
286
        case FS_NTFS_:
 
287
        case MAC_:
 
288
        case TOPS20_:
 
289
        default:
 
290
            G.pInfo->file_attr = (unsigned)(tmp&1? S_IREAD : S_IRWD);
 
291
            break;
 
292
 
 
293
    } /* end switch (host-OS-created-by) */
 
294
 
 
295
    G.pInfo->file_attr &= 0xff;   /* mask off all but lower eight bits */
 
296
    return 0;
 
297
 
 
298
} /* end function mapattr() */
 
299
 
 
300
 
 
301
 
 
302
 
 
303
/************************/
 
304
/*  Function mapname()  */
 
305
/************************/
 
306
 
 
307
int mapname(__G__ renamed)
 
308
    __GDEF
 
309
    int renamed;
 
310
/*
 
311
 * returns:
 
312
 *  MPN_OK          - no problem detected
 
313
 *  MPN_INF_TRUNC   - caution (truncated filename)
 
314
 *  MPN_INF_SKIP    - info "skip entry" (dir doesn't exist)
 
315
 *  MPN_ERR_SKIP    - error -> skip entry
 
316
 *  MPN_ERR_TOOLONG - error -> path is too long
 
317
 *  MPN_NOMEM       - error (memory allocation failed) -> skip entry
 
318
 *  [also MPN_VOL_LABEL, MPN_CREATED_DIR]
 
319
 */
 
320
{
 
321
    char pathcomp[FILNAMSIZ];   /* path-component buffer */
 
322
    char *pp, *cp=NULL;         /* character pointers */
 
323
    char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
 
324
    int killed_ddot = FALSE;    /* is set when skipping "../" pathcomp */
 
325
    int error = MPN_OK;
 
326
    register unsigned workch;   /* hold the character being tested */
 
327
 
 
328
 
 
329
/*---------------------------------------------------------------------------
 
330
    Initialize various pointers and counters and stuff.
 
331
  ---------------------------------------------------------------------------*/
 
332
 
 
333
    if (G.pInfo->vollabel)
 
334
        return MPN_VOL_LABEL;   /* can't set disk volume labels in AmigaDOS */
 
335
 
 
336
    /* can create path as long as not just freshening, or if user told us */
 
337
    G.create_dirs = (!uO.fflag || renamed);
 
338
 
 
339
    G.created_dir = FALSE;      /* not yet */
 
340
 
 
341
    /* user gave full pathname:  don't prepend G.rootpath */
 
342
#ifndef OLD_AMIGA_RENAMED
 
343
    G.renamed_fullpath = (renamed &&
 
344
                          (*G.filename == '/' || *G.filename == ':'));
 
345
#else
 
346
    /* supress G.rootpath even when user gave a relative pathname */
 
347
# if 1
 
348
    G.renamed_fullpath = (renamed && strpbrk(G.filename, ":/");
 
349
# else
 
350
    G.renamed_fullpath = (renamed &&
 
351
                          (strchr(G.filename, ':') || strchr(G.filename, '/')));
 
352
# endif
 
353
#endif
 
354
 
 
355
    if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM)
 
356
        return MPN_NOMEM;       /* initialize path buffer, unless no memory */
 
357
 
 
358
    *pathcomp = '\0';           /* initialize translation buffer */
 
359
    pp = pathcomp;              /* point to translation buffer */
 
360
    if (uO.jflag)               /* junking directories */
 
361
        cp = (char *)strrchr(G.filename, '/');
 
362
    if (cp == (char *)NULL)     /* no '/' or not junking dirs */
 
363
        cp = G.filename;        /* point to internal zipfile-member pathname */
 
364
    else
 
365
        ++cp;                   /* point to start of last component of path */
 
366
 
 
367
/*---------------------------------------------------------------------------
 
368
    Begin main loop through characters in filename.
 
369
  ---------------------------------------------------------------------------*/
 
370
 
 
371
    while ((workch = (uch)*cp++) != 0) {
 
372
 
 
373
        switch (workch) {
 
374
            case '/':             /* can assume -j flag not given */
 
375
                *pp = '\0';
 
376
                if (strcmp(pathcomp, ".") == 0) {
 
377
                    /* don't bother appending "./" to the path */
 
378
                    *pathcomp = '\0';
 
379
                } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
 
380
                    /* "../" dir traversal detected, skip over it */
 
381
                    *pathcomp = '\0';
 
382
                    killed_ddot = TRUE;     /* set "show message" flag */
 
383
                }
 
384
                /* when path component is not empty, append it now */
 
385
                if (*pathcomp != '\0' &&
 
386
                    ((error = checkdir(__G__ pathcomp, APPEND_DIR))
 
387
                     & MPN_MASK) > MPN_INF_TRUNC)
 
388
                    return error;
 
389
                pp = pathcomp;    /* reset conversion buffer for next piece */
 
390
                lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
 
391
                break;
 
392
 
 
393
            case ';':             /* VMS version (or DEC-20 attrib?) */
 
394
                lastsemi = pp;         /* keep for now; remove VMS ";##" */
 
395
                *pp++ = (char)workch;  /*  later, if requested */
 
396
                break;
 
397
 
 
398
            default:
 
399
                /* allow ISO European characters in filenames: */
 
400
                if (isprint(workch) || (160 <= workch && workch <= 255))
 
401
                    *pp++ = (char)workch;
 
402
        } /* end switch */
 
403
 
 
404
    } /* end while loop */
 
405
 
 
406
    /* Show warning when stripping insecure "parent dir" path components */
 
407
    if (killed_ddot && QCOND2) {
 
408
        Info(slide, 0, ((char *)slide,
 
409
          "warning:  skipped \"../\" path component(s) in %s\n",
 
410
          FnFilter1(G.filename)));
 
411
        if (!(error & ~MPN_MASK))
 
412
            error = (error & MPN_MASK) | PK_WARN;
 
413
    }
 
414
 
 
415
/*---------------------------------------------------------------------------
 
416
    Report if directory was created (and no file to create:  filename ended
 
417
    in '/'), check name to be sure it exists, and combine path and name be-
 
418
    fore exiting.
 
419
  ---------------------------------------------------------------------------*/
 
420
 
 
421
    if (G.filename[strlen(G.filename) - 1] == '/') {
 
422
        checkdir(__G__ G.filename, GETPATH);
 
423
        if (G.created_dir) {
 
424
            if (QCOND2) {
 
425
                Info(slide, 0, ((char *)slide, "   creating: %s\n",
 
426
                  FnFilter1(G.filename)));
 
427
            }
 
428
            /* set dir time (note trailing '/') */
 
429
            return (error & ~MPN_MASK) | MPN_CREATED_DIR;
 
430
        }
 
431
        /* dir existed already; don't look for data to extract */
 
432
        return (error & ~MPN_MASK) | MPN_INF_SKIP;
 
433
    }
 
434
 
 
435
    *pp = '\0';                   /* done with pathcomp:  terminate it */
 
436
 
 
437
    /* if not saving them, remove VMS version numbers (appended ";###") */
 
438
    if (!uO.V_flag && lastsemi) {
 
439
        pp = lastsemi + 1;
 
440
        while (isdigit((uch)(*pp)))
 
441
            ++pp;
 
442
        if (*pp == '\0')          /* only digits between ';' and end:  nuke */
 
443
            *lastsemi = '\0';
 
444
    }
 
445
 
 
446
    if (*pathcomp == '\0') {
 
447
        Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
 
448
          FnFilter1(G.filename)));
 
449
        return (error & ~MPN_MASK) | MPN_ERR_SKIP;
 
450
    }
 
451
 
 
452
    error = (error & ~MPN_MASK) | checkdir(__G__ pathcomp, APPEND_NAME);
 
453
    if ((error & MPN_MASK) == MPN_INF_TRUNC) {
 
454
        /* GRR:  OK if truncated here:  warn and continue */
 
455
        /* (warn in checkdir?) */
 
456
    }
 
457
    checkdir(__G__ G.filename, GETPATH);
 
458
 
 
459
    return error;
 
460
 
 
461
} /* end function mapname() */
 
462
 
 
463
 
 
464
 
 
465
 
 
466
/***********************/
 
467
/* Function checkdir() */
 
468
/***********************/
 
469
 
 
470
int checkdir(__G__ pathcomp, flag)
 
471
    __GDEF
 
472
    char *pathcomp;
 
473
    int flag;
 
474
/*
 
475
 * returns:
 
476
 *  MPN_OK          - no problem detected
 
477
 *  MPN_INF_TRUNC   - (on APPEND_NAME) truncated filename
 
478
 *  MPN_INF_SKIP    - path doesn't exist, not allowed to create
 
479
 *  MPN_ERR_SKIP    - path doesn't exist, tried to create and failed; or path
 
480
 *                    exists and is not a directory, but is supposed to be
 
481
 *  MPN_ERR_TOOLONG - path is too long
 
482
 *  MPN_NOMEM       - can't allocate memory for filename buffers
 
483
 */
 
484
{
 
485
/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h: */
 
486
/*  static int rootlen = 0; */   /* length of rootpath */
 
487
/*  static char *rootpath;  */   /* user's "extract-to" directory */
 
488
/*  static char *buildpath; */   /* full path (so far) to extracted file */
 
489
/*  static char *end;       */   /* pointer to end of buildpath ('\0') */
 
490
 
 
491
#   define FN_MASK   7
 
492
#   define FUNCTION  (flag & FN_MASK)
 
493
 
 
494
 
 
495
/*---------------------------------------------------------------------------
 
496
    APPEND_DIR:  append the path component to the path being built and check
 
497
    for its existence.  If doesn't exist and we are creating directories, do
 
498
    so for this one; else signal success or error as appropriate.
 
499
  ---------------------------------------------------------------------------*/
 
500
 
 
501
/* GRR:  check path length after each segment:  warn about truncation */
 
502
 
 
503
    if (FUNCTION == APPEND_DIR) {
 
504
        int too_long = FALSE;
 
505
 
 
506
        Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
 
507
        while ((*G.build_end = *pathcomp++) != '\0')
 
508
            ++G.build_end;
 
509
        /* Truncate components over 30 chars? Nah, the filesystem handles it. */
 
510
        if ((G.build_end-G.buildpath) > FILNAMSIZ-3)       /* room for "/a\0" */
 
511
            too_long = TRUE;                    /* check if extracting dir? */
 
512
        if (SSTAT(G.buildpath, &G.statbuf)) {   /* path doesn't exist */
 
513
            if (!G.create_dirs) { /* told not to create (freshening) */
 
514
                free(G.buildpath);
 
515
                return MPN_INF_SKIP;    /* path doesn't exist: nothing to do */
 
516
            }
 
517
            if (too_long) {
 
518
                Info(slide, 1, ((char *)slide,
 
519
                  "checkdir error:  path too long: %s\n",
 
520
                  FnFilter1(G.buildpath)));
 
521
                free(G.buildpath);
 
522
                /* no room for filenames:  fatal */
 
523
                return MPN_ERR_TOOLONG;
 
524
            }
 
525
            if (MKDIR(G.buildpath, 0777) == -1) {   /* create the directory */
 
526
                Info(slide, 1, ((char *)slide,
 
527
                  "checkdir error:  cannot create %s\n\
 
528
                 unable to process %s.\n",
 
529
                  FnFilter2(G.buildpath), FnFilter1(G.filename)));
 
530
                free(G.buildpath);
 
531
                /* path didn't exist, tried to create, failed */
 
532
                return MPN_ERR_SKIP;
 
533
            }
 
534
            G.created_dir = TRUE;
 
535
        } else if (!S_ISDIR(G.statbuf.st_mode)) {
 
536
            Info(slide, 1, ((char *)slide,
 
537
              "checkdir error:  %s exists but is not directory\n\
 
538
                 unable to process %s.\n",
 
539
              FnFilter2(G.buildpath), FnFilter1(G.filename)));
 
540
            free(G.buildpath);
 
541
            /* path existed but wasn't dir */
 
542
            return MPN_ERR_SKIP;
 
543
        }
 
544
        if (too_long) {
 
545
            Info(slide, 1, ((char *)slide,
 
546
              "checkdir error:  path too long: %s\n", FnFilter1(G.buildpath)));
 
547
            free(G.buildpath);
 
548
            /* no room for filenames:  fatal */
 
549
            return MPN_ERR_TOOLONG;
 
550
        }
 
551
        *G.build_end++ = '/';
 
552
        *G.build_end = '\0';
 
553
        Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
 
554
        return MPN_OK;
 
555
 
 
556
    } /* end if (FUNCTION == APPEND_DIR) */
 
557
 
 
558
/*---------------------------------------------------------------------------
 
559
    GETPATH:  copy full path to the string pointed at by pathcomp, and free
 
560
    G.buildpath.  Not our responsibility to worry whether pathcomp has room.
 
561
  ---------------------------------------------------------------------------*/
 
562
 
 
563
    if (FUNCTION == GETPATH) {
 
564
        strcpy(pathcomp, G.buildpath);
 
565
        Trace((stderr, "getting and freeing path [%s]\n",
 
566
          FnFilter1(pathcomp)));
 
567
        free(G.buildpath);
 
568
        G.buildpath = G.build_end = (char *)NULL;
 
569
        return MPN_OK;
 
570
    }
 
571
 
 
572
/*---------------------------------------------------------------------------
 
573
    APPEND_NAME:  assume the path component is the filename; append it and
 
574
    return without checking for existence.
 
575
  ---------------------------------------------------------------------------*/
 
576
 
 
577
    if (FUNCTION == APPEND_NAME) {
 
578
        Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
 
579
        while ((*G.build_end = *pathcomp++) != '\0') {
 
580
            ++G.build_end;
 
581
            if ((G.build_end-G.buildpath) >= FILNAMSIZ) {
 
582
                *--G.build_end = '\0';
 
583
                Info(slide, 0x201, ((char *)slide,
 
584
                  "checkdir warning:  path too long; truncating\n\
 
585
                   %s\n                -> %s\n",
 
586
                  FnFilter1(G.filename), FnFilter2(G.buildpath)));
 
587
                return MPN_INF_TRUNC;   /* filename truncated */
 
588
            }
 
589
        }
 
590
        Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
 
591
        /* could check for existence here, prompt for new name... */
 
592
        return MPN_OK;
 
593
    }
 
594
 
 
595
/*---------------------------------------------------------------------------
 
596
    INIT:  allocate and initialize buffer space for the file currently being
 
597
    extracted.  If file was renamed with an absolute path, don't prepend the
 
598
    extract-to path.
 
599
  ---------------------------------------------------------------------------*/
 
600
 
 
601
    if (FUNCTION == INIT) {
 
602
        Trace((stderr, "initializing buildpath to "));
 
603
        if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1))
 
604
            == (char *)NULL)
 
605
            return MPN_NOMEM;
 
606
        if ((G.rootlen > 0) && !G.renamed_fullpath) {
 
607
            strcpy(G.buildpath, G.rootpath);
 
608
            G.build_end = G.buildpath + G.rootlen;
 
609
        } else {
 
610
            *G.buildpath = '\0';
 
611
            G.build_end = G.buildpath;
 
612
        }
 
613
        Trace((stderr, "[%s]\n", FnFilter1(G.buildpath)));
 
614
        return MPN_OK;
 
615
    }
 
616
 
 
617
/*---------------------------------------------------------------------------
 
618
    ROOT:  if appropriate, store the path in G.rootpath and create it if
 
619
    necessary; else assume it's a zipfile member and return.  This path
 
620
    segment gets used in extracting all members from every zipfile specified
 
621
    on the command line.
 
622
  ---------------------------------------------------------------------------*/
 
623
 
 
624
#if (!defined(SFX) || defined(SFX_EXDIR))
 
625
    if (FUNCTION == ROOT) {
 
626
        Trace((stderr, "initializing root path to [%s]\n",
 
627
          FnFilter1(pathcomp)));
 
628
        if (pathcomp == (char *)NULL) {
 
629
            G.rootlen = 0;
 
630
            return MPN_OK;
 
631
        }
 
632
        if (G.rootlen > 0)      /* rootpath was already set, nothing to do */
 
633
            return MPN_OK;
 
634
        if ((G.rootlen = strlen(pathcomp)) > 0) {
 
635
            if (stat(pathcomp, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode)) {
 
636
                /* path does not exist */
 
637
                if (!G.create_dirs) {
 
638
                    G.rootlen = 0;
 
639
                    /* skip (or treat as stored file) */
 
640
                    return MPN_INF_SKIP;
 
641
                }
 
642
                /* create the directory (could add loop here scanning pathcomp
 
643
                 * to create more than one level, but why really necessary?) */
 
644
                if (MKDIR(pathcomp, 0777) == -1) {
 
645
                    Info(slide, 1, ((char *)slide,
 
646
                      "checkdir:  cannot create extraction directory: %s\n",
 
647
                      FnFilter1(pathcomp)));
 
648
                    G.rootlen = 0;
 
649
                    /* path didn't exist, tried to create, and failed: */
 
650
                    /* file exists, or 2+ subdir levels required */
 
651
                    return MPN_ERR_SKIP;
 
652
                }
 
653
            }
 
654
            if ((G.rootpath = (char *)malloc(G.rootlen+2)) == NULL) {
 
655
                G.rootlen = 0;
 
656
                return MPN_NOMEM;
 
657
            }
 
658
            strcpy(G.rootpath, pathcomp);
 
659
            if (G.rootpath[G.rootlen-1] != ':' && G.rootpath[G.rootlen-1] != '/')
 
660
                G.rootpath[G.rootlen++] = '/';
 
661
            G.rootpath[G.rootlen] = '\0';
 
662
            Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
 
663
        }
 
664
        return MPN_OK;
 
665
    }
 
666
#endif /* !SFX || SFX_EXDIR */
 
667
 
 
668
/*---------------------------------------------------------------------------
 
669
    END:  free G.rootpath, immediately prior to program exit.
 
670
  ---------------------------------------------------------------------------*/
 
671
 
 
672
    if (FUNCTION == END) {
 
673
        Trace((stderr, "freeing rootpath\n"));
 
674
        if (G.rootlen > 0) {
 
675
            free(G.rootpath);
 
676
            G.rootlen = 0;
 
677
        }
 
678
        return MPN_OK;
 
679
    }
 
680
 
 
681
    return MPN_INVALID; /* should never reach */
 
682
 
 
683
} /* end function checkdir() */
 
684
 
 
685
 
 
686
 
 
687
 
 
688
 
 
689
/**************************************/
 
690
/* Function close_outfile() */
 
691
/**************************************/
 
692
/* this part differs slightly with Zip */
 
693
/*-------------------------------------*/
 
694
 
 
695
void close_outfile(__G)
 
696
    __GDEF
 
697
{
 
698
    time_t m_time;
 
699
#ifdef USE_EF_UT_TIME
 
700
    iztimes z_utime;
 
701
#endif
 
702
    LONG FileDate();
 
703
 
 
704
    if (uO.cflag)               /* can't set time or filenote on stdout */
 
705
        return;
 
706
 
 
707
  /* close the file *before* setting its time under AmigaDOS */
 
708
 
 
709
    fclose(G.outfile);
 
710
 
 
711
#ifdef USE_EF_UT_TIME
 
712
    if (G.extra_field &&
 
713
#ifdef IZ_CHECK_TZ
 
714
        G.tz_is_valid &&
 
715
#endif
 
716
        (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
 
717
                          G.lrec.last_mod_dos_datetime, &z_utime, NULL)
 
718
         & EB_UT_FL_MTIME))
 
719
    {
 
720
        TTrace((stderr, "close_outfile:  Unix e.f. modif. time = %ld\n",
 
721
                         z_utime.mtime));
 
722
        m_time = z_utime.mtime;
 
723
    } else {
 
724
        /* Convert DOS time to time_t format */
 
725
        m_time = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
 
726
    }
 
727
#else /* !USE_EF_UT_TIME */
 
728
    /* Convert DOS time to time_t format */
 
729
    m_time = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
 
730
#endif /* ?USE_EF_UT_TIME */
 
731
 
 
732
#ifdef DEBUG
 
733
    Info(slide, 1, ((char *)slide, "\nclose_outfile(): m_time=%s\n",
 
734
                         ctime(&m_time)));
 
735
#endif
 
736
 
 
737
    if (!FileDate(G.filename, &m_time))
 
738
        Info(slide, 1, ((char *)slide,
 
739
             "warning:  cannot set the time for %s\n", G.filename));
 
740
 
 
741
  /* set file perms after closing (not done at creation)--see mapattr() */
 
742
 
 
743
    chmod(G.filename, G.pInfo->file_attr);
 
744
 
 
745
  /* give it a filenote from the zipfile comment, if appropriate */
 
746
 
 
747
    if (uO.N_flag && G.filenotes[G.filenote_slot]) {
 
748
        SetComment(G.filename, G.filenotes[G.filenote_slot]);
 
749
        free(G.filenotes[G.filenote_slot]);
 
750
        G.filenotes[G.filenote_slot] = NULL;
 
751
    }
 
752
 
 
753
} /* end function close_outfile() */
 
754
 
 
755
 
 
756
#ifdef TIMESTAMP
 
757
 
 
758
/*************************/
 
759
/* Function stamp_file() */
 
760
/*************************/
 
761
 
 
762
int stamp_file(fname, modtime)
 
763
    ZCONST char *fname;
 
764
    time_t modtime;
 
765
{
 
766
    time_t m_time;
 
767
    LONG FileDate();
 
768
 
 
769
    m_time = modtime;
 
770
    return (FileDate((char *)fname, &m_time));
 
771
 
 
772
} /* end function stamp_file() */
 
773
 
 
774
#endif /* TIMESTAMP */
 
775
 
 
776
 
 
777
#ifndef __SASC
 
778
/********************************************************************/
 
779
/* Load filedate as a separate external file; it's used by Zip, too.*/
 
780
/*                                                                  */
 
781
#  include "amiga/filedate.c"                                    /* */
 
782
/*                                                                  */
 
783
/********************************************************************/
 
784
 
 
785
/********************* do linewise with stat.c **********************/
 
786
 
 
787
#  include "amiga/stat.c"
 
788
/* this is the exact same stat.c used by Zip */
 
789
#endif /* !__SASC */
 
790
/* SAS/C makes separate object modules of these; there is less  */
 
791
/* trouble that way when redefining standard library functions. */
 
792
 
 
793
#include <stdio.h>
 
794
 
 
795
void _abort(void)               /* called when ^C is pressed */
 
796
{
 
797
    /* echon(); */
 
798
    close_leftover_open_dirs();
 
799
    fflush(stdout);
 
800
    fputs("\n^C\n", stderr);
 
801
    exit(1);
 
802
}
 
803
 
 
804
 
 
805
/************************************************************/
 
806
/* function screensize() -- uses sendpkt() from filedate.c: */
 
807
/************************************************************/
 
808
 
 
809
#include <devices/conunit.h>
 
810
#include <dos/dosextens.h>
 
811
#include <exec/memory.h>
 
812
#include <clib/exec_protos.h>
 
813
 
 
814
extern long sendpkt(struct MsgPort *pid, long action, long *args, long nargs);
 
815
 
 
816
int screensize(int *ttrows, int *ttcols)
 
817
{
 
818
    BPTR fh = Output();
 
819
    if (fh && IsInteractive(fh)) {
 
820
        struct ConUnit *conunit = NULL;
 
821
        void *conp = ((struct FileHandle *) (fh << 2))->fh_Type;
 
822
        struct InfoData *ind = AllocMem(sizeof(*ind), MEMF_PUBLIC);
 
823
        long argp = ((unsigned long) ind) >> 2;
 
824
 
 
825
        if (ind && conp && sendpkt(conp, ACTION_DISK_INFO, &argp, 1))
 
826
            conunit = (void *) ((struct IOStdReq *) ind->id_InUse)->io_Unit;
 
827
        if (ind)
 
828
            FreeMem(ind, sizeof(*ind));
 
829
        if (conunit) {
 
830
            if (ttrows) *ttrows = conunit->cu_YMax + 1;
 
831
            if (ttcols) *ttcols = conunit->cu_XMax + 1;
 
832
            return 0;     /* success */
 
833
        }
 
834
    }
 
835
    if (ttrows) *ttrows = INT_MAX;
 
836
    if (ttcols) *ttcols = INT_MAX;
 
837
    return 1;             /* failure */
 
838
}
 
839
 
 
840
 
 
841
#ifdef AMIGA_VOLUME_LABELS
 
842
/* This function is for if we someday implement -$ on the Amiga. */
 
843
#  include <dos/dosextens.h>
 
844
#  include <dos/filehandler.h>
 
845
#  include <clib/macros.h>
 
846
 
 
847
BOOL is_floppy(ZCONST char *path)
 
848
{
 
849
    BOOL okay = FALSE;
 
850
    char devname[32], *debna;
 
851
    ushort i;
 
852
    BPTR lok = Lock((char *)path, ACCESS_READ), pok;
 
853
    struct FileSysStartupMsg *fart;
 
854
    struct DeviceNode *debb, devlist = (void *) BADDR((struct DosInfo *)
 
855
                                BADDR(DOSBase->dl_Root->rn_Info)->di_DevInfo);
 
856
    if (!lok)
 
857
        return FALSE;                   /* should not happen */
 
858
    if (pok = ParentDir((char *)path)) {
 
859
        UnLock(lok);
 
860
        UnLock(pok);
 
861
        return FALSE;                   /* it's not a root directory path */
 
862
    }
 
863
    Forbid();
 
864
    for (debb = devlist; debb; debb = BADDR(debb->dn_Next))
 
865
        if (debb->dn_Type == DLT_DEVICE && (debb->dn_Task == lick->fl_Task))
 
866
            if (fart = BADDR(debb->dn_Startup)) {
 
867
                debna = (char *) BADDR(fart->fssm_Device) + 1;
 
868
                if ((i = debna[-1]) > 31) i = 30;
 
869
                strncpy(devname, debna, i);
 
870
                devname[i] = 0;
 
871
                okay = !strcmp(devname, "trackdisk.device")
 
872
                                || !strcmp(devname, "mfm.device")
 
873
                                || !strcmp(devname, "messydisk.device");
 
874
                break;  /* We only support obvious floppy drives, not tricky */
 
875
            }           /* things like removable cartrige hard drives, or    */
 
876
    Permit();           /* any unusual kind of floppy device driver.         */
 
877
    return okay;
 
878
}
 
879
#endif /* AMIGA_VOLUME_LABELS */
 
880
 
 
881
 
 
882
#ifndef SFX
 
883
 
 
884
# if 0
 
885
/* As far as I can tell, all the locales AmigaDOS 2.1 knows about all */
 
886
/* happen to use DF_MDY ordering, so there's no point in using this.  */
 
887
 
 
888
/*************************/
 
889
/* Function dateformat() */
 
890
/*************************/
 
891
 
 
892
#include <clib/locale_protos.h>
 
893
#ifdef AZTEC_C
 
894
#  include <pragmas/locale_lib.h>
 
895
#endif
 
896
 
 
897
int dateformat()
 
898
{
 
899
/*---------------------------------------------------------------------------
 
900
    For those operating systems which support it, this function returns a
 
901
    value which tells how national convention says that numeric dates are
 
902
    displayed.  Return values are DF_YMD, DF_DMY and DF_MDY (the meanings
 
903
    should be fairly obvious).
 
904
  ---------------------------------------------------------------------------*/
 
905
    struct Library *LocaleBase;
 
906
    struct Locale *ll;
 
907
    int result = DF_MDY;        /* the default */
 
908
 
 
909
    if ((LocaleBase = OpenLibrary("locale.library", 0))) {
 
910
        if (ll = OpenLocale(NULL)) {
 
911
            uch *f = ll->loc_ShortDateFormat;
 
912
            /* In this string, %y|%Y is year, %b|%B|%h|%m is month, */
 
913
            /* %d|%e is day day, and %D|%x is short for mo/da/yr.   */
 
914
            if (!strstr(f, "%D") && !strstr(f, "%x")) {
 
915
                uch *da, *mo, *yr;
 
916
                if (!(mo = strstr(f, "%b")) && !(mo = strstr(f, "%B"))
 
917
                                    && !(mo = strstr(f, "%h")))
 
918
                    mo = strstr(f, "%m");
 
919
                if (!(da = strstr(f, "%d")))
 
920
                    da = strstr(f, "%e");
 
921
                if (!(yr = strstr(f, "%y")))
 
922
                    yr = strstr(f, "%Y");
 
923
                if (yr && yr < mo)
 
924
                    result = DF_YMD;
 
925
                else if (da && da < mo)
 
926
                    result = DF_DMY;
 
927
            }
 
928
            CloseLocale(ll);
 
929
        }
 
930
        CloseLibrary(LocaleBase);
 
931
    }
 
932
    return result;
 
933
}
 
934
 
 
935
# endif /* 0 */
 
936
 
 
937
 
 
938
/************************/
 
939
/*  Function version()  */
 
940
/************************/
 
941
 
 
942
 
 
943
/* NOTE:  the following include depends upon the environment
 
944
 *        variable $Workbench to be set correctly.  (Set by
 
945
 *        default, by kickstart during startup)
 
946
 */
 
947
int WBversion = (int)
 
948
#include "ENV:Workbench"
 
949
;
 
950
 
 
951
void version(__G)
 
952
   __GDEF
 
953
{
 
954
/* Define buffers. */
 
955
 
 
956
   char buf1[16];  /* compiler name */
 
957
   char buf2[16];  /* revstamp */
 
958
   char buf3[16];  /* OS */
 
959
   char buf4[16];  /* Date */
 
960
/*   char buf5[16];  /* Time */
 
961
 
 
962
/* format "with" name strings */
 
963
 
 
964
#ifdef AMIGA
 
965
# ifdef __SASC
 
966
   strcpy(buf1,"SAS/C ");
 
967
# else
 
968
#  ifdef LATTICE
 
969
    strcpy(buf1,"Lattice C ");
 
970
#  else
 
971
#   ifdef AZTEC_C
 
972
     strcpy(buf1,"Manx Aztec C ");
 
973
#   else
 
974
     strcpy(buf1,"UNKNOWN ");
 
975
#   endif
 
976
#  endif
 
977
# endif
 
978
/* "under" */
 
979
  sprintf(buf3,"AmigaDOS v%d",WBversion);
 
980
#else
 
981
  strcpy(buf1,"Unknown compiler ");
 
982
  strcpy(buf3,"Unknown OS");
 
983
#endif
 
984
 
 
985
/* Define revision, date, and time strings.
 
986
 * NOTE:  Do not calculate run time, be sure to use time compiled.
 
987
 * Pass these strings via your makefile if undefined.
 
988
 */
 
989
 
 
990
#if defined(__VERSION__) && defined(__REVISION__)
 
991
  sprintf(buf2,"version %d.%d",__VERSION__,__REVISION__);
 
992
#else
 
993
# ifdef __VERSION__
 
994
  sprintf(buf2,"version %d",__VERSION__);
 
995
# else
 
996
  sprintf(buf2,"unknown version");
 
997
# endif
 
998
#endif
 
999
 
 
1000
#ifdef __DATE__
 
1001
  sprintf(buf4," on %s",__DATE__);
 
1002
#else
 
1003
  strcpy(buf4," unknown date");
 
1004
#endif
 
1005
 
 
1006
/******
 
1007
#ifdef __TIME__
 
1008
  sprintf(buf5," at %s",__TIME__);
 
1009
#else
 
1010
  strcpy(buf5," unknown time");
 
1011
#endif
 
1012
******/
 
1013
 
 
1014
/* Print strings using "CompiledWith" mask defined in unzip.c (used by all).
 
1015
 *  ("Compiled with %s%s for %s%s%s%s.")
 
1016
 */
 
1017
 
 
1018
   printf(LoadFarString(CompiledWith),
 
1019
     buf1,
 
1020
     buf2,
 
1021
     buf3,
 
1022
     buf4,
 
1023
     "",    /* buf5 not used */
 
1024
     "" );  /* buf6 not used */
 
1025
 
 
1026
} /* end function version() */
 
1027
 
 
1028
#endif /* !SFX */