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

« back to all changes in this revision

Viewing changes to flexos/flexos.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
  flexos.c
 
12
 
 
13
  FlexOS-specific routines for use with Info-ZIP's UnZip 5.2 and later.
 
14
 
 
15
  Based upon the MSDOS version of this file (msdos/msdos.c)
 
16
 
 
17
  Contains:  do_wild()
 
18
             mapattr()
 
19
             mapname()
 
20
             map2fat()
 
21
             checkdir()
 
22
             close_outfile()
 
23
             dateformat()
 
24
             version()
 
25
             _wildarg()
 
26
 
 
27
  ---------------------------------------------------------------------------*/
 
28
 
 
29
 
 
30
 
 
31
#define UNZIP_INTERNAL
 
32
#include "unzip.h"
 
33
 
 
34
#include <flexif.h>
 
35
 
 
36
/* The following should really be a static declaration,  but the compiler
 
37
   complains (crappy compiler can't cope with a static forward declaration).
 
38
 */
 
39
extern void map2fat OF((char *pathcomp, char *last_dot));
 
40
 
 
41
static int created_dir;        /* used by mapname(), checkdir() */
 
42
static int renamed_fullpath;   /* ditto */
 
43
 
 
44
/*****************************/
 
45
/*  Strings used in flexos.c  */
 
46
/*****************************/
 
47
 
 
48
#ifndef SFX
 
49
  static ZCONST char Far CantAllocateWildcard[] =
 
50
    "warning:  cannot allocate wildcard buffers\n";
 
51
#endif
 
52
static ZCONST char Far WarnDirTraversSkip[] =
 
53
  "warning:  skipped \"../\" path component(s) in %s\n";
 
54
static ZCONST char Far Creating[] = "   creating: %s\n";
 
55
static ZCONST char Far ConversionFailed[] =
 
56
  "mapname:  conversion of %s failed\n";
 
57
static ZCONST char Far PathTooLong[] = "checkdir error:  path too long: %s\n";
 
58
static ZCONST char Far CantCreateDir[] = "checkdir error:  cannot create %s\n\
 
59
                 unable to process %s.\n";
 
60
static ZCONST char Far DirIsntDirectory[] =
 
61
  "checkdir error:  %s exists but is not directory\n\
 
62
                 unable to process %s.\n";
 
63
static ZCONST char Far PathTooLongTrunc[] =
 
64
  "checkdir warning:  path too long; truncating\n                   %s\n\
 
65
                -> %s\n";
 
66
#if (!defined(SFX) || defined(SFX_EXDIR))
 
67
   static ZCONST char Far CantCreateExtractDir[] =
 
68
     "checkdir:  cannot create extraction directory: %s\n";
 
69
#endif
 
70
 
 
71
#include <dirent.h>
 
72
 
 
73
#ifndef SFX
 
74
 
 
75
/************************/
 
76
/*  Function do_wild()  */   /* identical to OS/2 version */
 
77
/************************/
 
78
 
 
79
char *do_wild(__G__ wildspec)
 
80
    __GDEF
 
81
    ZCONST char *wildspec;   /* only used first time on a given dir */
 
82
{
 
83
    static DIR *wild_dir = (DIR *)NULL;
 
84
    static ZCONST char *wildname;
 
85
    static char *dirname, matchname[FILNAMSIZ];
 
86
    static int notfirstcall=FALSE, have_dirname, dirnamelen;
 
87
    char *fnamestart;
 
88
    struct dirent *file;
 
89
 
 
90
    /* Even when we're just returning wildspec, we *always* do so in
 
91
     * matchname[]--calling routine is allowed to append four characters
 
92
     * to the returned string, and wildspec may be a pointer to argv[].
 
93
     */
 
94
    if (!notfirstcall) {    /* first call:  must initialize everything */
 
95
        notfirstcall = TRUE;
 
96
 
 
97
        if (!iswild(wildspec)) {
 
98
            strcpy(matchname, wildspec);
 
99
            have_dirname = FALSE;
 
100
            dir = NULL;
 
101
            return matchname;
 
102
        }
 
103
 
 
104
        /* break the wildspec into a directory part and a wildcard filename */
 
105
        if ((wildname = strrchr(wildspec, '/')) == (ZCONST char *)NULL &&
 
106
            (wildname = strrchr(wildspec, ':')) == (ZCONST char *)NULL) {
 
107
            dirname = ".";
 
108
            dirnamelen = 1;
 
109
            have_dirname = FALSE;
 
110
            wildname = wildspec;
 
111
        } else {
 
112
            ++wildname;     /* point at character after '/' or ':' */
 
113
            dirnamelen = (int)(wildname - wildspec);
 
114
            if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
 
115
                Info(slide, 1, ((char *)slide,
 
116
                  LoadFarString(CantAllocateWildcard)));
 
117
                strcpy(matchname, wildspec);
 
118
                return matchname;   /* but maybe filespec was not a wildcard */
 
119
            }
 
120
/* GRR:  cannot strip trailing char for opendir since might be "d:/" or "d:"
 
121
 *       (would have to check for "./" at end--let opendir handle it instead) */
 
122
            strncpy(dirname, wildspec, dirnamelen);
 
123
            dirname[dirnamelen] = '\0';   /* terminate for strcpy below */
 
124
            have_dirname = TRUE;
 
125
        }
 
126
        Trace((stderr, "do_wild:  dirname = [%s]\n", FnFilter1(dirname)));
 
127
 
 
128
        if ((wild_dir = opendir(dirname)) != (DIR *)NULL) {
 
129
            if (have_dirname) {
 
130
                strcpy(matchname, dirname);
 
131
                fnamestart = matchname + dirnamelen;
 
132
            } else
 
133
                fnamestart = matchname;
 
134
            while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
 
135
                Trace((stderr, "do_wild:  readdir returns %s\n",
 
136
                  FnFilter1(file->d_name)));
 
137
                strcpy(fnamestart, file->d_name);
 
138
                if (strrchr(fnamestart, '.') == (char *)NULL)
 
139
                    strcat(fnamestart, ".");
 
140
                if (match(fnamestart, wildname, 1) &&  /* 1 == ignore case */
 
141
                    /* skip "." and ".." directory entries */
 
142
                    strcmp(fnamestart, ".") && strcmp(fnamestart, "..")) {
 
143
                    Trace((stderr, "do_wild:  match() succeeds\n"));
 
144
                    /* remove trailing dot */
 
145
                    fnamestart += strlen(fnamestart) - 1;
 
146
                    if (*fnamestart == '.')
 
147
                        *fnamestart = '\0';
 
148
                    return matchname;
 
149
                }
 
150
            }
 
151
            /* if we get to here directory is exhausted, so close it */
 
152
            closedir(wild_dir);
 
153
            wild_dir = (DIR *)NULL;
 
154
        }
 
