Subversion Repositories Kolibri OS

Rev

Rev 6745 | Rev 6775 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6725 siemargl 1
/*
2
Kolibri OS port for gcc 5.4
3
 
4
Started by Siemargl @Nov 2016
5
Borrowed code parts from other unzip ports
6
 
7
howto make:
8
go in unzip60 directory (below this file) and
9
>make -f kolibri\makefile.gcc
10
 
11
Contains:
12
    version()
13
    mapattr()
6745 siemargl 14
    mapname()
6725 siemargl 15
    checkdir()
6745 siemargl 16
    close_outfile()
17
    get_extattribs()
18
    do_wild()
6725 siemargl 19
 
6745 siemargl 20
todo
21
	russian filenames in arh
22
	datetime restore
23
	overwrite request not in stderr
24
 
25
	too many open files error EMFILE when DEBUG - error in newlib open. fixed
26
	-d dir error.  Use -ddir or -d dir/
27
 
28
	release, sizing removing old compression methods or zlib
6725 siemargl 29
*/
30
 
31
#define FATTR   FS_HIDDEN+FS_SYSTEM+FS_SUBDIR
32
 
33
 
34
 
35
#define UNZIP_INTERNAL
36
#include "unzip.h"
37
 
38
// Siemargl fork of Kolibri system API
39
#include "kos32sys1.h"
40
 
41
/********************************************************************************************************************/
42
/***  Function version()  */
43
/********************************************************************************************************************/
44
 
45
void version(__G)
46
    __GDEF
