Subversion Repositories Kolibri OS

Rev

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