155
#ifdef DEBUG
 
156
        else {
 
157
            Trace((stderr, "do_wild:  opendir(%s) returns NULL\n",
 
158
              FnFilter1(dirname)));
 
159
        }
 
160
#endif /* DEBUG */
 
161
 
 
162
        /* return the raw wildspec in case that works (e.g., directory not
 
163
         * searchable, but filespec was not wild and file is readable) */
 
164
        strcpy(matchname, wildspec);
 
165
        return matchname;
 
166
    }
 
167
 
 
168
    /* last time through, might have failed opendir but returned raw wildspec */
 
169
    if (wild_dir == (DIR *)NULL) {
 
170
        notfirstcall = FALSE; /* nothing left to try--reset for new wildspec */
 
171
        if (have_dirname)
 
172
            free(dirname);
 
173
        return (char *)NULL;
 
174
    }
 
175
 
 
176
    /* If we've gotten this far, we've read and matched at least one entry
 
177
     * successfully (in a previous call), so dirname has been copied into
 
178
     * matchname already.
 
179
     */
 
180
    if (have_dirname) {
 
181
        /* strcpy(matchname, dirname); */
 
182
        fnamestart = matchname + dirnamelen;
 
183
    } else
 
184
        fnamestart = matchname;
 
185
    while ((file = readdir(wild_dir)) != (struct dirent *)NULL) {
 
186
        Trace((stderr, "do_wild:  readdir returns %s\n",
 
187
          FnFilter1(file->d_name)));
 
188
        strcpy(fnamestart, file->d_name);
 
189
        if (strrchr(fnamestart, '.') == (char *)NULL)
 
190
            strcat(fnamestart, ".");
 
191
        if (match(fnamestart, wildname, 1)) {   /* 1 == ignore case */
 
192
            Trace((stderr, "do_wild:  match() succeeds\n"));
 
193
            /* remove trailing dot */
 
194
            fnamestart += strlen(fnamestart) - 1;
 
195
            if (*fnamestart == '.')
 
196
                *fnamestart = '\0';
 
197
            return matchname;
 
198
        }
 
199
    }
 
200
 
 
201
    closedir(wild_dir);     /* have read at least one entry; nothing left */
 
202
    wild_dir = (DIR *)NULL;
 
203
    notfirstcall = FALSE;   /* reset for new wildspec */
 
204
    if (have_dirname)
 
205
        free(dirname);
 
206
    return (char *)NULL;
 
207
 
 
208
} /* end function do_wild() */
 
209
 
 
210
#endif /* !SFX */
 
211
 
 
212
 
 
213
 
 
214
/**********************/
 
215
/* Function mapattr() */
 
216
/**********************/
 
217
 
 
218
int mapattr(__G)
 
219
    __GDEF
 
220
{
 
221
    /* set archive bit (file is not backed up): */
 
222
    G.pInfo->file_attr = (unsigned)(G.crec.external_file_attributes & 7) | 32;
 
223
    return 0;
 
224
}
 
225
 
 
226
 
 
227
 
 
228
/**********************/
 
229
/* Function mapname() */
 
230
/**********************/
 
231
 
 
232
int mapname(__G__ renamed)
 
233
    __GDEF
 
234
    int renamed;
 
235
/*
 
236
 * returns:
 
237
 *  MPN_OK          - no problem detected
 
238
 *  MPN_INF_TRUNC   - caution (truncated filename)
 
239
 *  MPN_INF_SKIP    - info "skip entry" (dir doesn't exist)
 
240
 *  MPN_ERR_SKIP    - error -> skip entry
 
241
 *  MPN_ERR_TOOLONG - error -> path is too long
 
242
 *  MPN_NOMEM       - error (memory allocation failed) -> skip entry
 
243
 *  [also MPN_VOL_LABEL, MPN_CREATED_DIR]
 
244
 */
 