47
{
48
    sprintf((char *)slide, LoadFarString(CompiledWith),
49
#if defined(__TINYC__)
50
      "TinyC", "",
51
#elif defined(__GNUC__)
52
      "GNU C ", __VERSION__,
53
#else
54
      "(unknown compiler) ","",
55
#endif
56
      "KolibriOS ",
57
 
58
#ifdef __POWERPC__
59
      "(PowerPC)",
60
#else
61
# ifdef __INTEL__
62
      "(x86)",
63
# else
64
      "(unknown)",   /* someday we may have other architectures... */
65
# endif
66
#endif
67
 
68
#ifdef __DATE__
69
      " on ", __DATE__
70
#else
71
      "", ""
72
#endif
73
    );
74
 
75
    (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
76
 
77
} /* end function version() */
78
 
79
 
80
/********************************************************************************************************************/
81
/*** Function mapattr() */
82
/********************************************************************************************************************/
83
 
84
/* Identical to MS-DOS, OS/2 versions.  However, NT has a lot of extra
85
 * permission stuff, so this function should probably be extended in the
86
 * future. */
87
 
88
int mapattr(__G)
89
    __GDEF
90
{
91
    /* set archive bit for file entries (file is not backed up): */
92
    G.pInfo->file_attr = ((unsigned)G.crec.external_file_attributes |
93
      (G.crec.external_file_attributes & FS_SUBDIR ?
94
 
95
    return 0;
96
 
97
} /* end function mapattr() */
98
 
99
 
100
/********************************************************************************************************************/
6727 siemargl 101
/***  Function mapname()  */
6725 siemargl 102
/********************************************************************************************************************/
103
 
104
int mapname(__G__ renamed)
105
    __GDEF
106
    int renamed;
107
/*
108
 * returns:
109
 *  MPN_OK          - no problem detected
110
 *  MPN_INF_TRUNC   - caution (truncated filename)
111
 *  MPN_INF_SKIP    - info "skip entry" (dir doesn't exist)
112
 *  MPN_ERR_SKIP    - error -> skip entry
113
 *  MPN_ERR_TOOLONG - error -> path is too long
114
 *  MPN_NOMEM       - error (memory allocation failed) -> skip entry
115
 *  [also MPN_VOL_LABEL, MPN_CREATED_DIR]
116
 */
117
{
118
    char pathcomp[FILNAMSIZ];      /* path-component buffer */
119
    char *pp, *cp=(char *)NULL;    /* character pointers */
120
    char *lastsemi=(char *)NULL;   /* pointer to last semi-colon in pathcomp */
121
#ifdef ACORN_FTYPE_NFS
122
    char *lastcomma=(char *)NULL;  /* pointer to last comma in pathcomp */
123
    RO_extra_block *ef_spark;      /* pointer Acorn FTYPE ef block */
124
#endif
125
    int killed_ddot = FALSE;       /* is set when skipping "../" pathcomp */
126
    int error = MPN_OK;
127
    register unsigned workch;      /* hold the character being tested */
128
 
129
 
130
/*---------------------------------------------------------------------------
131
    Initialize various pointers and counters and stuff.
132
  ---------------------------------------------------------------------------*/
133
 
134
    if (G.pInfo->vollabel)
135
        return MPN_VOL_LABEL;   /* can't set disk volume labels in Unix */
136
 
137
    /* can create path as long as not just freshening, or if user told us */
138
    G.create_dirs = (!uO.fflag || renamed);
139
 
140
    G.created_dir = FALSE;      /* not yet */
141
 
142
    /* user gave full pathname:  don't prepend rootpath */
143
    G.renamed_fullpath = (renamed && (*G.filename == '/'));
144
 
145
    if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM)
146
        return MPN_NOMEM;       /* initialize path buffer, unless no memory */
147
 
148
    *pathcomp = '\0';           /* initialize translation buffer */
149
    pp = pathcomp;              /* point to translation buffer */
150
    if (uO.jflag)               /* junking directories */
151
        cp = (char *)strrchr(G.filename, '/');
152
    if (cp == (char *)NULL)     /* no '/' or not junking dirs */
153
        cp = G.filename;        /* point to internal zipfile-member pathname */
154
    else
155
        ++cp;                   /* point to start of last component of path */
156
 
6764 siemargl 157
fprintf(stderr, "mapname start[%s]\n", cp);
158
 
6725 siemargl 159
/*---------------------------------------------------------------------------
160
    Begin main loop through characters in filename.
161
  ---------------------------------------------------------------------------*/
162
 
163
    while ((workch = (uch)*cp++) != 0) {
164
 
165
        switch (workch) {
166
            case '/':             /* can assume -j flag not given */
167
                *pp = '\0';
168
                if (strcmp(pathcomp, ".") == 0) {
169
                    /* don't bother appending "./" to the path */
170
                    *pathcomp = '\0';
171
                } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
172
                    /* "../" dir traversal detected, skip over it */
173
                    *pathcomp = '\0';
174
                    killed_ddot = TRUE;     /* set "show message" flag */
175
                }
176
                /* when path component is not empty, append it now */
177
                if (*pathcomp != '\0' &&
178
                    ((error = checkdir(__G__ pathcomp, APPEND_DIR))
179
                     & MPN_MASK) > MPN_INF_TRUNC)
180
                    return error;
181
                pp = pathcomp;    /* reset conversion buffer for next piece */
182
                lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
183
                break;
184
 
6764 siemargl 185
#ifdef KOS32   /* Cygwin runs on Win32, apply FAT/NTFS filename rules */
6725 siemargl 186
            case ':':         /* drive spec not stored, so no colon allowed */
187
            case '\\':        /* '\\' may come as normal filename char (not */
188
            case '<':         /*  dir sep char!) from unix-like file system */
189
            case '>':         /* no redirection symbols allowed either */
190
            case '|':         /* no pipe signs allowed */
191
            case '"':         /* no double quotes allowed */
192
            case '?':         /* no wildcards allowed */
193
            case '*':
194
                *pp++ = '_';  /* these rules apply equally to FAT and NTFS */
195
                break;
196
#endif
197
 
198
            case ';':             /* VMS version (or DEC-20 attrib?) */
199
                lastsemi = pp;
200
                *pp++ = ';';      /* keep for now; remove VMS ";##" */
201
                break;            /*  later, if requested */
202
 
203
#ifdef ACORN_FTYPE_NFS
204
            case ',':             /* NFS filetype extension */
205
                lastcomma = pp;
206
                *pp++ = ',';      /* keep for now; may need to remove */
207
                break;            /*  later, if requested */
208
#endif
209
 
6764 siemargl 210
#ifdef KOS32
6725 siemargl 211
            case ' ':             /* change spaces to underscore under */
212
                *pp++ = '_';      /*  MTS; leave as spaces under Unix */
213
                break;
214
#endif
215
 
216
            default:
217
                /* disable control character filter when requested,
218
                 * else allow 8-bit characters (e.g. UTF-8) in filenames:
219
                 */
6727 siemargl 220
                if ((isprint(workch) || (128 <= workch && workch <= 254)))
221
                    *pp++ = (char)workch;
6725 siemargl 222
        } /* end switch */
223
 
224
    } /* end while loop */
225
 
226
    /* Show warning when stripping insecure "parent dir" path components */
227
    if (killed_ddot && QCOND2) {
228
        Info(slide, 0, ((char *)slide,
229
          "warning:  skipped \"../\" path component(s) in %s\n",
230
          FnFilter1(G.filename)));
231
        if (!(error & ~MPN_MASK))
232
            error = (error & MPN_MASK) | PK_WARN;
233
    }
234
 
235
/*---------------------------------------------------------------------------
236
    Report if directory was created (and no file to create:  filename ended
237
    in '/'), check name to be sure it exists, and combine path and name be-
238
    fore exiting.
239
  ---------------------------------------------------------------------------*/
240
 
241
    if (G.filename[strlen(G.filename) - 1] == '/') {
242
        checkdir(__G__ G.filename, GETPATH);
243
        if (G.created_dir) {
244
            if (QCOND2) {
245
                Info(slide, 0, ((char *)slide, "   creating: %s\n",
246
                  FnFilter1(G.filename)));
247
            }
248
#ifndef NO_CHMOD
249
            /* Filter out security-relevant attributes bits. */
250
            G.pInfo->file_attr = filtattr(__G__ G.pInfo->file_attr);
251
            /* When extracting non-UNIX directories or when extracting
252
             * without UID/GID restoration or SGID preservation, any
253
             * SGID flag inherited from the parent directory should be
254
             * maintained to allow files extracted into this new folder
255
             * to inherit the GID setting from the parent directory.
256
             */
257
            if (G.pInfo->hostnum != UNIX_ || !(uO.X_flag || uO.K_flag)) {
258
                /* preserve SGID bit when inherited from parent dir */
259
                if (!SSTAT(G.filename, &G.statbuf)) {
260
                    G.pInfo->file_attr |= G.statbuf.st_mode & S_ISGID;
261
                } else {
262
                    perror("Could not read directory attributes");
263
                }
264
            }
265
 
266
            /* set approx. dir perms (make sure can still read/write in dir) */
267
            if (chmod(G.filename, G.pInfo->file_attr | 0700))
268
                perror("chmod (directory attributes) error");
269
#endif
270
            /* set dir time (note trailing '/') */
271
            return (error & ~MPN_MASK) | MPN_CREATED_DIR;
272
        }
273
        /* dir existed already; don't look for data to extract */
274
        return (error & ~MPN_MASK) | MPN_INF_SKIP;
275
    }
276
 
277
    *pp = '\0';                   /* done with pathcomp:  terminate it */
278
 
279
    /* if not saving them, remove VMS version numbers (appended ";###") */
280
    if (!uO.V_flag && lastsemi) {
281
        pp = lastsemi + 1;
282
        while (isdigit((uch)(*pp)))
283
            ++pp;
284
        if (*pp == '\0')          /* only digits between ';' and end:  nuke */
285
            *lastsemi = '\0';
286
    }
287
 
288
    /* On UNIX (and compatible systems), "." and ".." are reserved for
289
     * directory navigation and cannot be used as regular file names.
290
     * These reserved one-dot and two-dot names are mapped to "_" and "__".
291
     */
292
    if (strcmp(pathcomp, ".") == 0)
293
        *pathcomp = '_';
294
    else if (strcmp(pathcomp, "..") == 0)
295
        strcpy(pathcomp, "__");
296
 
297
#ifdef ACORN_FTYPE_NFS
298
    /* translate Acorn filetype information if asked to do so */
299
    if (uO.acorn_nfs_ext &&
300
        (ef_spark = (RO_extra_block *)
301
                    getRISCOSexfield(G.extra_field, G.lrec.extra_field_length))
302
        != (RO_extra_block *)NULL)
303
    {
304
        /* file *must* have a RISC OS extra field */
305
        long ft = (long)makelong(ef_spark->loadaddr);
306
        /*32-bit*/
307
        if (lastcomma) {
308
            pp = lastcomma + 1;
309
            while (isxdigit((uch)(*pp))) ++pp;
310
            if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */
311
        }
312
        if ((ft & 1<<31)==0) ft=0x000FFD00;
313
        sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF);
314
    }
315
#endif /* ACORN_FTYPE_NFS */
316
 
317
    if (*pathcomp == '\0') {
318
        Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
319
          FnFilter1(G.filename)));
