Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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