245
{
 
246
    char pathcomp[FILNAMSIZ];      /* path-component buffer */
 
247
    char *pp, *cp=(char *)NULL;    /* character pointers */
 
248
    char *lastsemi=(char *)NULL;   /* pointer to last semi-colon in pathcomp */
 
249
    char *last_dot=(char *)NULL;   /* last dot not converted to underscore */
 
250
    int dotname = FALSE;           /* path component begins with dot? */
 
251
    int killed_ddot = FALSE;       /* is set when skipping "../" pathcomp */
 
252
    int error = MPN_OK;
 
253
    register unsigned workch;      /* hold the character being tested */
 
254
 
 
255
 
 
256
    if (G.pInfo->vollabel)
 
257
        return MPN_VOL_LABEL;   /* Cannot set disk volume labels in FlexOS */
 
258
 
 
259
/*---------------------------------------------------------------------------
 
260
    Initialize various pointers and counters and stuff.
 
261
  ---------------------------------------------------------------------------*/
 
262
 
 
263
    /* can create path as long as not just freshening, or if user told us */
 
264
    G.create_dirs = (!uO.fflag || renamed);
 
265
 
 
266
    created_dir = FALSE;        /* not yet */
 
267
    renamed_fullpath = FALSE;
 
268
 
 
269
    if (renamed) {
 
270
        cp = G.filename - 1;    /* point to beginning of renamed name... */
 
271
        while (*++cp)
 
272
            if (*cp == '\\')    /* convert backslashes to forward */
 
273
                *cp = '/';
 
274
        cp = G.filename;
 
275
        /* use temporary rootpath if user gave full pathname */
 
276
        if (G.filename[0] == '/') {
 
277
            renamed_fullpath = TRUE;
 
278
            pathcomp[0] = '/';  /* copy the '/' and terminate */
 
279
            pathcomp[1] = '\0';
 
280
            ++cp;
 
281
        } else if (isalpha((uch)G.filename[0]) && G.filename[1] == ':') {
 
282
            renamed_fullpath = TRUE;
 
283
            pp = pathcomp;
 
284
            *pp++ = *cp++;      /* copy the "d:" (+ '/', possibly) */
 
285
            *pp++ = *cp++;
 
286
            if (*cp == '/')
 
287
                *pp++ = *cp++;  /* otherwise add "./"? */
 
288
            *pp = '\0';
 
289
        }
 
290
    }
 
291
 
 
292
    /* pathcomp is ignored unless renamed_fullpath is TRUE: */
 
293
    if ((error = checkdir(__G__ pathcomp, INIT)) != 0) /* initialize path buf */
 
294
        return error;           /* ...unless no mem or vol label on hard disk */
 
295
 
 
296
    *pathcomp = '\0';           /* initialize translation buffer */
 
297
    pp = pathcomp;              /* point to translation buffer */
 
298
    if (!renamed) {             /* cp already set if renamed */
 
299
        if (uO.jflag)           /* junking directories */
 
300
            cp = (char *)strrchr(G.filename, '/');
 
301
        if (cp == (char *)NULL) /* no '/' or not junking dirs */
 
302
            cp = G.filename;    /* point to internal zipfile-member pathname */
 
303
        else
 
304
            ++cp;               /* point to start of last component of path */
 
305
    }
 
306
 
 
307
/*---------------------------------------------------------------------------
 
308
    Begin main loop through characters in filename.
 
309
  ---------------------------------------------------------------------------*/
 
310
 
 
311
    while ((workch = (uch)*cp++) != 0) {
 
312
 
 
313
        switch (workch) {
 
314
            case '/':             /* can assume -j flag not given */
 
315
                *pp = '\0';
 
316
                map2fat(pathcomp, last_dot);   /* 8.3 truncation (in place) */
 
317
                last_dot = (char *)NULL;
 
318
                if (strcmp(pathcomp, ".") == 0) {
 
319
                    /* don't bother appending "./" to the path */
 
320
                    *pathcomp = '\0';
 
321
                } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
 
322
                    /* "../" dir traversal detected, skip over it */
 
323
                    *pathcomp = '\0';
 
324
                    killed_ddot = TRUE;     /* set "show message" flag */
 
325
                }
 
326
                /* when path component is not empty, append it now */
 
327
                if (*pathcomp != '\0' &&
 
328
                    ((error = checkdir(__G__ pathcomp, APPEND_DIR))
 
329
                     & MPN_MASK) > MPN_INF_TRUNC)
 
330
                    return error;
 
331
                pp = pathcomp;    /* reset conversion buffer for next piece */
 
332
                lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
 
333
                break;
 
334
 
 
335
            case '.':
 
336
                if (pp == pathcomp) {     /* nothing appended yet... */
 
337
                    if (*cp == '.' && cp[1] == '/') {   /* "../" */
 
338
                        *pp++ = '.';      /* add first dot, unchanged... */
 
339
                        ++cp;             /* skip second dot, since it will */
 
340
                    } else {              /*  be "added" at end of if-block */
 
341
                        *pp++ = '_';      /* FAT doesn't allow null filename */
 
342
                        dotname = TRUE;   /*  bodies, so map .exrc -> _.exrc */
 
343
                    }                     /*  (extra '_' now, "dot" below) */
 
344
                } else if (dotname) {     /* found a second dot, but still */
 
345
                    dotname = FALSE;      /*  have extra leading underscore: */
 
346
                    *pp = '\0';           /*  remove it by shifting chars */
 
347
                    pp = pathcomp + 1;    /*  left one space (e.g., .p1.p2: */
 
348
                    while (pp[1]) {       /*  __p1 -> _p1_p2 -> _p1.p2 when */
 
349
                        *pp = pp[1];      /*  finished) [opt.:  since first */
 
350
                        ++pp;             /*  two chars are same, can start */
 
351
                    }                     /*  shifting at second position] */
 
352
                }
 
353
                last_dot = pp;    /* point at last dot so far... */
 
354
                *pp++ = '_';      /* convert dot to underscore for now */
 
355
                break;
 
356
 
 
357
            /* drive names are not stored in zipfile, so no colons allowed;
 
358
             *  no brackets or most other punctuation either (all of which
 
359
             *  can appear in Unix-created archives; backslash is particularly
 
360
             *  bad unless all necessary directories exist) */
 
361
            case '[':          /* these punctuation characters forbidden */
 
362
            case ']':          /*  only on plain FAT file systems */
 
363
            case '+':
 
364
            case ',':
 
365
            case '=':
 
366
            case ':':           /* special shell characters of command.com */
 
367
            case '\\':          /*  (device and directory limiters, wildcard */
 
368
            case '"':           /*  characters, stdin/stdout redirection and */
 
369
            case '<':           /*  pipe indicators and the quote sign) are */
 
370
            case '>':           /*  never allowed in filenames on (V)FAT */
 
371
            case '|':
 
372
            case '*':
 
373
            case '?':
 
374
                *pp++ = '_';
 
375
                break;
 
376
 
 
377
            case ';':             /* start of VMS version? */
 
378
                lastsemi = pp;
 
379
                break;
 
380
 
 
381
            case ' ':                      /* change spaces to underscores */
 
382
                if (uO.sflag)              /*  only if requested */
 
383
                    *pp++ = '_';
 
384
                else
 
385
                    *pp++ = (char)workch;
 
386
                break;
 
387
 
 
388
            default:
 
389
                /* allow ASCII 255 and European characters in filenames: */
 
390
                if (isprint(workch) || workch >= 127)
 
391
                    *pp++ = (char)workch;
 
392
 
 
393
        } /* end switch */
 
394
    } /* end while loop */
 