320
        return (error & ~MPN_MASK) | MPN_ERR_SKIP;
321
    }
322
 
323
    checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
324
    checkdir(__G__ G.filename, GETPATH);
325
 
6764 siemargl 326
fprintf(stderr, "mapname end[%s]\n", pathcomp);
327
 
328
 
6725 siemargl 329
    return error;
330
 
331
} /* end function mapname() */
332
 
333
 
334
 
335
 
336
#if 0  /*========== NOTES ==========*/
337
 
338
  extract-to dir:      a:path/
339
  buildpath:           path1/path2/ ...   (NULL-terminated)
340
  pathcomp:                filename
341
 
342
  mapname():
343
    loop over chars in zipfile member name
344
      checkdir(path component, COMPONENT | CREATEDIR) --> map as required?
345
        (d:/tmp/unzip/)                    (disk:[tmp.unzip.)
346
        (d:/tmp/unzip/jj/)                 (disk:[tmp.unzip.jj.)
347
        (d:/tmp/unzip/jj/temp/)            (disk:[tmp.unzip.jj.temp.)
348
    finally add filename itself and check for existence? (could use with rename)
349
        (d:/tmp/unzip/jj/temp/msg.outdir)  (disk:[tmp.unzip.jj.temp]msg.outdir)
350
    checkdir(name, GETPATH)     -->  copy path to name and free space
351
 
352
#endif /* 0 */
353
 
354
 
355
 
356
 
6727 siemargl 357
/********************************************************************************************************************/
358
/*** Function checkdir() */
359
/********************************************************************************************************************/
6725 siemargl 360
 
6727 siemargl 361
 
6725 siemargl 362
int checkdir(__G__ pathcomp, flag)
363
    __GDEF
364
    char *pathcomp;
365
    int flag;
366
/*
367
 * returns:
368
 *  MPN_OK          - no problem detected
369
 *  MPN_INF_TRUNC   - (on APPEND_NAME) truncated filename
370
 *  MPN_INF_SKIP    - path doesn't exist, not allowed to create
371
 *  MPN_ERR_SKIP    - path doesn't exist, tried to create and failed; or path
372
 *                    exists and is not a directory, but is supposed to be
373
 *  MPN_ERR_TOOLONG - path is too long
374
 *  MPN_NOMEM       - can't allocate memory for filename buffers
375
 */
376
{
377
 /* static int rootlen = 0; */  /* length of rootpath */
378
 /* static char *rootpath;  */  /* user's "extract-to" directory */
379
 /* static char *buildpath; */  /* full path (so far) to extracted file */
380
 /* static char *end;       */  /* pointer to end of buildpath ('\0') */
381
 
382
#   define FN_MASK   7
383
#   define FUNCTION  (flag & FN_MASK)
384
 
385
 
386
 
387
/*---------------------------------------------------------------------------
388
    APPEND_DIR:  append the path component to the path being built and check
389
    for its existence.  If doesn't exist and we are creating directories, do
390
    so for this one; else signal success or error as appropriate.
391
  ---------------------------------------------------------------------------*/
392
 
393
    if (FUNCTION == APPEND_DIR) {
394
        int too_long = FALSE;
395
#ifdef SHORT_NAMES
396
        char *old_end = end;
397
#endif
398
 
399
        Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
400
        while ((*G.end = *pathcomp++) != '\0')
401
            ++G.end;
402
#ifdef SHORT_NAMES   /* path components restricted to 14 chars, typically */
403
        if ((G.end-old_end) > FILENAME_MAX)  /* GRR:  proper constant? */
404
            *(G.end = old_end + FILENAME_MAX) = '\0';
405
#endif
406
 
407
        /* GRR:  could do better check, see if overrunning buffer as we go:
408
         * check end-buildpath after each append, set warning variable if
409
         * within 20 of FILNAMSIZ; then if var set, do careful check when
410
         * appending.  Clear variable when begin new path. */
411
 
412
        /* next check: need to append '/', at least one-char name, '\0' */
413
        if ((G.end-G.buildpath) > FILNAMSIZ-3)
414
            too_long = TRUE;                    /* check if extracting dir? */
415
        if (SSTAT(G.buildpath, &G.statbuf)) {   /* path doesn't exist */
416
            if (!G.create_dirs) { /* told not to create (freshening) */
417
                free(G.buildpath);
418
                return MPN_INF_SKIP;    /* path doesn't exist: nothing to do */
419
            }
420
            if (too_long) {
421
                Info(slide, 1, ((char *)slide,
422
                  "checkdir error:  path too long: %s\n",
423
                  FnFilter1(G.buildpath)));
424
                free(G.buildpath);
425
                /* no room for filenames:  fatal */
426
                return MPN_ERR_TOOLONG;
427
            }
428
            if (mkdir(G.buildpath, 0777) == -1) {   /* create the directory */
429
                Info(slide, 1, ((char *)slide,
430
                  "checkdir error:  cannot create %s\n\
431
                 %s\n\
432
                 unable to process %s.\n",
433
                  FnFilter2(G.buildpath),
434
                  strerror(errno),
435
                  FnFilter1(G.filename)));
436
                free(G.buildpath);
437
                /* path didn't exist, tried to create, failed */
438
                return MPN_ERR_SKIP;
439
            }
440
            G.created_dir = TRUE;
441
        } else if (!S_ISDIR(G.statbuf.st_mode)) {
442
            Info(slide, 1, ((char *)slide,
443
              "checkdir error:  %s exists but is not directory\n\
444
                 unable to process %s.\n",
445
              FnFilter2(G.buildpath), FnFilter1(G.filename)));
446
            free(G.buildpath);
447
            /* path existed but wasn't dir */
448
            return MPN_ERR_SKIP;
449
        }
450
        if (too_long) {
451
            Info(slide, 1, ((char *)slide,
452
              "checkdir error:  path too long: %s\n", FnFilter1(G.buildpath)));
453
            free(G.buildpath);
454
            /* no room for filenames:  fatal */
455
            return MPN_ERR_TOOLONG;
456
        }
457
        *G.end++ = '/';
458
        *G.end = '\0';
459
        Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
460
        return MPN_OK;
461
 
462
    } /* end if (FUNCTION == APPEND_DIR) */
463
 
464
/*---------------------------------------------------------------------------
465
    GETPATH:  copy full path to the string pointed at by pathcomp, and free
466
    G.buildpath.
467
  ---------------------------------------------------------------------------*/
468
 
469
    if (FUNCTION == GETPATH) {
6764 siemargl 470
        if(G.native_is_utf8)
471
        {
472
            pathcomp[0] = 3;  // kolibri utf8 flag
473
            strcpy(pathcomp + 1, G.buildpath);
474
        }
475
            else
6725 siemargl 476
        strcpy(pathcomp, G.buildpath);
477
        Trace((stderr, "getting and freeing path [%s]\n",
478
          FnFilter1(pathcomp)));
479
        free(G.buildpath);
480
        G.buildpath = G.end = (char *)NULL;
481
        return MPN_OK;
482
    }
483
 
484
/*---------------------------------------------------------------------------
485
    APPEND_NAME:  assume the path component is the filename; append it and
486
    return without checking for existence.
487
  ---------------------------------------------------------------------------*/
488
 
489
    if (FUNCTION == APPEND_NAME) {
490
#ifdef SHORT_NAMES
491
        char *old_end = end;
492
#endif
493
 
494
        Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
495
        while ((*G.end = *pathcomp++) != '\0') {
496
            ++G.end;
497
#ifdef SHORT_NAMES  /* truncate name at 14 characters, typically */
498
            if ((G.end-old_end) > FILENAME_MAX)    /* GRR:  proper constant? */
499
                *(G.end = old_end + FILENAME_MAX) = '\0';
500
#endif
501
            if ((G.end-G.buildpath) >= FILNAMSIZ) {
502
                *--G.end = '\0';
503
                Info(slide, 0x201, ((char *)slide,
504
                  "checkdir warning:  path too long; truncating\n\
505
                   %s\n                -> %s\n",
506
                  FnFilter1(G.filename), FnFilter2(G.buildpath)));
507
                return MPN_INF_TRUNC;   /* filename truncated */
508
            }
509
        }
510
        Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
511
        /* could check for existence here, prompt for new name... */
512
        return MPN_OK;
513
    }
514
 
515
/*---------------------------------------------------------------------------
516
    INIT:  allocate and initialize buffer space for the file currently being
517
    extracted.  If file was renamed with an absolute path, don't prepend the
518
    extract-to path.
519
  ---------------------------------------------------------------------------*/
520
 
521
/* GRR:  for VMS and TOPS-20, add up to 13 to strlen */
522
 
523
    if (FUNCTION == INIT) {
524
        Trace((stderr, "initializing buildpath to "));
525
#ifdef ACORN_FTYPE_NFS
526
        if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+
527
                                          (uO.acorn_nfs_ext ? 5 : 1)))
528
#else
529
        if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1))
530
#endif
531
            == (char *)NULL)