395
 
 
396
    /* Show warning when stripping insecure "parent dir" path components */
 
397
    if (killed_ddot && QCOND2) {
 
398
        Info(slide, 0, ((char *)slide, LoadFarString(WarnDirTraversSkip),
 
399
          FnFilter1(G.filename)));
 
400
        if (!(error & ~MPN_MASK))
 
401
            error = (error & MPN_MASK) | PK_WARN;
 
402
    }
 
403
 
 
404
/*---------------------------------------------------------------------------
 
405
    Report if directory was created (and no file to create:  filename ended
 
406
    in '/'), check name to be sure it exists, and combine path and name be-
 
407
    fore exiting.
 
408
  ---------------------------------------------------------------------------*/
 
409
 
 
410
    if (G.filename[strlen(G.filename) - 1] == '/') {
 
411
        checkdir(__G__ G.filename, GETPATH);
 
412
        if (created_dir) {
 
413
            if (QCOND2) {
 
414
                Info(slide, 0, ((char *)slide, LoadFarString(Creating),
 
415
                  FnFilter1(G.filename)));
 
416
            }
 
417
            /* set dir time (note trailing '/') */
 
418
            return (error & ~MPN_MASK) | MPN_CREATED_DIR;
 
419
        }
 
420
        /* dir existed already; don't look for data to extract */
 
421
        return (error & ~MPN_MASK) | MPN_INF_SKIP;
 
422
    }
 
423
 
 
424
    *pp = '\0';                   /* done with pathcomp:  terminate it */
 
425
 
 
426
    /* if not saving them, remove VMS version numbers (appended ";###") */
 
427
    if (!uO.V_flag && lastsemi) {
 
428
        pp = lastsemi;            /* semi-colon was omitted:  expect all #'s */
 
429
        while (isdigit((uch)(*pp)))
 
430
            ++pp;
 
431
        if (*pp == '\0')          /* only digits between ';' and end:  nuke */
 
432
            *lastsemi = '\0';
 
433
    }
 
434
 
 
435
    map2fat(pathcomp, last_dot);  /* 8.3 truncation (in place) */
 
436
 
 
437
    if (*pathcomp == '\0') {
 
438
        Info(slide, 1, ((char *)slide, LoadFarString(ConversionFailed),
 
439
          FnFilter1(G.filename)));
 
440
        return (error & ~MPN_MASK) | MPN_ERR_SKIP;
 
441
    }
 
442
 
 
443
    checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
 
444
    checkdir(__G__ G.filename, GETPATH);
 
445
 
 
446
    return error;
 
447
 
 
448
} /* end function mapname() */
 
449
 
 
450
 
 
451
 
 
452
 
 
453
/**********************/
 
454
/* Function map2fat() */
 
455
/**********************/
 
456
 
 
457
static void map2fat(pathcomp, last_dot)
 
458
    char *pathcomp, *last_dot;
 