532
            return MPN_NOMEM;
533
        if ((G.rootlen > 0) && !G.renamed_fullpath) {
534
            strcpy(G.buildpath, G.rootpath);
535
            G.end = G.buildpath + G.rootlen;
536
        } else {
537
            *G.buildpath = '\0';
538
            G.end = G.buildpath;
539
        }
540
        Trace((stderr, "[%s]\n", FnFilter1(G.buildpath)));
541
        return MPN_OK;
542
    }
543
 
544
/*---------------------------------------------------------------------------
545
    ROOT:  if appropriate, store the path in rootpath and create it if
546
    necessary; else assume it's a zipfile member and return.  This path
547
    segment gets used in extracting all members from every zipfile specified
548
    on the command line.
549
  ---------------------------------------------------------------------------*/
550
 
551
#if (!defined(SFX) || defined(SFX_EXDIR))
552
    if (FUNCTION == ROOT) {
553
        Trace((stderr, "initializing root path to [%s]\n",
554
          FnFilter1(pathcomp)));
555
        if (pathcomp == (char *)NULL) {
556
            G.rootlen = 0;
557
            return MPN_OK;
558
        }
559
        if (G.rootlen > 0)      /* rootpath was already set, nothing to do */
560
            return MPN_OK;
561
        if ((G.rootlen = strlen(pathcomp)) > 0) {
562
            char *tmproot;
563
 
564
            if ((tmproot = (char *)malloc(G.rootlen+2)) == (char *)NULL) {
565
                G.rootlen = 0;
566
                return MPN_NOMEM;
567
            }
568
            strcpy(tmproot, pathcomp);
569
            if (tmproot[G.rootlen-1] == '/') {
570
                tmproot[--G.rootlen] = '\0';
571
            }
572
            if (G.rootlen > 0 && (SSTAT(tmproot, &G.statbuf) ||
573
                                  !S_ISDIR(G.statbuf.st_mode)))
574
            {   /* path does not exist */
575
                if (!G.create_dirs /* || iswild(tmproot) */ ) {
576
                    free(tmproot);
577
                    G.rootlen = 0;
578
                    /* skip (or treat as stored file) */
579
                    return MPN_INF_SKIP;
580
                }
581
                /* create the directory (could add loop here scanning tmproot
582
                 * to create more than one level, but why really necessary?) */
583
                if (mkdir(tmproot, 0777) == -1) {
584
                    Info(slide, 1, ((char *)slide,
585
                      "checkdir:  cannot create extraction directory: %s\n\
586
           %s\n",
587
                      FnFilter1(tmproot), strerror(errno)));
588
                    free(tmproot);
589
                    G.rootlen = 0;
590
                    /* path didn't exist, tried to create, and failed: */
591
                    /* file exists, or 2+ subdir levels required */
592
                    return MPN_ERR_SKIP;
593
                }
594
            }
595
            tmproot[G.rootlen++] = '/';
596
            tmproot[G.rootlen] = '\0';
597
            if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
598
                free(tmproot);
599
                G.rootlen = 0;
600
                return MPN_NOMEM;
601
            }
602
            Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
603
        }