459
{
 
460
    char *pEnd = pathcomp + strlen(pathcomp);
 
461
 
 
462
/*---------------------------------------------------------------------------
 
463
    Case 1:  filename has no dot, so figure out if we should add one.  Note
 
464
    that the algorithm does not try to get too fancy:  if there are no dots
 
465
    already, the name either gets truncated at 8 characters or the last un-
 
466
    derscore is converted to a dot (only if more characters are saved that
 
467
    way).  In no case is a dot inserted between existing characters.
 
468
 
 
469
              GRR:  have problem if filename is volume label??
 
470
 
 
471
  ---------------------------------------------------------------------------*/
 
472
 
 
473
    /* pEnd = pathcomp + strlen(pathcomp); */
 
474
    if (last_dot == (char *)NULL) {   /* no dots:  check for underscores... */
 
475
        char *plu = strrchr(pathcomp, '_');   /* pointer to last underscore */
 
476
 
 
477
        if (plu == (char *)NULL) {  /* no dots, no underscores:  truncate at */
 
478
            if (pEnd > pathcomp+8)  /* 8 chars (could insert '.' and keep 11) */
 
479
                *(pEnd = pathcomp+8) = '\0';
 
480
        } else if (MIN(plu - pathcomp, 8) + MIN(pEnd - plu - 1, 3) > 8) {
 
481
            last_dot = plu;       /* be lazy:  drop through to next if-block */
 
482
        } else if ((pEnd - pathcomp) > 8)    /* more fits into just basename */
 
483
            pathcomp[8] = '\0';    /* than if convert last underscore to dot */
 
484
        /* else whole thing fits into 8 chars or less:  no change */
 
485
    }
 
486
 
 
487
/*---------------------------------------------------------------------------
 
488
    Case 2:  filename has dot in it, so truncate first half at 8 chars (shift
 
489
    extension if necessary) and second half at three.
 
490
  ---------------------------------------------------------------------------*/
 
491
 
 
492
    if (last_dot != (char *)NULL) {   /* one dot (or two, in the case of */
 
493
        *last_dot = '.';              /*  "..") is OK:  put it back in */
 
494
 
 
495
        if ((last_dot - pathcomp) > 8) {
 
496
            char *p=last_dot, *q=pathcomp+8;
 
497
            int i;
 
498
 
 
499
            for (i = 0;  (i < 4) && *p;  ++i)  /* too many chars in basename: */
 
500
                *q++ = *p++;                   /*  shift extension left and */
 
501
            *q = '\0';                         /*  truncate/terminate it */
 
502
        } else if ((pEnd - last_dot) > 4)
 
503
            last_dot[4] = '\0';                /* too many chars in extension */
 
504
        /* else filename is fine as is:  no change */
 
505
    }
 
506
} /* end function map2fat() */
 
507
 
 
508
 
 
509
 
 
510
 
 
511
/***********************/
 
512
/* Function checkdir() */
 
513
/***********************/
 
514
 
 
515
int checkdir(__G__ pathcomp, flag)
 
516
    __GDEF
 
517
    char *pathcomp;
 
518
    int flag;
 
519
/*
 
520
 * returns:
 
521
 *  MPN_OK          - no problem detected
 
522
 *  MPN_INF_TRUNC   - (on APPEND_NAME) truncated filename
 
523
 *  MPN_INF_SKIP    - path doesn't exist, not allowed to create
 
524
 *  MPN_ERR_SKIP    - path doesn't exist, tried to create and failed; or path
 
525
 *                    exists and is not a directory, but is supposed to be
 
526
 *  MPN_ERR_TOOLONG - path is too long
 
527
 *  MPN_NOMEM       - can't allocate memory for filename buffers
 
528
 */
 
529
{
 
530
    static int rootlen = 0;   /* length of rootpath */
 
531
    static char *rootpath;    /* user's "extract-to" directory */
 
532
    static char *buildpath;   /* full path (so far) to extracted file */
 
533
    static char *end;         /* pointer to end of buildpath ('\0') */
 
534
 
 
535
#   define FN_MASK   7
 
536
#   define FUNCTION  (flag & FN_MASK)
 
537
 
 
538
 
 
539
/*---------------------------------------------------------------------------
 
540
    APPEND_DIR:  append the path component to the path being built and check
 
541
    for its existence.  If doesn't exist and we are creating directories, do
 
542
    so for this one; else signal success or error as appropriate.
 
543
  ---------------------------------------------------------------------------*/
 
544
 
 
545
    if (FUNCTION == APPEND_DIR) {
 
546
        int too_long = FALSE;
 
547
 
 
548
        Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
 
549
        while ((*end = *pathcomp++) != '\0')
 
550
            ++end;
 
551
 
 
552
        /* GRR:  could do better check, see if overrunning buffer as we go:
 
553
         * check end-buildpath after each append, set warning variable if
 
554
         * within 20 of FILNAMSIZ; then if var set, do careful check when
 
555
         * appending.  Clear variable when begin new path. */
 
556
 
 
557
        if ((end-buildpath) > FILNAMSIZ-3)  /* need '/', one-char name, '\0' */
 
558
            too_long = TRUE;                /* check if extracting directory? */
 
559
        if (stat(buildpath, &G.statbuf))    /* path doesn't exist */
 
560
        {
 
561
            if (!G.create_dirs) { /* told not to create (freshening) */
 
562
                free(buildpath);
 
563
                return MPN_INF_SKIP;    /* path doesn't exist: nothing to do */
 
564
            }
 
565
            if (too_long) {
 
566
                Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong),
 
567
                  FnFilter1(buildpath)));
 
568
                free(buildpath);
 
569
                /* no room for filenames:  fatal */
 
570
                return MPN_ERR_TOOLONG;
 
571
            }
 
572
            if (mkdir(buildpath, 0777) == -1) {   /* create the directory */
 
573
                Info(slide, 1, ((char *)slide, LoadFarString(CantCreateDir),
 
574
                  FnFilter2(buildpath), FnFilter1(G.filename)));
 
575
                free(buildpath);
 
576
                /* path didn't exist, tried to create, failed */
 
577
                return MPN_ERR_SKIP;
 
578
            }
 
579
            created_dir = TRUE;
 
580
        } else if (!S_ISDIR(G.statbuf.st_mode)) {
 
581
            Info(slide, 1, ((char *)slide, LoadFarString(DirIsntDirectory),
 
582
              FnFilter2(buildpath), FnFilter1(G.filename)));
 
583
            free(buildpath);
 
584
            /* path existed but wasn't dir */
 
585
            return MPN_ERR_SKIP;
 
586
        }
 
587
        if (too_long) {
 
588
            Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong),
 
589
              FnFilter1(buildpath)));
 
590
            free(buildpath);
 
591
            /* no room for filenames:  fatal */
 
592
            return MPN_ERR_TOOLONG;
 
593
        }
 
594
        *end++ = '/';
 
595
        *end = '\0';
 
596
        Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
 
597
        return MPN_OK;
 
598
 
 
599
    } /* end if (FUNCTION == APPEND_DIR) */
 
600
 
 
601
/*---------------------------------------------------------------------------
 
602
    GETPATH:  copy full path to the string pointed at by pathcomp, and free
 
603
    buildpath.
 
604
  ---------------------------------------------------------------------------*/
 
605
 
 
606
    if (FUNCTION == GETPATH) {
 
607
        strcpy(pathcomp, buildpath);
 
608
        Trace((stderr, "getting and freeing path [%s]\n",
 
609
          FnFilter1(pathcomp)));
 
610
        free(buildpath);
 
611
        buildpath = end = (char *)NULL;
 
612
        return MPN_OK;
 
613
    }
 
614
 
 
615
/*---------------------------------------------------------------------------
 
616
    APPEND_NAME:  assume the path component is the filename; append it and
 
617
    return without checking for existence.
 
618
  ---------------------------------------------------------------------------*/
 
619
 
 
620
    if (FUNCTION == APPEND_NAME) {
 
621
        Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
 
622
        while ((*end = *pathcomp++) != '\0') {
 
623
            ++end;
 
624
            if ((end-buildpath) >= FILNAMSIZ) {
 
625
                *--end = '\0';
 
626
                Info(slide, 1, ((char *)slide, LoadFarString(PathTooLongTrunc),
 
627
                  FnFilter1(G.filename), FnFilter2(buildpath)));
 
628
                return MPN_INF_TRUNC;   /* filename truncated */
 
629
            }
 
630
        }
 
631
        Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
 
632
        /* could check for existence here, prompt for new name... */
 
633
        return MPN_OK;
 
634
    }
 
635
 
 
636
/*---------------------------------------------------------------------------
 
637
    INIT:  allocate and initialize buffer space for the file currently being
 
638
    extracted.  If file was renamed with an absolute path, don't prepend the
 
639
    extract-to path.
 
640
  ---------------------------------------------------------------------------*/
 
641
 
 
642
    if (FUNCTION == INIT) {
 
643
        Trace((stderr, "initializing buildpath to "));
 
644
        /* allocate space for full filename, root path, and maybe "./" */
 
645
        if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+3)) ==
 
646
            (char *)NULL)
 
647
            return MPN_NOMEM;
 
648
        if (renamed_fullpath) {   /* pathcomp = valid data */
 
649
            end = buildpath;
 
650
            while ((*end = *pathcomp++) != '\0')
 
651
                ++end;
 
652
        } else if (rootlen > 0) {
 
653
            strcpy(buildpath, rootpath);
 
654
            end = buildpath + rootlen;
 
655
        } else {
 
656
            *buildpath = '\0';
 
657
            end = buildpath;
 
658
        }
 
659
        Trace((stderr, "[%s]\n", FnFilter1(buildpath)));
 
660
        return MPN_OK;
 
661
    }
 
662
 
 
663
/*---------------------------------------------------------------------------
 
664
    ROOT:  if appropriate, store the path in rootpath and create it if neces-
 
665
    sary; else assume it's a zipfile member and return.  This path segment
 
666
    gets used in extracting all members from every zipfile specified on the
 
667
    command line.  Note that under FlexOS, if a candidate extract-to
 
668
    directory specification includes a drive letter (leading "x:"), it is
 
669
    treated just as if it had a trailing '/'--that is, one directory level
 
670
    will be created if the path doesn't exist, unless this is otherwise pro-
 
671
    hibited (e.g., freshening).
 
672
  ---------------------------------------------------------------------------*/
 
673
 
 
674
#if (!defined(SFX) || defined(SFX_EXDIR))
 