604
        return MPN_OK;
605
    }
606
#endif /* !SFX || SFX_EXDIR */
607
 
608
/*---------------------------------------------------------------------------
609
    END:  free rootpath, immediately prior to program exit.
610
  ---------------------------------------------------------------------------*/
611
 
612
    if (FUNCTION == END) {
613
        Trace((stderr, "freeing rootpath\n"));
614
        if (G.rootlen > 0) {
615
            free(G.rootpath);
616
            G.rootlen = 0;
617
        }
618
        return MPN_OK;
619
    }
620
 
621
    return MPN_INVALID; /* should never reach */
622
 
623
} /* end function checkdir() */
624
 
625
static int get_extattribs OF((__GPRO__ iztimes *pzt, ulg z_uidgid[2]));
626
 
627
static int get_extattribs(__G__ pzt, z_uidgid)
628
    __GDEF
629
    iztimes *pzt;
630
    ulg z_uidgid[2];
631
{
632
/*---------------------------------------------------------------------------
633
    Convert from MSDOS-format local time and date to Unix-format 32-bit GMT
634
    time:  adjust base year from 1980 to 1970, do usual conversions from
635
    yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day-
636
    light savings time differences.  If we have a Unix extra field, however,
637
    we're laughing:  both mtime and atime are ours.  On the other hand, we
638
    then have to check for restoration of UID/GID.
639
  ---------------------------------------------------------------------------*/
640
    int have_uidgid_flg;
641
    unsigned eb_izux_flg;
642
 
643
    eb_izux_flg = 0; // kos32
644
/*
645
    (G.extra_field ? ef_scan_for_izux(G.extra_field,
646
                   G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
647
#ifdef IZ_CHECK_TZ
648
                   (G.tz_is_valid ? pzt : NULL),
649
#else
650
                   pzt,
651
#endif
652
                   z_uidgid) : 0);
653
*/
654
    if (eb_izux_flg & EB_UT_FL_MTIME) {
655
        TTrace((stderr, "\nget_extattribs:  Unix e.f. modif. time = %ld\n",
656
          pzt->mtime));
657
    } else {
658
        pzt->mtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
659
    }
660
    if (eb_izux_flg & EB_UT_FL_ATIME) {
661
        TTrace((stderr, "get_extattribs:  Unix e.f. access time = %ld\n",
662
          pzt->atime));
663
    } else {
664
        pzt->atime = pzt->mtime;
665
        TTrace((stderr, "\nget_extattribs:  modification/access times = %ld\n",
666
          pzt->mtime));
667
    }
668
 
669
    /* if -X option was specified and we have UID/GID info, restore it */
670
    have_uidgid_flg =
671
#ifdef RESTORE_UIDGID
672
            (uO.X_flag && (eb_izux_flg & EB_UX2_VALID));
673
#else
674
            0;
675
#endif
676
    return have_uidgid_flg;
677
}
678
 