675
    if (FUNCTION == ROOT) {
 
676
        Trace((stderr, "initializing root path to [%s]\n",
 
677
          FnFilter1(pathcomp)));
 
678
        if (pathcomp == (char *)NULL) {
 
679
            rootlen = 0;
 
680
            return MPN_OK;
 
681
        }
 
682
        if (rootlen > 0)        /* rootpath was already set, nothing to do */
 
683
            return MPN_OK;
 
684
        if ((rootlen = strlen(pathcomp)) > 0) {
 
685
            int had_trailing_pathsep=FALSE, add_dot=FALSE;
 
686
            char *tmproot;
 
687
 
 
688
            if ((tmproot = (char *)malloc(rootlen+3)) == (char *)NULL) {
 
689
                rootlen = 0;
 
690
                return MPN_NOMEM;
 
691
            }
 
692
            strcpy(tmproot, pathcomp);
 
693
            if (tmproot[rootlen-1] == '/' || tmproot[rootlen-1] == '\\') {
 
694
                tmproot[--rootlen] = '\0';
 
695
                had_trailing_pathsep = TRUE;
 
696
            }
 
697
            if (tmproot[rootlen-1] == ':') {
 
698
                if (!had_trailing_pathsep)  /* i.e., original wasn't "xxx:/" */
 
699
                    add_dot = TRUE;     /* relative path: add '.' before '/' */
 
700
            } else if (rootlen > 0) &&  /* need not check "xxx:." and "xxx:/" */
 
701
                       (SSTAT(tmproot, &G.statbuf) ||
 
702
                        !S_ISDIR(G.statbuf.st_mode))
 
703
            {
 
704
                /* path does not exist */
 
705
                if (!G.create_dirs /* || iswild(tmproot) */ ) {
 
706
                    free(tmproot);
 
707
                    rootlen = 0;
 
708
                    /* treat as stored file */
 
709
                    return MPN_INF_SKIP;
 
710
                }
 
711
/* GRR:  scan for wildcard characters?  OS-dependent...
 
712
 * if find any, return MPN_INF_SKIP: treat as stored file(s) */
 
713
                /* create directory (could add loop here scanning tmproot
 
714
                 * to create more than one level, but really necessary?) */
 
715
                if (mkdir(tmproot, 0777) == -1) {
 
716
                    Info(slide, 1, ((char *)slide,
 
717
                      LoadFarString(CantCreateExtractDir),
 
718
                      FnFilter1(tmproot)));
 
719
                    free(tmproot);
 
720
                    rootlen = 0;
 
721
                    /* path didn't exist, tried to create, and failed: */
 
722
                    /* file exists, or 2+ subdir levels required */
 
723
                    return MPN_ERR_SKIP;
 
724
                }
 
725
            }
 
726
            if (add_dot)                    /* had just "x:", make "x:." */
 
727
                tmproot[rootlen++] = '.';
 
728
            tmproot[rootlen++] = '/';
 
729
            tmproot[rootlen] = '\0';
 
730
            if ((rootpath = (char *)realloc(tmproot, rootlen+1)) == NULL) {
 
731
                free(tmproot);
 
732
                rootlen = 0;
 
733
                return MPN_NOMEM;
 
734
            }
 
735
            Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
 
736
        }
 
737
        return MPN_OK;
 
738
    }
 
739
#endif /* !SFX || SFX_EXDIR */
 
740
 
 
741
/*---------------------------------------------------------------------------
 
742
    END:  free rootpath, immediately prior to program exit.
 
743
  ---------------------------------------------------------------------------*/
 
744
 
 
745
    if (FUNCTION == END) {
 
746
        Trace((stderr, "freeing rootpath\n"));
 
747
        if (rootlen > 0) {
 
748
            free(rootpath);
 
749
            rootlen = 0;
 
750
        }
 
751
        return MPN_OK;
 
752
    }
 
753
 
 
754
    return MPN_INVALID; /* should never reach */
 
755
 
 
756
} /* end function checkdir() */
 
757
 
 
758
 
 
759
 
 
760
 
 
761
/****************************/
 
762
/* Function close_outfile() */
 
763
/****************************/
 
764
 
 
765
void close_outfile(__G)
 
766
    __GDEF
 
767
 /*
 
768
  * FlexOS VERSION
 
769
  *
 
770
  * Set the output file date/time stamp according to information from the
 
771
  * zipfile directory record for this member, then close the file and set
 
772
  * its permissions (archive, hidden, read-only, system).  Aside from closing
 
773
  * the file, this routine is optional (but most compilers support it).
 
774
  */
 
775
{
 
776
    DISKFILE    df;
 
777
    LONG        fnum;
 
778
 
 
779
    struct {                /* date and time words */
 
780
        union {             /* DOS file modification time word */
 
781
            ush ztime;
 
782
            struct {
 
783
                unsigned zt_se : 5;
 
784
                unsigned zt_mi : 6;
 
785
                unsigned zt_hr : 5;
 
786
            } _tf;
 
787
        } _t;
 
788
        union {             /* DOS file modification date word */
 
789
            ush zdate;
 
790
            struct {
 
791
                unsigned zd_dy : 5;
 
792
                unsigned zd_mo : 4;
 
793
                unsigned zd_yr : 7;
 
794
            } _df;
 
795
        } _d;
 
796
    } zt;
 
797
 
 
798
#ifdef USE_EF_UT_TIME
 
799
    iztimes z_utime;
 
800
    struct tm *t;
 
801
#endif /* ?USE_EF_UT_TIME */
 
802
 
 
803
    fclose(G.outfile);
 
804
 
 
805
    if ((fnum = s_open(A_SET, G.filename)) < 0) {
 
806
        Info(slide, 0x201, ((char *)slide,
 
807
          "warning:  cannot open %s to set the time\n",
 
808
          FnFilter1(G.filename)));
 
809
        return;
 
810
    }
 
811
 
 
812
    if (s_get(T_FILE, fnum, &df, DSKFSIZE) < 0) {
 
813
        s_close(0, fnum);
 
814
 
 
815
        Info(slide, 0x201, ((char *)slide,
 
816
          "warning:  cannot get info on %s\n", FnFilter1(G.filename)));
 
817
        return;
 
818
    }
 
819
 
 
820
/*---------------------------------------------------------------------------
 
821
    Copy and/or convert time and date variables, if necessary; then fill in
 
822
    the file time/date.
 
823
  ---------------------------------------------------------------------------*/
 
824
 
 
825
#ifdef USE_EF_UT_TIME
 
826
    if (G.extra_field &&
 
827
#ifdef IZ_CHECK_TZ
 
828
        G.tz_is_valid &&
 
829
#endif
 
830
        (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
 
831
         G.lrec.last_mod_dos_datetime, &z_utime, NULL) & EB_UT_FL_MTIME))
 
832
    {
 
833
        TTrace((stderr, "close_outfile:  Unix e.f. modif. time = %ld\n",
 
834
          z_utime.mtime));
 
835
        t = localtime(&(z_utime.mtime));
 
836
    } else
 
837
        t = (struct tm *)NULL;
 
838
    if (t != (struct tm *)NULL) {
 
839
        if (t->tm_year < 80) {
 
840
            df.df_modyear = 1980;
 
841
            df.df_modmonth = 1;
 
842
            df.df_modday = 1;
 
843
            df.df_modhr = 0;
 
844
            df.df_modmin = 0;
 
845
            df.df_modsec = 0;
 
846
        } else {
 
847
            df.df_modyear = t->tm_year + 1900;
 
848
            df.df_modmonth = t->tm_mon + 1;
 
849
            df.df_modday = t->tm_mday;
 
850
            df.df_modhr = t->tm_hour;
 
851
            df.df_modmin = t->tm_min;
 
852
            df.df_modsec = t->tm_sec;
 
853
        }
 
854
    } else
 
855
#endif /* ?USE_EF_UX_TIME */
 
856
    {
 
857
        zt._t.ztime = (ush)(G.lrec.last_mod_dos_datetime) & 0xffff;
 
858
        zt._d.zdate = (ush)(G.lrec.last_mod_dos_datetime >> 16);
 
859
 
 
860
        df.df_modyear = 1980 + zt._d._df.zd_yr;
 
861
        df.df_modmonth = zt._d._df.zd_mo;
 
862
        df.df_modday = zt._d._df.zd_dy;
 
863
        df.df_modhr = zt._t._tf.zt_hr;
 
864
        df.df_modmin = zt._t._tf.zt_mi;
 
865
        df.df_modsec = zt._t._tf.zt_se << 1;
 
866
    }
 
867
 
 
868
/*---------------------------------------------------------------------------
 
869
    Fill in the file attributes.
 
870
  ---------------------------------------------------------------------------*/
 
871
 
 
872
    df.df_attr1 = (UBYTE)G.pInfo->file_attr;
 
873
 
 
874
/*---------------------------------------------------------------------------
 
875
    Now we try to set the attributes & date/time.
 
876
  ---------------------------------------------------------------------------*/
 
877
 
 
878
    if (s_set(T_FILE, fnum, &df, DSKFSIZE) < 0)
 
879
        Info(slide, 0x201, ((char *)slide,
 
880
          "warning:  cannot set info for %s\n", FnFilter1(G.filename)));
 
881
 
 
882
    s_close(0, fnum);
 
883
}
 
884
 
 
885
#ifndef SFX
 
886
 
 
887
/*************************/
 
888
/* Function dateformat() */
 
889
/*************************/
 
890
 
 
891
int dateformat()
 
892
{
 
893
    return DF_DMY;   /* default for systems without locale info */
 
894
}
 
895
 
 
896
/************************/
 
897
/*  Function version()  */
 
898
/************************/
 
899
 
 
900
void version(__G)
 
901
    __GDEF
 
902
{
 
903
    int len;
 
904
 
 
905
    len = sprintf((char *)slide, LoadFarString(CompiledWith),
 
906
            "MetaWare High C",
 
907
            "",
 
908
            "FlexOS",
 
909
            " (16-bit, big)",
 
910
 
 
911
#ifdef __DATE__
 
912
      " on ", __DATE__
 
913
#else
 
914
      "", ""
 
915
#endif
 
916
    );
 
917
 
 
918
    (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
 
919
}
 
920
 
 
921
#endif /* !SFX */
 
922
 
 
923
/************************/
 
924
/*  Function _wildarg() */
 
925
/************************/
 
926
 
 
927
/* This prevents the PORTLIB startup code from preforming argument globbing */
 
928
 
 
929
_wildarg() {}