679
/****************************/
680
/* Function close_outfile() */
681
/****************************/
682
 
683
void close_outfile(__G)    /* GRR: change to return PK-style warning level */
684
    __GDEF
685
{
686
    union {
687
        iztimes t3;             /* mtime, atime, ctime */
688
        ztimbuf t2;             /* modtime, actime */
689
    } zt;
690
    ulg z_uidgid[2];
691
    int have_uidgid_flg;
692
 
693
    have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid);
694
 
695
/*---------------------------------------------------------------------------
696
    If symbolic links are supported, allocate storage for a symlink control
697
    structure, put the uncompressed "data" and other required info in it, and
698
    add the structure to the "deferred symlinks" chain.  Since we know it's a
699
    symbolic link to start with, we shouldn't have to worry about overflowing
700
    unsigned ints with unsigned longs.
701
  ---------------------------------------------------------------------------*/
702
 
703
#ifdef SYMLINKS
704
    if (G.symlnk) {
705
        extent ucsize = (extent)G.lrec.ucsize;
706
# ifdef SET_SYMLINK_ATTRIBS
707
        extent attribsize = sizeof(unsigned) +
708
                            (have_uidgid_flg ? sizeof(z_uidgid) : 0);
709
# else
710
        extent attribsize = 0;
711
# endif
712
        /* size of the symlink entry is the sum of
713
         *  (struct size (includes 1st '\0') + 1 additional trailing '\0'),
714
         *  system specific attribute data size (might be 0),
715
         *  and the lengths of name and link target.
716
         */
717
        extent slnk_entrysize = (sizeof(slinkentry) + 1) + attribsize +
718
                                ucsize + strlen(G.filename);
719
        slinkentry *slnk_entry;
720
 
721
        if (slnk_entrysize < ucsize) {
722
            Info(slide, 0x201, ((char *)slide,
723
              "warning:  symbolic link (%s) failed: mem alloc overflow\n",
724
              FnFilter1(G.filename)));
725
            fclose(G.outfile);
726
            return;
727
        }
728
 
729
        if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) {
730
            Info(slide, 0x201, ((char *)slide,
731
              "warning:  symbolic link (%s) failed: no mem\n",
732
              FnFilter1(G.filename)));
733
            fclose(G.outfile);
734
            return;
735
        }
736
        slnk_entry->next = NULL;
737
        slnk_entry->targetlen = ucsize;
738
        slnk_entry->attriblen = attribsize;
739
# ifdef SET_SYMLINK_ATTRIBS
740
        memcpy(slnk_entry->buf, &(G.pInfo->file_attr),
741
               sizeof(unsigned));
742
        if (have_uidgid_flg)
743
            memcpy(slnk_entry->buf + 4, z_uidgid, sizeof(z_uidgid));
744
# endif
745
        slnk_entry->target = slnk_entry->buf + slnk_entry->attriblen;
746
        slnk_entry->fname = slnk_entry->target + ucsize + 1;
747
        strcpy(slnk_entry->fname, G.filename);
748
 
749
        /* move back to the start of the file to re-read the "link data" */
750
        rewind(G.outfile);
751
 
752
        if (fread(slnk_entry->target, 1, ucsize, G.outfile) != ucsize)
753
        {
754
            Info(slide, 0x201, ((char *)slide,
755
              "warning:  symbolic link (%s) failed\n",
756
              FnFilter1(G.filename)));
757
            free(slnk_entry);
758
            fclose(G.outfile);
759
            return;
760
        }
761
        fclose(G.outfile);                  /* close "link" file for good... */
762
        slnk_entry->target[ucsize] = '\0';
763
        if (QCOND2)
764
            Info(slide, 0, ((char *)slide, "-> %s ",
765
              FnFilter1(slnk_entry->target)));
766
        /* add this symlink record to the list of deferred symlinks */
767
        if (G.slink_last != NULL)
768
            G.slink_last->next = slnk_entry;
769
        else
770
            G.slink_head = slnk_entry;
771
        G.slink_last = slnk_entry;
772
        return;
773
    }
774
#endif /* SYMLINKS */
775
 
776
#ifdef QLZIP
777
    if (G.extra_field) {
778
        static void qlfix OF((__GPRO__ uch *ef_ptr, unsigned ef_len));
779
 
780
        qlfix(__G__ G.extra_field, G.lrec.extra_field_length);
781
    }
782
#endif
783
 
784
#if (defined(NO_FCHOWN))
785
    fclose(G.outfile);
6745 siemargl 786
    Trace((stdout, "File (%s) closed\n", FnFilter1(G.filename)));
6725 siemargl 787
#endif
788
 
789
// kos. add set file datetime ?
790
#ifndef KOS32
791
    /* if -X option was specified and we have UID/GID info, restore it */
792
    if (have_uidgid_flg
793
        /* check that both uid and gid values fit into their data sizes */
794
        && ((ulg)(uid_t)(z_uidgid[0]) == z_uidgid[0])
795
        && ((ulg)(gid_t)(z_uidgid[1]) == z_uidgid[1])) {
796
        TTrace((stderr, "close_outfile:  restoring Unix UID/GID info\n"));
797
#if (defined(NO_FCHOWN))
798
        if (chown(G.filename, (uid_t)z_uidgid[0], (gid_t)z_uidgid[1]))
799
#else
800
        if (fchown(fileno(G.outfile), (uid_t)z_uidgid[0], (gid_t)z_uidgid[1]))
801
#endif
802
        {
803
            if (uO.qflag)
804
                Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid,
805
                  z_uidgid[0], z_uidgid[1], FnFilter1(G.filename),
806
                  strerror(errno)));
807
            else
808
                Info(slide, 0x201, ((char *)slide, CannotSetUidGid,
809
                  z_uidgid[0], z_uidgid[1], strerror(errno)));
810
        }
811
    }
812
 
813
#if (!defined(NO_FCHOWN) && defined(NO_FCHMOD))
814
    fclose(G.outfile);
815
#endif
816
 
817
#if (!defined(NO_FCHOWN) && !defined(NO_FCHMOD))
818
/*---------------------------------------------------------------------------
819
    Change the file permissions from default ones to those stored in the
820
    zipfile.
821
  ---------------------------------------------------------------------------*/
822
 
823
    if (fchmod(fileno(G.outfile), filtattr(__G__ G.pInfo->file_attr)))
824
        perror("fchmod (file attributes) error");
825
 
826
    fclose(G.outfile);
827
#endif /* !NO_FCHOWN && !NO_FCHMOD */
828
 
829
    /* skip restoring time stamps on user's request */
830
    if (uO.D_flag <= 1) {
831
        /* set the file's access and modification times */
832
        if (utime(G.filename, &(zt.t2))) {
833
            if (uO.qflag)
834
                Info(slide, 0x201, ((char *)slide, CannotSetItemTimestamps,
835
                  FnFilter1(G.filename), strerror(errno)));
836
            else
837
                Info(slide, 0x201, ((char *)slide, CannotSetTimestamps,
838
                  strerror(errno)));
839
        }
840
    }
841
 
842
#if (defined(NO_FCHOWN) || defined(NO_FCHMOD))
843
/*---------------------------------------------------------------------------
844
    Change the file permissions from default ones to those stored in the
845
    zipfile.
846
  ---------------------------------------------------------------------------*/
847
 
848
#ifndef NO_CHMOD
849
    if (chmod(G.filename, filtattr(__G__ G.pInfo->file_attr)))
850
        perror("chmod (file attributes) error");
851
#endif
852
#endif /* NO_FCHOWN || NO_FCHMOD */
853
 
854
#endif // 0
855
 
856
} /* end function close_outfile() */
857
 
858
 
859
/**********************/
860
/* Function do_wild() */   /* for porting: dir separator; match(ignore_case) */
861
/**********************/
862
 
863
char *do_wild(__G__ wildspec)
864
    __GDEF
865
    ZCONST char *wildspec;  /* only used first time on a given dir */
866
{
867
/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in unxcfg.h:
868
    static DIR *wild_dir = (DIR *)NULL;
869
    static ZCONST char *wildname;
870
    static char *dirname, matchname[FILNAMSIZ];
871
    static int notfirstcall=FALSE, have_dirname, dirnamelen;
872
*/
873
    struct dirent *file;
874
 
875
    /* Even when we're just returning wildspec, we *always* do so in
876
     * matchname[]--calling routine is allowed to append four characters
877
     * to the returned string, and wildspec may be a pointer to argv[].
878
     */
879
    if (!G.notfirstcall) {  /* first call:  must initialize everything */
880
        G.notfirstcall = TRUE;
881
 
882
        if (!iswild(wildspec)) {
883
            strncpy(G.matchname, wildspec, FILNAMSIZ);
884
            G.matchname[FILNAMSIZ-1] = '\0';
885
            G.have_dirname = FALSE;
886
            G.wild_dir = NULL;
887
            return G.matchname;
888
        }
889
 
890
        /* break the wildspec into a directory part and a wildcard filename */
891
        if ((G.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL) {
892
            G.dirname = ".";
893
            G.dirnamelen = 1;
894
            G.have_dirname = FALSE;
895
            G.wildname = wildspec;
896
        } else {
897
            ++G.wildname;     /* point at character after '/' */
898
            G.dirnamelen = G.wildname - wildspec;
899
            if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == (char *)NULL) {
900
                Info(slide, 0x201, ((char *)slide,
901
                  "warning:  cannot allocate wildcard buffers\n"));
902
                strncpy(G.matchname, wildspec, FILNAMSIZ);
903
                G.matchname[FILNAMSIZ-1] = '\0';
904
                return G.matchname; /* but maybe filespec was not a wildcard */
905
            }
906
            strncpy(G.dirname, wildspec, G.dirnamelen);
907
            G.dirname[G.dirnamelen] = '\0';   /* terminate for strcpy below */
908
            G.have_dirname = TRUE;
909
        }
910
 
911
        if ((G.wild_dir = (zvoid *)opendir(G.dirname)) != (zvoid *)NULL) {
912
            while ((file = readdir((DIR *)G.wild_dir)) !=
913
                   (struct dirent *)NULL) {
914
                Trace((stderr, "do_wild:  readdir returns %s\n",
915
                  FnFilter1(file->d_name)));
916
                if (file->d_name[0] == '.' && G.wildname[0] != '.')
917
                    continue; /* Unix:  '*' and '?' do not match leading dot */
918
                if (match(file->d_name, G.wildname, 0 WISEP) &&/*0=case sens.*/
919
                    /* skip "." and ".." directory entries */
920
                    strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {
921
                    Trace((stderr, "do_wild:  match() succeeds\n"));
922
                    if (G.have_dirname) {
923
                        strcpy(G.matchname, G.dirname);
924
                        strcpy(G.matchname+G.dirnamelen, file->d_name);
925
                    } else
926
                        strcpy(G.matchname, file->d_name);
927
                    return G.matchname;
928
                }
929
            }
930
            /* if we get to here directory is exhausted, so close it */
931
            closedir((DIR *)G.wild_dir);
932
            G.wild_dir = (zvoid *)NULL;
933
        }
934
        Trace((stderr, "do_wild:  opendir(%s) returns NULL\n",
935
          FnFilter1(G.dirname)));
936
 
937
        /* return the raw wildspec in case that works (e.g., directory not
938
         * searchable, but filespec was not wild and file is readable) */
939
        strncpy(G.matchname, wildspec, FILNAMSIZ);
940
        G.matchname[FILNAMSIZ-1] = '\0';
941
        return G.matchname;
942
    }
943
 
944
    /* last time through, might have failed opendir but returned raw wildspec */
945
    if ((DIR *)G.wild_dir == (DIR *)NULL) {
946
        G.notfirstcall = FALSE; /* nothing left--reset for new wildspec */
947
        if (G.have_dirname)
948
            free(G.dirname);
949
        return (char *)NULL;
950
    }
951
 
952
    /* If we've gotten this far, we've read and matched at least one entry
953
     * successfully (in a previous call), so dirname has been copied into
954
     * matchname already.
955
     */
956
    while ((file = readdir((DIR *)G.wild_dir)) != (struct dirent *)NULL) {
957
        Trace((stderr, "do_wild:  readdir returns %s\n",
958
          FnFilter1(file->d_name)));
959
        if (file->d_name[0] == '.' && G.wildname[0] != '.')
960
            continue;   /* Unix:  '*' and '?' do not match leading dot */
961
        if (match(file->d_name, G.wildname, 0 WISEP)) { /* 0 == case sens. */
962
            Trace((stderr, "do_wild:  match() succeeds\n"));
963
            if (G.have_dirname) {
964
                /* strcpy(G.matchname, G.dirname); */
965
                strcpy(G.matchname+G.dirnamelen, file->d_name);
966
            } else
967
                strcpy(G.matchname, file->d_name);
968
            return G.matchname;
969
        }
970
    }
971
 
972
    closedir((DIR *)G.wild_dir);  /* at least one entry read; nothing left */
973
    G.wild_dir = (zvoid *)NULL;
974
    G.notfirstcall = FALSE;       /* reset for new wildspec */
975
    if (G.have_dirname)
976
        free(G.dirname);
977
    return (char *)NULL;
978
 
979
} /* end function do_wild() */
980