Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6725 siemargl 1
/*
2
  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
3
 
4
  See the accompanying file LICENSE, version 2007-Mar-04 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
  win32.c
12
 
13
  32-bit Windows-specific (NT/9x) routines for use with Info-ZIP's UnZip 5.3
14
  and later.
15
 
16
  Contains:  GetLoadPath()
17
             Opendir()
18
             Readdir()
19
             Closedir()
20
             SetSD()              set security descriptor on file
21
             FindSDExtraField()   extract SD e.f. block from extra field
22
             IsWinNT()            indicate type of WIN32 platform
23
             test_NTSD()          test integrity of NT security data
24
             utime2NtfsFileTime()
25
             utime2VFatFileTime()
26
             FStampIsLocTime()
27
             NtfsFileTime2utime()
28
             VFatFileTime2utime()
29
             getNTfiletime()
30
             SetFileSize()
31
             close_outfile()
32
             defer_dir_attribs()
33
             set_direc_attribs()
34
             stamp_file()
35
             isfloppy()
36
             NTQueryVolInfo()
37
             IsVolumeOldFAT()
38
             do_wild()
39
             mapattr()
40
             mapname()
41
             maskDOSdevice()
42
             map2fat()
43
             checkdir()
44
             dateformat()
45
             dateseparator()
46
             version()
47
             screensize()
48
             zstat_win32()
49
             conv_to_rule()
50
             GetPlatformLocalTimezone()
51
             getch_win32()
52
 
53
  ---------------------------------------------------------------------------*/
54
 
55
 
56
#define UNZIP_INTERNAL
57
#include "../unzip.h"
58
#include     /* must be AFTER unzip.h to avoid struct G problems */
59
#ifdef __RSXNT__
60
#  include "../win32/rsxntwin.h"
61
#endif
62
#include "../win32/nt.h"
63
 
64
#ifndef FUNZIP          /* most of this file is not used with fUnZip */
65
 
66
/* some non-MS runtime headers (e.g. lcc) may miss this definition */
67
#ifndef FILE_WRITE_ATTRIBUTES
68
#  define FILE_WRITE_ATTRIBUTES 0x0100
69
#endif
70
 
71
#if (defined(__EMX__) || defined(__CYGWIN__))
72
#  define MKDIR(path,mode)   mkdir(path,mode)
73
#else
74
#  define MKDIR(path,mode)   mkdir(path)
75
#endif
76
 
77
#ifdef HAVE_WORKING_DIRENT_H
78
#  undef HAVE_WORKING_DIRENT_H
79
#endif
80
/* The emxrtl dirent support of (__GO32__ || __EMX__) converts to lowercase! */
81
#if defined(__CYGWIN__)
82
#  define HAVE_WORKING_DIRENT_H
83
#endif
84
 
85
#ifndef SFX
86
#  ifdef HAVE_WORKING_DIRENT_H
87
#    include          /* use readdir() */
88
#    define zdirent  dirent
89
#    define zDIR     DIR
90
#    define Opendir  opendir
91
#    define Readdir  readdir
92
#    define Closedir closedir
93
#  else /* !HAVE_WORKING_DIRENT_H */
94
     typedef struct zdirent {
95
         char    reserved [21];
96
         char    ff_attrib;
97
         short   ff_ftime;
98
         short   ff_fdate;
99
         long    size;
100
         char    d_name[MAX_PATH];
101
         int     d_first;
102
         HANDLE  d_hFindFile;
103
     } zDIR;
104
 
105
     static zDIR           *Opendir  (const char *n);
106
     static struct zdirent *Readdir  (zDIR *d);
107
     static void            Closedir (zDIR *d);
108
#  endif /* ?HAVE_WORKING_DIRENT_H */
109
#endif /* !SFX */
110
 
111
#ifdef SET_DIR_ATTRIB
112
typedef struct NTdirattr {      /* struct for holding unix style directory */
113
    struct NTdirattr *next;     /*  info until can be sorted and set at end */
114
    char *fn;                   /* filename of directory */
115
    FILETIME Modft;    /* File time type defined in NT, `last modified' time */
116
    FILETIME Accft;    /* NT file time type, `last access' time */
117
    FILETIME Creft;    /* NT file time type, `file creation' time */
118
    int gotTime;
119
    unsigned perms;             /* same as min_info.file_attr */
120
#ifdef NTSD_EAS
121
    unsigned SDlen;             /* length of SD data in buf */
122
#endif
123
    char buf[1];                /* buffer stub for directory SD and name */
124
} NTdirattr;
125
#define NtAtt(d)  ((NTdirattr *)d)    /* typecast shortcut */
126
#endif /* SET_DIR_ATTRIB */
127
 
128
 
129
/* Function prototypes */
130
#ifdef NTSD_EAS
131
   static int  SetSD(__GPRO__ char *path, unsigned fperms,
132
                     uch *eb_ptr, unsigned eb_len);
133
   static int  FindSDExtraField(__GPRO__
134
                                uch *ef_ptr, unsigned ef_len,
135
                                uch **p_ebSD_ptr, unsigned *p_ebSD_len);
136
#endif
137
 
138
#ifndef NO_W32TIMES_IZFIX
139
   static void utime2NtfsFileTime(time_t ut, FILETIME *pft);
140
#endif
141
static void utime2VFatFileTime(time_t ut, FILETIME *pft, int clipDosMin);
142
#if (defined(W32_STAT_BANDAID) && !defined(NO_W32TIMES_IZFIX))
143
   static int NtfsFileTime2utime(const FILETIME *pft, time_t *ut);
144
#endif
145
#ifdef W32_STAT_BANDAID
146
   static int VFatFileTime2utime(const FILETIME *pft, time_t *ut);
147
#endif
148
static int FStampIsLocTime(__GPRO__ const char *path);
149
 
150
 
151
static int  getNTfiletime   (__GPRO__ FILETIME *pModFT, FILETIME *pAccFT,
152
                             FILETIME *pCreFT);
153
static int  isfloppy        (int nDrive);
154
static int  NTQueryVolInfo  (__GPRO__ const char *name);
155
static int  IsVolumeOldFAT  (__GPRO__ const char *name);
156
static void maskDOSdevice   (__GPRO__ char *pathcomp);
157
static void map2fat         (char *pathcomp, char **pEndFAT);
158
 
159
 
160
#if (defined(__MINGW32__) && !defined(USE_MINGW_GLOBBING))
161
   int _CRT_glob = 0;   /* suppress command line globbing by C RTL */
162
#endif
163
 
164
#ifdef ACORN_FTYPE_NFS
165
/* Acorn bits for NFS filetyping */
166
typedef struct {
167
  uch ID[2];
168
  uch size[2];
169
  uch ID_2[4];
170
  uch loadaddr[4];
171
  uch execaddr[4];
172
  uch attr[4];
173
} RO_extra_block;
174
 
175
#endif /* ACORN_FTYPE_NFS */
176
 
177
/* static int created_dir;      */     /* used by mapname(), checkdir() */
178
/* static int renamed_fullpath; */     /* ditto */
179
/* static int fnlen;            */     /* ditto */
180
/* static unsigned nLabelDrive; */     /* ditto */
181
 
182
extern char Far TruncNTSD[];    /* in extract.c */
183
 
184
 
185
 
186
#ifdef SFX
187
 
188
/**************************/
189
/* Function GetLoadPath() */
190
/**************************/
191
 
192
char *GetLoadPath(__GPRO)
193
{
194
#ifdef MSC
195
    extern char *_pgmptr;
196
    return _pgmptr;
197
 
198
#else    /* use generic API call */
199
 
200
    GetModuleFileName(NULL, G.filename, FILNAMSIZ);
201
    _ISO_INTERN(G.filename);    /* translate to codepage of C rtl's stdio */
202
    return G.filename;
203
#endif
204
 
205
} /* end function GetLoadPath() */
206
 
207
 
208
 
209
 
210
 
211
#else /* !SFX */
212
 
213
#ifndef HAVE_WORKING_DIRENT_H
214
 
215
/**********************/        /* Borrowed from ZIP 2.0 sources            */
216
/* Function Opendir() */        /* Difference: no special handling for      */
217
/**********************/        /*             hidden or system files.      */
218
 
219
static zDIR *Opendir(n)
220
    const char *n;          /* directory to open */
221
{
222
    zDIR *d;                /* malloc'd return value */
223
    char *p;                /* malloc'd temporary string */
224
    WIN32_FIND_DATAA fd;
225
    extent len = strlen(n);
226
 
227
    /* Start searching for files in directory n */
228
 
229
    if ((d = (zDIR *)malloc(sizeof(zDIR))) == NULL ||
230
        (p = malloc(strlen(n) + 5)) == NULL)
231
    {
232
        if (d != (zDIR *)NULL)
233
            free((void *)d);
234
        return (zDIR *)NULL;
235
    }
236
    INTERN_TO_ISO(n, p);
237
    if (len > 0) {
238
        if (p[len-1] == ':')
239
            p[len++] = '.';     /* x: => x:. */
240
        else if (p[len-1] == '/' || p[len-1] == '\\')
241
            --len;              /* foo/ => foo */
242
    }
243
    strcpy(p+len, "/*");
244
 
245
    if (INVALID_HANDLE_VALUE == (d->d_hFindFile = FindFirstFileA(p, &fd))) {
246
        free((zvoid *)d);
247
        free((zvoid *)p);
248
        return NULL;
249
    }
250
    strcpy(d->d_name, fd.cFileName);
251
 
252
    free((zvoid *)p);
253
    d->d_first = 1;
254
    return d;
255
 
256
} /* end of function Opendir() */
257
 
258
 
259
 
260
 
261
/**********************/        /* Borrowed from ZIP 2.0 sources            */
262
/* Function Readdir() */        /* Difference: no special handling for      */
263
/**********************/        /*             hidden or system files.      */
264
 
265
static struct zdirent *Readdir(d)
266
    zDIR *d;                    /* directory stream from which to read */
267
{
268
    /* Return pointer to first or next directory entry, or NULL if end. */
269
 
270
    if ( d->d_first )
271
        d->d_first = 0;
272
    else
273
    {
274
        WIN32_FIND_DATAA fd;
275
 
276
        if ( !FindNextFileA(d->d_hFindFile, &fd) )
277
            return NULL;
278
 
279
        ISO_TO_INTERN(fd.cFileName, d->d_name);
280
    }
281
    return (struct zdirent *)d;
282
 
283
} /* end of function Readdir() */
284
 
285
 
286
 
287
 
288
/***********************/
289
/* Function Closedir() */       /* Borrowed from ZIP 2.0 sources */
290
/***********************/
291
 
292
static void Closedir(d)
293
    zDIR *d;                    /* directory stream to close */
294
{
295
    FindClose(d->d_hFindFile);
296
    free(d);
297
}
298
 
299
#endif /* !HAVE_WORKING_DIRENT_H */
300
#endif /* ?SFX */
301
 
302
 
303
 
304
 
305
#ifdef NTSD_EAS
306
 
307
/**********************/
308
/*  Function SetSD()  */   /* return almost-PK errors */
309
/**********************/
310
 
311
static int SetSD(__G__ path, fperms, eb_ptr, eb_len)
312
    __GDEF
313
    char *path;
314
    unsigned fperms;
315
    uch *eb_ptr;
316
    unsigned eb_len;
317
{
318
    ulg ntsd_ucSize;
319
    VOLUMECAPS VolumeCaps;
320
    uch *security_data;
321
    int error;
322
 
323
    ntsd_ucSize = makelong(eb_ptr + (EB_HEADSIZE+EB_UCSIZE_P));
324
    if (ntsd_ucSize > 0L && eb_len <= (EB_NTSD_L_LEN + EB_CMPRHEADLEN))
325
        return IZ_EF_TRUNC;               /* no compressed data! */
326
 
327
    /* provide useful input */
328
    VolumeCaps.dwFileAttributes = fperms;
329
    VolumeCaps.bUsePrivileges = (uO.X_flag > 1);
330
 
331
    /* check target volume capabilities - just fall through
332
     * and try if fail */
333
    if (GetVolumeCaps(G.rootpath, path, &VolumeCaps) &&
334
        !(VolumeCaps.dwFileSystemFlags & FS_PERSISTENT_ACLS))
335
        return PK_OK;
336
 
337
    /* allocate storage for uncompressed data */
338
    security_data = (uch *)malloc((extent)ntsd_ucSize);
339
    if (security_data == (uch *)NULL)
340
        return PK_MEM4;
341
 
342
    error = memextract(__G__ security_data, ntsd_ucSize,
343
      (eb_ptr + (EB_HEADSIZE+EB_NTSD_L_LEN)), (ulg)(eb_len - EB_NTSD_L_LEN));
344
 
345
    if (error == PK_OK) {
346
        if (SecuritySet(path, &VolumeCaps, security_data)) {
347
            error = PK_COOL;
348
            if (!uO.tflag && QCOND2)
349
                Info(slide, 0, ((char *)slide, " (%ld bytes security)",
350
                  ntsd_ucSize));
351
        }
352
    }
353
 
354
    free(security_data);
355
    return error;
356
}
357
 
358
 
359
 
360
 
361
/********************************/   /* scan extra fields for something */
362
/*  Function FindSDExtraField() */   /*  we happen to know */
363
/********************************/
364
/* Returns TRUE when a valid NTFS SD block is found.
365
 * Address and size of the NTSD e.f. block are passed up to the caller.
366
 * In case of more than one valid NTSD block in the e.f., the last block
367
 * found is passed up.
368
 * Returns FALSE and leaves the content of the ebSD_ptr and ebSD_len
369
 * parameters untouched when no valid NTFS SD block is found. */
370
static int FindSDExtraField(__GPRO__
371
                            uch *ef_ptr, unsigned ef_len,
372
                            uch **p_ebSD_ptr, unsigned *p_ebSD_len)
373
{
374
    int rc = FALSE;
375
 
376
    if (!uO.X_flag)
377
        return FALSE;  /* user said don't process ACLs; for now, no other
378
                          extra block types are handled here */
379
 
380
    while (ef_len >= EB_HEADSIZE)
381
    {
382
        unsigned eb_id = makeword(EB_ID + ef_ptr);
383
        unsigned eb_len = makeword(EB_LEN + ef_ptr);
384
 
385
        if (eb_len > (ef_len - EB_HEADSIZE)) {
386
            /* discovered some extra field inconsistency! */
387
            Trace((stderr,
388
              "FindSDExtraField: block length %u > rest ef_size %u\n", eb_len,
389
              ef_len - EB_HEADSIZE));
390
            break;
391
        }
392
 
393
        switch (eb_id)
394
        {
395
            /* process security descriptor extra data if:
396
                 Caller is WinNT AND
397
                 Target local/remote drive supports acls AND
398
                 Target file is not a directory (else we defer processing
399
                   until later)
400
             */
401
            case EF_NTSD:
402
                if (!IsWinNT())
403
                    break; /* OS not capable of handling NTFS attributes */
404
 
405
                if (eb_len < EB_NTSD_L_LEN)
406
                    break; /* not a valid NTSD extra field */
407
 
408
                /* check if we know how to handle this version */
409
                if (*(ef_ptr + (EB_HEADSIZE+EB_NTSD_VERSION))
410
                    > (uch)EB_NTSD_MAX_VER)
411
                    break;
412
 
413
                *p_ebSD_ptr = ef_ptr;
414
                *p_ebSD_len = eb_len;
415
                rc = TRUE;
416
                break;
417
 
418
#ifdef DEBUG
419
            case EF_OS2:
420
            case EF_AV:
421
            case EF_PKVMS:
422
            case EF_PKW32:
423
            case EF_PKUNIX:
424
            case EF_IZVMS:
425
            case EF_IZUNIX:
426
            case EF_IZUNIX2:
427
            case EF_TIME:
428
            case EF_MAC3:
429
            case EF_JLMAC:
430
            case EF_ZIPIT:
431
            case EF_VMCMS:
432
            case EF_MVS:
433
            case EF_ACL:
434
            case EF_ATHEOS:
435
            case EF_BEOS:
436
            case EF_QDOS:
437
            case EF_AOSVS:
438
            case EF_SPARK:
439
            case EF_MD5:
440
            case EF_ASIUNIX:
441
                break;          /* shut up for other known e.f. blocks  */
442
#endif /* DEBUG */
443
 
444
            default:
445
                Trace((stderr,
446
                  "FindSDExtraField: unknown extra field block, ID=%u\n",
447
                  eb_id));
448
                break;
449
        }
450
 
451
        ef_ptr += (eb_len + EB_HEADSIZE);
452
        ef_len -= (eb_len + EB_HEADSIZE);
453
    }
454
 
455
    return rc;
456
}
457
 
458
 
459
 
460
 
461
#ifndef SFX
462
 
463
/**************************/
464
/*  Function test_NTSD()  */   /*  returns PK_WARN when NTSD data is invalid */
465
/**************************/
466
 
467
#ifdef __BORLANDC__
468
/* Turn off warning about not using all parameters for this function only */
469
#pragma argsused
470
#endif
471
int test_NTSD(__G__ eb, eb_size, eb_ucptr, eb_ucsize)
472
    __GDEF
473
    uch *eb;
474
    unsigned eb_size;
475
    uch *eb_ucptr;
476
    ulg eb_ucsize;
477
{
478
    return (ValidateSecurity(eb_ucptr) ? PK_OK : PK_WARN);
479
} /* end function test_NTSD() */
480
 
481
#endif /* !SFX */
482
#endif /* NTSD_EAS */
483
 
484
 
485
 
486
 
487
/**********************/
488
/* Function IsWinNT() */
489
/**********************/
490
 
491
int IsWinNT(void)       /* returns TRUE if real NT, FALSE if Win9x or Win32s */
492
{
493
    static DWORD g_PlatformId = 0xFFFFFFFF; /* saved platform indicator */
494
 
495
    if (g_PlatformId == 0xFFFFFFFF) {
496
        /* note: GetVersionEx() doesn't exist on WinNT 3.1 */
497
        if (GetVersion() < 0x80000000)
498
            g_PlatformId = TRUE;
499
        else
500
            g_PlatformId = FALSE;
501
    }
502
    return (int)g_PlatformId;
503
}
504
 
505
 
506
/* DEBUG_TIME insertion: */
507
#ifdef DEBUG_TIME
508
static int show_NTFileTime(FILE *hdo, char *TTmsg, int isloc, FILETIME *pft);
509
 
510
static int show_NTFileTime(FILE *hdo, char *TTmsg, int isloc, FILETIME *pft)
511
{
512
    SYSTEMTIME w32tm;
513
    int rval;
514
 
515
    rval = FileTimeToSystemTime(pft, &w32tm);
516
    if (!rval) {
517
        fprintf(hdo, "%s\n %08lX,%08lX (%s) -> Conversion failed !!!\n",
518
                TTmsg, (ulg)(pft->dwHighDateTime), (ulg)(pft->dwLowDateTime),
519
                (isloc ? "local" : "UTC"));
520
    } else {
521
        fprintf(hdo, "%s\n %08lx,%08lx -> %04u-%02u-%02u, %02u:%02u:%02u %s\n",
522
                TTmsg, (ulg)(pft->dwHighDateTime), (ulg)(pft->dwLowDateTime),
523
                w32tm.wYear, w32tm.wMonth, w32tm.wDay, w32tm.wHour,
524
                w32tm.wMinute, w32tm.wSecond, (isloc ? "local" : "UTC"));
525
    }
526
    return rval;
527
}
528
#define FTTrace(x)   show_NTFileTime x
529
#else
530
#define FTTrace(x)
531
#endif /* DEBUG_TIME */
532
/* end of DEBUG_TIME insertion */
533
 
534
#ifndef IZ_USE_INT64
535
#  if (defined(__GNUC__) || defined(ULONG_LONG_MAX))
536
     typedef long long            LLONG64;
537
     typedef unsigned long long   ULLNG64;
538
#    define IZ_USE_INT64
539
#  elif (defined(__WATCOMC__) && (__WATCOMC__ >= 1100))
540
     typedef __int64              LLONG64;
541
     typedef unsigned __int64     ULLNG64;
542
#    define IZ_USE_INT64
543
#  elif (defined(_MSC_VER) && (_MSC_VER >= 1100))
544
     typedef __int64              LLONG64;
545
     typedef unsigned __int64     ULLNG64;
546
#    define IZ_USE_INT64
547
#  elif (defined(__IBMC__) && (__IBMC__ >= 350))
548
     typedef __int64              LLONG64;
549
     typedef unsigned __int64     ULLNG64;
550
#    define IZ_USE_INT64
551
#  elif defined(HAVE_INT64)
552
     typedef __int64              LLONG64;
553
     typedef unsigned __int64     ULLNG64;
554
#    define IZ_USE_INT64
555
#  endif
556
#endif
557
 
558
/* scale factor and offset for conversion time_t -> FILETIME */
559
#define NT_QUANTA_PER_UNIX 10000000L
560
#define UNIX_TIME_ZERO_HI  0x019DB1DEUL
561
#define UNIX_TIME_ZERO_LO  0xD53E8000UL
562
/* special FILETIME values for bound-checks */
563
#define UNIX_TIME_UMAX_HI  0x0236485EUL
564
#define UNIX_TIME_UMAX_LO  0xD4A5E980UL
565
#define UNIX_TIME_SMIN_HI  0x0151669EUL
566
#define UNIX_TIME_SMIN_LO  0xD53E8000UL
567
#define UNIX_TIME_SMAX_HI  0x01E9FD1EUL
568
#define UNIX_TIME_SMAX_LO  0xD4A5E980UL
569
#define DOSTIME_MIN_FT_HI  0x01A8E79FUL
570
#define DOSTIME_MIN_FT_LO  0xE1D58000UL
571
/* time_t equivalent of DOSTIME_MINIMUM */
572
#define UTIME_1980_JAN_01_00_00   315532800L
573
 
574
 
575
#ifndef NO_W32TIMES_IZFIX
576
/*********************************/
577
/* Function utime2NtfsFileTime() */ /* convert Unix time_t format into the */
578
/*********************************/ /* form used by SetFileTime() in NT/9x */
579
 
580
static void utime2NtfsFileTime(time_t ut, FILETIME *pft)
581
{
582
#ifdef IZ_USE_INT64
583
    ULLNG64 NTtime;
584
 
585
    /* NT_QUANTA_PER_UNIX is small enough so that "ut * NT_QUANTA_PER_UNIX"
586
     * cannot overflow in 64-bit signed calculation, regardless whether "ut"
587
     * is signed or unsigned.  */
588
    NTtime = ((LLONG64)ut * NT_QUANTA_PER_UNIX) +
589
             ((ULLNG64)UNIX_TIME_ZERO_LO + ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
590
    pft->dwLowDateTime = (DWORD)NTtime;
591
    pft->dwHighDateTime = (DWORD)(NTtime >> 32);
592
 
593
#else /* !IZ_USE_INT64 (64-bit integer arithmetics may not be supported) */
594
    unsigned int b1, b2, carry = 0;
595
    unsigned long r0, r1, r2, r3;
596
    long r4;            /* signed, to catch environments with signed time_t */
597
 
598
    b1 = ut & 0xFFFF;
599
    b2 = (ut >> 16) & 0xFFFF;       /* if ut is over 32 bits, too bad */
600
    r1 = b1 * (NT_QUANTA_PER_UNIX & 0xFFFF);
601
    r2 = b1 * (NT_QUANTA_PER_UNIX >> 16);
602
    r3 = b2 * (NT_QUANTA_PER_UNIX & 0xFFFF);
603
    r4 = b2 * (NT_QUANTA_PER_UNIX >> 16);
604
    r0 = (r1 + (r2 << 16)) & 0xFFFFFFFFL;
605
    if (r0 < r1)
606
        carry++;
607
    r1 = r0;
608
    r0 = (r0 + (r3 << 16)) & 0xFFFFFFFFL;
609
    if (r0 < r1)
610
        carry++;
611
    pft->dwLowDateTime = r0 + UNIX_TIME_ZERO_LO;
612
    if (pft->dwLowDateTime < r0)
613
        carry++;
614
    pft->dwHighDateTime = r4 + (r2 >> 16) + (r3 >> 16)
615
                            + UNIX_TIME_ZERO_HI + carry;
616
#endif /* ?IZ_USE_INT64 */
617
 
618
} /* end function utime2NtfsFileTime() */
619
#endif /* !NO_W32TIMES_IZFIX */
620
 
621
 
622
 
623
/*********************************/
624
/* Function utime2VFatFileTime() */ /* convert Unix time_t format into the */
625
/*********************************/ /* form used by SetFileTime() in NT/9x */
626
 
627
static void utime2VFatFileTime(time_t ut, FILETIME *pft, int clipDosMin)
628
{
629
    time_t utc = ut;
630
    struct tm *ltm;
631
    SYSTEMTIME w32tm;
632
    FILETIME lft;
633
 
634
    /* The milliseconds field gets always initialized to 0. */
635
    w32tm.wMilliseconds = 0;
636
 
637
#ifdef __BORLANDC__   /* Borland C++ 5.x crashes when trying to reference tm */
638
    if (utc < UTIME_1980_JAN_01_00_00)
639
        utc = UTIME_1980_JAN_01_00_00;
640
#endif
641
    ltm = localtime(&utc);
642
    if (ltm == (struct tm *)NULL)
643
        /* localtime() did not accept given utc time value; try to use
644
           the UTC value */
645
        ltm = gmtime(&utc);
646
    if (ltm == (struct tm *)NULL) {
647
        if (ut <= (UTIME_1980_JAN_01_00_00 + 86400)) {
648
            /* use DOSTIME_MINIMUM date instead of "early" failure dates */
649
            w32tm.wYear = 1980;
650
            w32tm.wMonth = 1;
651
            w32tm.wDay = 1;
652
            w32tm.wHour = 0;
653
            w32tm.wMinute = 0;
654
            w32tm.wSecond = 0;
655
        } else {
656
            /* as a last resort, use the current system time */
657
            GetLocalTime(&w32tm);
658
        }
659
    } else if (clipDosMin && (ltm->tm_year < 80)) {
660
        w32tm.wYear = 1980;
661
        w32tm.wMonth = 1;
662
        w32tm.wDay = 1;
663
        w32tm.wHour = 0;
664
        w32tm.wMinute = 0;
665
        w32tm.wSecond = 0;
666
    } else {
667
        w32tm.wYear = ltm->tm_year + 1900; /* year + 1900 -> year */
668
        w32tm.wMonth = ltm->tm_mon + 1;    /* 0..11 -> 1..12 */
669
        w32tm.wDay = ltm->tm_mday;         /* 1..31 */
670
        w32tm.wHour = ltm->tm_hour;        /* 0..23 */
671
        w32tm.wMinute = ltm->tm_min;       /* 0..59 */
672
        w32tm.wSecond = ltm->tm_sec;       /* 0..61 in ANSI C */
673
    }
674
 
675
    SystemTimeToFileTime(&w32tm, &lft);
676
    LocalFileTimeToFileTime(&lft, pft);
677
 
678
} /* end function utime2VFatFileTime() */
679
 
680
 
681
 
682
 /* nonzero if `y' is a leap year, else zero */
683
#define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0)
684
 /* number of leap years from 1970 to `y' (not including `y' itself) */
685
#define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400)
686
 
687
extern ZCONST ush ydays[];              /* defined in fileio.c */
688
 
689
#if (defined(W32_STAT_BANDAID) && !defined(NO_W32TIMES_IZFIX))
690
/*********************************/
691
/* Function NtfsFileTime2utime() */
692
/*********************************/
693
 
694
static int NtfsFileTime2utime(const FILETIME *pft, time_t *ut)
695
{
696
#ifdef IZ_USE_INT64
697
    ULLNG64 NTtime;
698
 
699
    NTtime = ((ULLNG64)pft->dwLowDateTime +
700
              ((ULLNG64)pft->dwHighDateTime << 32));
701
 
702
#ifndef TIME_T_TYPE_DOUBLE
703
    /* underflow and overflow handling */
704
#ifdef CHECK_UTIME_SIGNED_UNSIGNED
705
    if ((time_t)0x80000000L < (time_t)0L)
706
    {
707
        if (NTtime < ((ULLNG64)UNIX_TIME_SMIN_LO +
708
                      ((ULLNG64)UNIX_TIME_SMIN_HI << 32))) {
709
            *ut = (time_t)LONG_MIN;
710
            return FALSE;
711
        }
712
        if (NTtime > ((ULLNG64)UNIX_TIME_SMAX_LO +
713
                      ((ULLNG64)UNIX_TIME_SMAX_HI << 32))) {
714
            *ut = (time_t)LONG_MAX;
715
            return FALSE;
716
        }
717
    }
718
    else
719
#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
720
    {
721
        if (NTtime < ((ULLNG64)UNIX_TIME_ZERO_LO +
722
                      ((ULLNG64)UNIX_TIME_ZERO_HI << 32))) {
723
            *ut = (time_t)0;
724
            return FALSE;
725
        }
726
        if (NTtime > ((ULLNG64)UNIX_TIME_UMAX_LO +
727
                      ((ULLNG64)UNIX_TIME_UMAX_HI << 32))) {
728
            *ut = (time_t)ULONG_MAX;
729
            return FALSE;
730
        }
731
    }
732
#endif /* !TIME_T_TYPE_DOUBLE */
733
 
734
    NTtime -= ((ULLNG64)UNIX_TIME_ZERO_LO +
735
               ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
736
    *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX);
737
    return TRUE;
738
#else /* !IZ_USE_INT64 (64-bit integer arithmetics may not be supported) */
739
    time_t days;
740
    SYSTEMTIME w32tm;
741
 
742
#ifndef TIME_T_TYPE_DOUBLE
743
    /* underflow and overflow handling */
744
#ifdef CHECK_UTIME_SIGNED_UNSIGNED
745
    if ((time_t)0x80000000L < (time_t)0L)
746
    {
747
        if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
748
            ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
749
             (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
750
            *ut = (time_t)LONG_MIN;
751
            return FALSE;
752
        if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
753
            ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
754
             (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
755
            *ut = (time_t)LONG_MAX;
756
            return FALSE;
757
        }
758
    }
759
    else
760
#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
761
    {
762
        if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
763
            ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
764
             (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
765
            *ut = (time_t)0;
766
            return FALSE;
767
        }
768
        if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
769
            ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
770
             (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
771
            *ut = (time_t)ULONG_MAX;
772
            return FALSE;
773
        }
774
    }
775
#endif /* !TIME_T_TYPE_DOUBLE */
776
 
777
    FileTimeToSystemTime(pft, &w32tm);
778
 
779
    /* set `days' to the number of days into the year */
780
    days = w32tm.wDay - 1 + ydays[w32tm.wMonth-1] +
781
           (w32tm.wMonth > 2 && leap (w32tm.wYear));
782
 
783
    /* now set `days' to the number of days since 1 Jan 1970 */
784
    days += 365 * (time_t)(w32tm.wYear - 1970) +
785
            (time_t)(nleap(w32tm.wYear));
786
 
787
    *ut = (time_t)(86400L * days + 3600L * (time_t)w32tm.wHour +
788
                   (time_t)(60 * w32tm.wMinute + w32tm.wSecond));
789
    return TRUE;
790
#endif /* ?IZ_USE_INT64 */
791
} /* end function NtfsFileTime2utime() */
792
#endif /* W32_STAT_BANDAID && !NO_W32TIMES_IZFIX */
793
 
794
 
795
 
796
#ifdef W32_STAT_BANDAID
797
/*********************************/
798
/* Function VFatFileTime2utime() */
799
/*********************************/
800
 
801
static int VFatFileTime2utime(const FILETIME *pft, time_t *ut)
802
{
803
    FILETIME lft;
804
#ifndef HAVE_MKTIME
805
    WORD wDOSDate, wDOSTime;
806
#else
807
    SYSTEMTIME w32tm;
808
    struct tm ltm;
809
#endif
810
 
811
    if (!FileTimeToLocalFileTime(pft, &lft)) {
812
        /* if pft cannot be converted to local time, set ut to current time */
813
        time(ut);
814
        return FALSE;
815
    }
816
    FTTrace((stdout, "VFatFT2utime, feed for mktime()", 1, &lft));
817
#ifndef HAVE_MKTIME
818
    /* This version of the FILETIME-to-UNIXTIME conversion function
819
     * uses DOS-DATE-TIME format as intermediate stage. For modification
820
     * and access times, this is no problem. But, the extra fine resolution
821
     * of the VFAT-stored creation time gets lost.
822
     */
823
    if (!FileTimeToDosDateTime(&lft, &wDOSDate, &wDOSTime)) {
824
        static const FILETIME dosmin_ft =
825
                {DOSTIME_MIN_FT_LO, DOSTIME_MIN_FT_HI};
826
        if (CompareFileTime(&lft, &dosmin_ft) <= 0) {
827
            /* underflow -> set to minimum DOS time */
828
            wDOSDate = (WORD)((DWORD)DOSTIME_MINIMUM >> 16);
829
            wDOSTime = (WORD)DOSTIME_MINIMUM;
830
        } else {
831
            /* overflow -> set to maximum DOS time */
832
            wDOSDate = (WORD)0xFF9F;    /* 2107-12-31 */
833
            wDOSTime = (WORD)0xBF7D;    /* 23:59:58 */
834
        }
835
    }
836
    TTrace((stdout,"DosDateTime is %04u-%02u-%02u %02u:%02u:%02u\n",
837
      (unsigned)((wDOSDate>>9)&0x7f)+1980,(unsigned)((wDOSDate>>5)&0x0f),
838
      (unsigned)(wDOSDate&0x1f),(unsigned)((wDOSTime>>11)&0x1f),
839
      (unsigned)((wDOSTime>>5)&0x3f),(unsigned)((wDOSTime<<1)&0x3e)));
840
    *ut = dos_to_unix_time(((ulg)wDOSDate << 16) | (ulg)wDOSTime);
841
 
842
    /* a cheap error check: dos_to_unix_time() only returns an odd time
843
     * when clipping at maximum time_t value. DOS_DATE_TIME values have
844
     * a resolution of 2 seconds and are therefore even numbers.
845
     */
846
    return (((*ut)&1) == (time_t)0);
847
#else /* HAVE_MKTIME */
848
    FileTimeToSystemTime(&lft, &w32tm);
849
#ifndef TIME_T_TYPE_DOUBLE
850
    /* underflow and overflow handling */
851
    /* TODO: The range checks are not accurate, the actual limits may
852
     *       be off by one daylight-saving-time shift (typically 1 hour),
853
     *       depending on the current state of "is_dst".
854
     */
855
#ifdef CHECK_UTIME_SIGNED_UNSIGNED
856
    if ((time_t)0x80000000L < (time_t)0L)
857
    {
858
        if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
859
            ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
860
             (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
861
            *ut = (time_t)LONG_MIN;
862
            return FALSE;
863
        if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
864
            ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
865
             (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
866
            *ut = (time_t)LONG_MAX;
867
            return FALSE;
868
        }
869
    }
870
    else
871
#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
872
    {
873
        if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
874
            ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
875
             (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
876
            *ut = (time_t)0;
877
            return FALSE;
878
        }
879
        if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
880
            ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
881
             (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
882
            *ut = (time_t)ULONG_MAX;
883
            return FALSE;
884
        }
885
    }
886
#endif /* !TIME_T_TYPE_DOUBLE */
887
    ltm.tm_year = w32tm.wYear - 1900;
888
    ltm.tm_mon = w32tm.wMonth - 1;
889
    ltm.tm_mday = w32tm.wDay;
890
    ltm.tm_hour = w32tm.wHour;
891
    ltm.tm_min = w32tm.wMinute;
892
    ltm.tm_sec = w32tm.wSecond;
893
    ltm.tm_isdst = -1;  /* let mktime determine if DST is in effect */
894
    *ut = mktime(<m);
895
 
896
    /* a cheap error check: mktime returns "(time_t)-1L" on conversion errors.
897
     * Normally, we would have to apply a consistency check because "-1"
898
     * could also be a valid time. But, it is quite unlikely to read back odd
899
     * time numbers from file systems that store time stamps in DOS format.
900
     * (The only known exception is creation time on VFAT partitions.)
901
     */
902
    return (*ut != (time_t)-1L);
903
#endif /* ?HAVE_MKTIME */
904
 
905
} /* end function VFatFileTime2utime() */
906
#endif /* W32_STAT_BANDAID */
907
 
908
 
909
 
910
/******************************/
911
/* Function FStampIsLocTime() */
912
/******************************/
913
 
914
static int FStampIsLocTime(__GPRO__ const char *path)
915
{
916
    return (NTQueryVolInfo(__G__ path) ? G.lastVolLocTim : FALSE);
917
}
918
 
919
 
920
 
921
#ifndef NO_W32TIMES_IZFIX
922
# define UTIME_2_IZFILETIME(ut, pft) \
923
   if (fs_uses_loctime) {utime2VFatFileTime(ut, pft, TRUE);} \
924
   else {utime2NtfsFileTime(ut, pft);}
925
#else
926
# define UTIME_2_IZFILETIME(ut, pft) \
927
   utime2VFatFileTime(ut, pft, fs_uses_loctime);
928
#endif
929
 
930
 
931
 
932
/****************************/      /* Get the file time in a format that */
933
/* Function getNTfiletime() */      /*  can be used by SetFileTime() in NT */
934
/****************************/
935
 
936
static int getNTfiletime(__G__ pModFT, pAccFT, pCreFT)
937
    __GDEF
938
    FILETIME *pModFT;
939
    FILETIME *pAccFT;
940
    FILETIME *pCreFT;
941
{
942
#ifdef USE_EF_UT_TIME
943
    unsigned eb_izux_flg;
944
    iztimes z_utime;   /* struct for Unix-style actime & modtime, + creatime */
945
#endif
946
    int fs_uses_loctime = FStampIsLocTime(__G__ G.filename);
947
 
948
    /* Copy and/or convert time and date variables, if necessary;
949
     * return a flag indicating which time stamps are available. */
950
#ifdef USE_EF_UT_TIME
951
    if (G.extra_field &&
952
#ifdef IZ_CHECK_TZ
953
        G.tz_is_valid &&
954
#endif
955
        ((eb_izux_flg = ef_scan_for_izux(G.extra_field,
956
          G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
957
          &z_utime, NULL)) & EB_UT_FL_MTIME))
958
    {
959
        TTrace((stderr, "getNTfiletime:  Unix e.f. modif. time = %lu\n",
960
          z_utime.mtime));
961
        UTIME_2_IZFILETIME(z_utime.mtime, pModFT)
962
        if (eb_izux_flg & EB_UT_FL_ATIME) {
963
            UTIME_2_IZFILETIME(z_utime.atime, pAccFT)
964
        }
965
        if (eb_izux_flg & EB_UT_FL_CTIME) {
966
            UTIME_2_IZFILETIME(z_utime.ctime, pCreFT)
967
        }
968
        return (int)eb_izux_flg;
969
    }
970
#endif /* USE_EF_UT_TIME */
971
#ifndef NO_W32TIMES_IZFIX
972
    if (!fs_uses_loctime) {
973
        time_t ux_modtime;
974
 
975
        ux_modtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
976
        utime2NtfsFileTime(ux_modtime, pModFT);
977
    } else
978
#endif /* NO_W32TIMES_IZFIX */
979
    {
980
        FILETIME lft;
981
 
982
        DosDateTimeToFileTime((WORD)(G.lrec.last_mod_dos_datetime >> 16),
983
                              (WORD)(G.lrec.last_mod_dos_datetime & 0xFFFFL),
984
                              &lft);
985
        LocalFileTimeToFileTime(&lft, pModFT);
986
    }
987
    *pAccFT = *pModFT;
988
    return (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
989
 
990
} /* end function getNTfiletime() */
991
 
992
 
993
 
994
 
995
/**************************/
996
/* Function SetFileSize() */
997
/**************************/
998
 
999
int SetFileSize(FILE *file, zusz_t filesize)
1000
{
1001
#ifdef __RSXNT__
1002
    /* RSXNT environment lacks a translation function from C file pointer
1003
       to Win32-API file handle. So, simply do nothing. */
1004
    return 0;
1005
#else /* !__RSXNT__ */
1006
    /* not yet verified, if that really creates an unfragmented file
1007
      rommel@ars.de
1008
     */
1009
    HANDLE os_fh;
1010
#ifdef Z_UINT8_DEFINED
1011
    LARGE_INTEGER fsbuf;
1012
#endif
1013
 
1014
    /* Win9x supports FAT file system, only; presetting file size does
1015
       not help to prevent fragmentation. */
1016
    if (!IsWinNT()) return 0;
1017
 
1018
    /* Win32-API calls require access to the Win32 file handle.
1019
       The interface function used to retrieve the Win32 handle for
1020
       a file opened by the C rtl is non-standard and may not be
1021
       available for every Win32 compiler environment.
1022
       (see also win32/win32.c of the Zip distribution)
1023
     */
1024
    os_fh = (HANDLE)_get_osfhandle(fileno(file));
1025
    /* move file pointer behind the last byte of the expected file size */
1026
#ifdef Z_UINT8_DEFINED
1027
    fsbuf.QuadPart = filesize;
1028
    if ((SetFilePointer(os_fh, fsbuf.LowPart, &fsbuf.HighPart, FILE_BEGIN)
1029
         == 0xFFFFFFFF) && GetLastError() != NO_ERROR)
1030
#else
1031
    if (SetFilePointer(os_fh, (ulg)filesize, 0, FILE_BEGIN) == 0xFFFFFFFF)
1032
#endif
1033
        return -1;
1034
    /* extend/truncate file to the current position */
1035
    if (SetEndOfFile(os_fh) == 0)
1036
        return -1;
1037
    /* move file position pointer back to the start of the file! */
1038
    return (SetFilePointer(os_fh, 0, 0, FILE_BEGIN) == 0xFFFFFFFF) ? -1 : 0;
1039
#endif /* ?__RSXNT__ */
1040
} /* end function SetFileSize() */
1041
 
1042
 
1043
 
1044
 
1045
/****************************/
1046
/* Function close_outfile() */
1047
/****************************/
1048
 
1049
void close_outfile(__G)
1050
    __GDEF
1051
{
1052
    FILETIME Modft;    /* File time type defined in NT, `last modified' time */
1053
    FILETIME Accft;    /* NT file time type, `last access' time */
1054
    FILETIME Creft;    /* NT file time type, `file creation' time */
1055
    HANDLE hFile = INVALID_HANDLE_VALUE;        /* File handle defined in NT */
1056
    int gotTime;
1057
#ifdef NTSD_EAS
1058
    uch *ebSDptr;
1059
    unsigned ebSDlen;
1060
#endif
1061
#ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
1062
    char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
1063
 
1064
    INTERN_TO_ISO(G.filename, ansi_name);
1065
#   define Ansi_Fname  ansi_name
1066
#else
1067
#   define Ansi_Fname  G.filename
1068
#endif
1069
 
1070
#ifndef __RSXNT__
1071
    if (IsWinNT()) {
1072
        /* Truncate the file to the current position.
1073
         * This is needed to remove excess allocation in case the
1074
         * extraction has failed or stopped prematurely. */
1075
        SetEndOfFile((HANDLE)_get_osfhandle(fileno(G.outfile)));
1076
    }
1077
#endif
1078
 
1079
    /* Close the file and then re-open it using the Win32
1080
     * CreateFile call, so that the file can be created
1081
     * with GENERIC_WRITE access, otherwise the SetFileTime
1082
     * call will fail. */
1083
    fclose(G.outfile);
1084
 
1085
    /* don't set the time stamp and attributes on standard output */
1086
    if (uO.cflag)
1087
        return;
1088
 
1089
    /* skip restoring time stamps on user's request */
1090
    if (uO.D_flag <= 1) {
1091
        gotTime = getNTfiletime(__G__ &Modft, &Accft, &Creft);
1092
 
1093
        /* open a handle to the file before processing extra fields;
1094
           we do this in case new security on file prevents us from updating
1095
           time stamps */
1096
        hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1097
             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1098
    } else {
1099
        gotTime = 0;
1100
    }
1101
 
1102
    /* sfield@microsoft.com: set attributes before time in case we decide to
1103
       support other filetime members later.  This also allows us to apply
1104
       attributes before the security is changed, which may prevent this
1105
       from succeeding otherwise.  Also, since most files don't have
1106
       any interesting attributes, only change them if something other than
1107
       FILE_ATTRIBUTE_ARCHIVE appears in the attributes.  This works well
1108
       as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the
1109
       file anyway, when it's created new. */
1110
    if ((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) {
1111
        if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
1112
            Info(slide, 1, ((char *)slide,
1113
              "\nwarning (%d): could not set file attributes\n",
1114
              (int)GetLastError()));
1115
    }
1116
 
1117
#ifdef NTSD_EAS
1118
    /* set NTFS SD extra fields */
1119
    if (G.extra_field &&    /* zipfile extra field may have extended attribs */
1120
        FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
1121
                         &ebSDptr, &ebSDlen))
1122
    {
1123
        int err = SetSD(__G__ Ansi_Fname, G.pInfo->file_attr,
1124
                        ebSDptr, ebSDlen);
1125
 
1126
        if (err == IZ_EF_TRUNC) {
1127
            if (uO.qflag)
1128
                Info(slide, 1, ((char *)slide, "%-22s ",
1129
                  FnFilter1(G.filename)));
1130
            Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
1131
              ebSDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), uO.qflag? "\n":""));
1132
        }
1133
    }
1134
#endif /* NTSD_EAS */
1135
 
1136
    /* skip restoring time stamps on user's request */
1137
    if (uO.D_flag <= 1) {
1138
        if ( hFile == INVALID_HANDLE_VALUE )
1139
            Info(slide, 1, ((char *)slide,
1140
              "\nCreateFile() error %d when trying set file time\n",
1141
              (int)GetLastError()));
1142
        else {
1143
            if (gotTime) {
1144
                FILETIME *pModft = (gotTime & EB_UT_FL_MTIME) ? &Modft : NULL;
1145
                FILETIME *pAccft = (gotTime & EB_UT_FL_ATIME) ? &Accft : NULL;
1146
                FILETIME *pCreft = (gotTime & EB_UT_FL_CTIME) ? &Creft : NULL;
1147
 
1148
                if (!SetFileTime(hFile, pCreft, pAccft, pModft))
1149
                    Info(slide, 0, ((char *)slide,
1150
                      "\nSetFileTime failed: %d\n", (int)GetLastError()));
1151
            }
1152
            CloseHandle(hFile);
1153
        }
1154
    }
1155
 
1156
    return;
1157
 
1158
#undef Ansi_Fname
1159
 
1160
} /* end function close_outfile() */
1161
 
1162
 
1163
 
1164
 
1165
#ifdef SET_DIR_ATTRIB
1166
 
1167
int defer_dir_attribs(__G__ pd)
1168
    __GDEF
1169
    direntry **pd;
1170
{
1171
    NTdirattr *d_entry;
1172
#ifdef NTSD_EAS
1173
    uch *ebSDptr;
1174
    unsigned ebSDlen;
1175
#endif
1176
 
1177
    /* Win9x does not support setting directory time stamps. */
1178
    if (!IsWinNT()) {
1179
        *pd = (direntry *)NULL;
1180
        return PK_OK;
1181
    }
1182
 
1183
#ifdef NTSD_EAS
1184
    /* set extended attributes from extra fields */
1185
    if (G.extra_field &&  /* zipfile e.f. may have extended attribs */
1186
        FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
1187
                         &ebSDptr, &ebSDlen)) {
1188
        /* ebSDlen contains the payload size of the e.f. block, but
1189
           we store it including the e.b. header. */
1190
        ebSDlen += EB_HEADSIZE;
1191
    } else {
1192
        /* no NTSD e.f. block -> no space needed to allocate */
1193
        ebSDlen = 0;
1194
    }
1195
#endif /* NTSD_EAS */
1196
 
1197
    d_entry = (NTdirattr *)malloc(sizeof(NTdirattr)
1198
#ifdef NTSD_EAS
1199
                                  + ebSDlen
1200
#endif
1201
                                  + strlen(G.filename));
1202
    *pd = (direntry *)d_entry;
1203
    if (d_entry == (NTdirattr *)NULL) {
1204
        return PK_MEM;
1205
    }
1206
#ifdef NTSD_EAS
1207
    if (ebSDlen > 0)
1208
        memcpy(d_entry->buf, ebSDptr, ebSDlen);
1209
    d_entry->SDlen = ebSDlen;
1210
    d_entry->fn = d_entry->buf + ebSDlen;
1211
#else
1212
    d_entry->fn = d_entry->buf;
1213
#endif
1214
 
1215
    strcpy(d_entry->fn, G.filename);
1216
 
1217
    d_entry->perms = G.pInfo->file_attr;
1218
 
1219
    d_entry->gotTime = (uO.D_flag <= 0
1220
                        ? getNTfiletime(__G__ &(d_entry->Modft),
1221
                                        &(d_entry->Accft), &(d_entry->Creft))
1222
                        : 0);
1223
    return PK_OK;
1224
} /* end function defer_dir_attribs() */
1225
 
1226
 
1227
int set_direc_attribs(__G__ d)
1228
    __GDEF
1229
    direntry *d;
1230
{
1231
    int errval;
1232
    HANDLE hFile = INVALID_HANDLE_VALUE;        /* File handle defined in NT */
1233
#ifdef __RSXNT__
1234
    char *ansi_name;
1235
#endif
1236
 
1237
    /* Win9x does not support setting directory time stamps. */
1238
    if (!IsWinNT())
1239
        return PK_OK;
1240
 
1241
    errval = PK_OK;
1242
#ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
1243
    ansi_name = (char *)alloca(strlen(d->fn) + 1);
1244
    INTERN_TO_ISO(d->fn, ansi_name);
1245
#   define Ansi_Dirname  ansi_name
1246
#else
1247
#   define Ansi_Dirname  d->fn
1248
#endif
1249
 
1250
    /* Skip restoring directory time stamps on user' request. */
1251
    if (uO.D_flag <= 0) {
1252
        /* Open a handle to the directory before processing extra fields;
1253
           we do this in case new security on file prevents us from updating
1254
           time stamps.
1255
           Although the WIN32 documentation recommends to use GENERIC_WRITE
1256
           access flag to create the handle for SetFileTime(), this is too
1257
           demanding for directories with the "read-only" attribute bit set.
1258
           So we use the more specific flag FILE_WRITE_ATTRIBUTES here to
1259
           request the minimum required access rights. (This problem is a
1260
           Windows bug that has been silently fixed in Windows XP SP2.) */
1261
        hFile = CreateFileA(Ansi_Dirname, FILE_WRITE_ATTRIBUTES,
1262
                            FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1263
                            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1264
    }
1265
 
1266
#ifdef NTSD_EAS
1267
    if (NtAtt(d)->SDlen > 0) {
1268
        int err;
1269
 
1270
        if (QCOND2) {
1271
            Info(slide, 1, ((char *)slide, " set attrib: %-22s  ",
1272
              FnFilter1(d->fn)));
1273
        }
1274
 
1275
        /* set NTFS SD extra fields */
1276
        err = SetSD(__G__ Ansi_Dirname, NtAtt(d)->perms,
1277
                        NtAtt(d)->buf, NtAtt(d)->SDlen - EB_HEADSIZE);
1278
        if (err == IZ_EF_TRUNC) {
1279
            if (!QCOND2)
1280
                Info(slide, 1, ((char *)slide, "%-22s  ",
1281
                  FnFilter1(d->fn)));
1282
            Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
1283
              NtAtt(d)->SDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n"));
1284
        } else if (QCOND2) {
1285
            Info(slide, 0, ((char *)slide, "\n"));
1286
        }
1287
        if (errval < err)
1288
            errval = err;
1289
    }
1290
#endif /* NTSD_EAS */
1291
 
1292
    /* Skip restoring directory time stamps on user' request. */
1293
    if (uO.D_flag <= 0) {
1294
        if (hFile == INVALID_HANDLE_VALUE) {
1295
            Info(slide, 1, ((char *)slide,
1296
              "warning: CreateFile() error %d (set file times for %s)\n",
1297
              (int)GetLastError(), FnFilter1(d->fn)));
1298
            if (!errval)
1299
                errval = PK_WARN;
1300
        } else {
1301
            if (NtAtt(d)->gotTime) {
1302
                FILETIME *pModft = (NtAtt(d)->gotTime & EB_UT_FL_MTIME)
1303
                                  ? &(NtAtt(d)->Modft) : NULL;
1304
                FILETIME *pAccft = (NtAtt(d)->gotTime & EB_UT_FL_ATIME)
1305
                                  ? &(NtAtt(d)->Accft) : NULL;
1306
                FILETIME *pCreft = (NtAtt(d)->gotTime & EB_UT_FL_CTIME)
1307
                                  ? &(NtAtt(d)->Creft) : NULL;
1308
 
1309
                if (!SetFileTime(hFile, pCreft, pAccft, pModft)) {
1310
                    Info(slide, 0, ((char *)slide,
1311
                      "warning:  SetFileTime() for %s error %d\n",
1312
                      FnFilter1(d->fn), (int)GetLastError()));
1313
                    if (!errval)
1314
                        errval = PK_WARN;
1315
                }
1316
            }
1317
            CloseHandle(hFile);
1318
        }
1319
    }
1320
 
1321
    return errval;
1322
} /* end function set_direc_attribs() */
1323
 
1324
#endif /* SET_DIR_ATTRIB */
1325
 
1326
 
1327
 
1328
 
1329
#ifdef TIMESTAMP
1330
 
1331
/*************************/
1332
/* Function stamp_file() */
1333
/*************************/
1334
 
1335
int stamp_file(__GPRO__ ZCONST char *fname, time_t modtime)
1336
{
1337
    FILETIME Modft;    /* File time type defined in NT, `last modified' time */
1338
    HANDLE hFile;      /* File handle defined in NT    */
1339
    int errstat = 0;   /* return status: 0 == "OK", -1 == "Failure" */
1340
    int fs_uses_loctime = FStampIsLocTime(__G__ fname);
1341
#ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
1342
    char *ansi_name = (char *)alloca(strlen(fname) + 1);
1343
 
1344
    INTERN_TO_ISO(fname, ansi_name);
1345
#   define Ansi_Fname  ansi_name
1346
#else
1347
#   define Ansi_Fname  fname
1348
#endif
1349
 
1350
    /* open a handle to the file to prepare setting the mod-time stamp */
1351
    hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1352
         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1353
    if ( hFile == INVALID_HANDLE_VALUE ) {
1354
        errstat = -1;
1355
    } else {
1356
        /* convert time_t modtime into WIN32 native 64bit format */
1357
        UTIME_2_IZFILETIME(modtime, &Modft)
1358
        /* set Access and Modification times of the file to modtime */
1359
        if (!SetFileTime(hFile, NULL, &Modft, &Modft)) {
1360
            errstat = -1;
1361
        }
1362
        CloseHandle(hFile);
1363
    }
1364
 
1365
    return errstat;
1366
 
1367
#undef Ansi_Fname
1368
} /* end function stamp_file() */
1369
 
1370
#endif /* TIMESTAMP */
1371
 
1372
 
1373
 
1374
 
1375
/***********************/
1376
/* Function isfloppy() */   /* more precisely, is it removable? */
1377
/***********************/
1378
 
1379
static int isfloppy(int nDrive)   /* 1 == A:, 2 == B:, etc. */
1380
{
1381
    char rootPathName[4];
1382
 
1383
    rootPathName[0] = (char)('A' + nDrive - 1);   /* build the root path */
1384
    rootPathName[1] = ':';                        /*  name, e.g. "A:/" */
1385
    rootPathName[2] = '/';
1386
    rootPathName[3] = '\0';
1387
 
1388
    return (GetDriveTypeA(rootPathName) == DRIVE_REMOVABLE);
1389
 
1390
} /* end function isfloppy() */
1391
 
1392
 
1393
 
1394
 
1395
/*****************************/
1396
/* Function NTQueryVolInfo() */
1397
/*****************************/
1398
 
1399
/*
1400
 * Note:  8.3 limits on filenames apply only to old-style FAT filesystems.
1401
 *        More recent versions of Windows (Windows NT 3.5 / Windows 4.0)
1402
 *        can support long filenames (LFN) on FAT filesystems.  Check the
1403
 *        filesystem maximum component length field to detect LFN support.
1404
 */
1405
 
1406
static int NTQueryVolInfo(__GPRO__ const char *name)
1407
{
1408
 /* static char lastRootPath[4] = ""; */
1409
 /* static int lastVolOldFAT; */
1410
 /* static int lastVolLocTim; */
1411
    char *tmp0;
1412
    char tmp1[MAX_PATH], tmp2[MAX_PATH];
1413
    DWORD volSerNo, maxCompLen, fileSysFlags;
1414
#ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
1415
    char *ansi_name = (char *)alloca(strlen(name) + 1);
1416
 
1417
    INTERN_TO_ISO(name, ansi_name);
1418
    name = ansi_name;
1419
#endif
1420
 
1421
    if ((!strncmp(name, "//", 2) || !strncmp(name, "\\\\", 2)) &&
1422
        (name[2] != '\0' && name[2] != '/' && name[2] != '\\')) {
1423
        /* GetFullPathname() and GetVolumeInformation() do not work
1424
         * on UNC names. For now, we return "error".
1425
         * **FIXME**: check if UNC name is mapped to a drive letter
1426
         *            and use mapped drive for volume info query.
1427
         */
1428
        return FALSE;
1429
    }
1430
    if (isalpha((uch)name[0]) && (name[1] == ':'))
1431
        tmp0 = (char *)name;
1432
    else
1433
    {
1434
        if (!GetFullPathNameA(name, MAX_PATH, tmp1, &tmp0))
1435
            return FALSE;
1436
        tmp0 = &tmp1[0];
1437
    }
1438
    if (strncmp(G.lastRootPath, tmp0, 2) != 0) {
1439
        /* For speed, we skip repeated queries for the same device */
1440
        strncpy(G.lastRootPath, tmp0, 2);   /* Build the root path name, */
1441
        G.lastRootPath[2] = '/';            /* e.g. "A:/"                */
1442
        G.lastRootPath[3] = '\0';
1443
 
1444
        if (!GetVolumeInformationA((LPCSTR)G.lastRootPath,
1445
              (LPSTR)tmp1, (DWORD)MAX_PATH,
1446
              &volSerNo, &maxCompLen, &fileSysFlags,
1447
              (LPSTR)tmp2, (DWORD)MAX_PATH)) {
1448
            G.lastRootPath[0] = '\0';
1449
            return FALSE;
1450
        }
1451
 
1452
        /*  LFNs are available if the component length is > 12 */
1453
        G.lastVolOldFAT = (maxCompLen <= 12);
1454
/*      G.lastVolOldFAT = !strncmp(strupr(tmp2), "FAT", 3);   old version */
1455
 
1456
        /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
1457
         * local time!
1458
         */
1459
        G.lastVolLocTim = !strncmp(strupr(tmp2), "VFAT", 4) ||
1460
                          !strncmp(tmp2, "HPFS", 4) ||
1461
                          !strncmp(tmp2, "FAT", 3);
1462
    }
1463
 
1464
    return TRUE;
1465
 
1466
} /* end function NTQueryVolInfo() */
1467
 
1468
 
1469
 
1470
 
1471
/*****************************/
1472
/* Function IsVolumeOldFAT() */
1473
/*****************************/
1474
 
1475
static int IsVolumeOldFAT(__GPRO__ const char *name)
1476
{
1477
    return (NTQueryVolInfo(__G__ name) ? G.lastVolOldFAT : FALSE);
1478
}
1479
 
1480
 
1481
 
1482
 
1483
#ifndef SFX
1484
 
1485
/************************/
1486
/*  Function do_wild()  */   /* identical to OS/2 version */
1487
/************************/
1488
 
1489
char *do_wild(__G__ wildspec)
1490
    __GDEF
1491
    ZCONST char *wildspec;  /* only used first time on a given dir */
1492
{
1493
/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in w32cfg.h:
1494
    static zDIR *wild_dir = NULL;
1495
    static ZCONST char *wildname;
1496
    static char *dirname, matchname[FILNAMSIZ];
1497
    static int notfirstcall=FALSE, have_dirname, dirnamelen;
1498
*/
1499
    char *fnamestart;
1500
    struct zdirent *file;
1501
 
1502
    /* Even when we're just returning wildspec, we *always* do so in
1503
     * matchname[]--calling routine is allowed to append four characters
1504
     * to the returned string, and wildspec may be a pointer to argv[].
1505
     */
1506
    if (!G.notfirstcall) {  /* first call:  must initialize everything */
1507
        G.notfirstcall = TRUE;
1508
 
1509
        if (!iswild(wildspec)) {
1510
            strncpy(G.matchname, wildspec, FILNAMSIZ);
1511
            G.matchname[FILNAMSIZ-1] = '\0';
1512
            G.have_dirname = FALSE;
1513
            G.wild_dir = NULL;
1514
            return G.matchname;
1515
        }
1516
 
1517
        /* break the wildspec into a directory part and a wildcard filename */
1518
        if ((G.wildname = MBSRCHR(wildspec, '/')) == (ZCONST char *)NULL &&
1519
            (G.wildname = MBSRCHR(wildspec, ':')) == (ZCONST char *)NULL) {
1520
            G.dirname = ".";
1521
            G.dirnamelen = 1;
1522
            G.have_dirname = FALSE;
1523
            G.wildname = wildspec;
1524
        } else {
1525
            ++G.wildname;     /* point at character after '/' or ':' */
1526
            G.dirnamelen = G.wildname - wildspec;
1527
            if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == NULL) {
1528
                Info(slide, 1, ((char *)slide,
1529
                  "warning:  cannot allocate wildcard buffers\n"));
1530
                strncpy(G.matchname, wildspec, FILNAMSIZ);
1531
                G.matchname[FILNAMSIZ-1] = '\0';
1532
                return G.matchname; /* but maybe filespec was not a wildcard */
1533
            }
1534
            strncpy(G.dirname, wildspec, G.dirnamelen);
1535
            G.dirname[G.dirnamelen] = '\0';   /* terminate for strcpy below */
1536
            G.have_dirname = TRUE;
1537
        }
1538
        Trace((stderr, "do_wild:  dirname = [%s]\n", FnFilter1(G.dirname)));
1539
 
1540
        if ((G.wild_dir = (zvoid *)Opendir(G.dirname)) != NULL) {
1541
            if (G.have_dirname) {
1542
                strcpy(G.matchname, G.dirname);
1543
                fnamestart = G.matchname + G.dirnamelen;
1544
            } else
1545
                fnamestart = G.matchname;
1546
            while ((file = Readdir((zDIR *)G.wild_dir)) != NULL) {
1547
                Trace((stderr, "do_wild:  Readdir returns %s\n",
1548
                  FnFilter1(file->d_name)));
1549
                strcpy(fnamestart, file->d_name);
1550
                if (MBSRCHR(fnamestart, '.') == (char *)NULL)
1551
                    strcat(fnamestart, ".");
1552
                if (match(fnamestart, G.wildname, TRUE WISEP) &&
1553
                    /* skip "." and ".." directory entries */
1554
                    strcmp(fnamestart, ".") && strcmp(fnamestart, "..")) {
1555
                    Trace((stderr, "do_wild:  match() succeeds\n"));
1556
                    /* remove trailing dot */
1557
                    fnamestart = plastchar(fnamestart, strlen(fnamestart));
1558
                    if (*fnamestart == '.')
1559
                        *fnamestart = '\0';
1560
                    return G.matchname;
1561
                }
1562
            }
1563
            /* if we get to here directory is exhausted, so close it */
1564
            Closedir((zDIR *)G.wild_dir);
1565
            G.wild_dir = NULL;
1566
        }
1567
        Trace((stderr, "do_wild:  Opendir(%s) returns NULL\n",
1568
          FnFilter1(G.dirname)));
1569
 
1570
        /* return the raw wildspec in case that works (e.g., directory not
1571
         * searchable, but filespec was not wild and file is readable) */
1572
        strncpy(G.matchname, wildspec, FILNAMSIZ);
1573
        G.matchname[FILNAMSIZ-1] = '\0';
1574
        return G.matchname;
1575
    }
1576
 
1577
    /* last time through, might have failed opendir but returned raw wildspec */
1578
    if (G.wild_dir == NULL) {
1579
        G.notfirstcall = FALSE;    /* reset for new wildspec */
1580
        if (G.have_dirname)
1581
            free(G.dirname);
1582
        return (char *)NULL;
1583
    }
1584
 
1585
    /* If we've gotten this far, we've read and matched at least one entry
1586
     * successfully (in a previous call), so dirname has been copied into
1587
     * matchname already.
1588
     */
1589
    if (G.have_dirname) {
1590
        /* strcpy(G.matchname, G.dirname); */
1591
        fnamestart = G.matchname + G.dirnamelen;
1592
    } else
1593
        fnamestart = G.matchname;
1594
    while ((file = Readdir((zDIR *)G.wild_dir)) != NULL) {
1595
        Trace((stderr, "do_wild:  readdir returns %s\n",
1596
          FnFilter1(file->d_name)));
1597
        strcpy(fnamestart, file->d_name);
1598
        if (MBSRCHR(fnamestart, '.') == (char *)NULL)
1599
            strcat(fnamestart, ".");
1600
        if (match(fnamestart, G.wildname, TRUE WISEP)) {
1601
            Trace((stderr, "do_wild:  match() succeeds\n"));
1602
            /* remove trailing dot */
1603
            fnamestart = plastchar(fnamestart, strlen(fnamestart));
1604
            if (*fnamestart == '.')
1605
                *fnamestart = '\0';
1606
            return G.matchname;
1607
        }
1608
    }
1609
 
1610
    Closedir((zDIR *)G.wild_dir);  /* at least one entry read; nothing left */
1611
    G.wild_dir = NULL;
1612
    G.notfirstcall = FALSE;        /* reset for new wildspec */
1613
    if (G.have_dirname)
1614
        free(G.dirname);
1615
    return (char *)NULL;
1616
 
1617
} /* end function do_wild() */
1618
 
1619
#endif /* !SFX */
1620
 
1621
 
1622
 
1623
/**********************/
1624
/* Function mapattr() */
1625
/**********************/
1626
 
1627
/* Identical to MS-DOS, OS/2 versions.  However, NT has a lot of extra
1628
 * permission stuff, so this function should probably be extended in the
1629
 * future. */
1630
 
1631
int mapattr(__G)
1632
    __GDEF
1633
{
1634
    /* set archive bit for file entries (file is not backed up): */
1635
    G.pInfo->file_attr = ((unsigned)G.crec.external_file_attributes |
1636
      (G.crec.external_file_attributes & FILE_ATTRIBUTE_DIRECTORY ?
1637
 
1638
    return 0;
1639
 
1640
} /* end function mapattr() */
1641
 
1642
 
1643
 
1644
 
1645
/************************/
1646
/*  Function mapname()  */
1647
/************************/
1648
 
1649
int mapname(__G__ renamed)
1650
    __GDEF
1651
    int renamed;
1652
/*
1653
 * returns:
1654
 *  MPN_OK          - no problem detected
1655
 *  MPN_INF_TRUNC   - caution (truncated filename)
1656
 *  MPN_INF_SKIP    - info "skip entry" (dir doesn't exist)
1657
 *  MPN_ERR_SKIP    - error -> skip entry
1658
 *  MPN_ERR_TOOLONG - error -> path is too long
1659
 *  MPN_NOMEM       - error (memory allocation failed) -> skip entry
1660
 *  [also MPN_VOL_LABEL, MPN_CREATED_DIR]
1661
 */
1662
{
1663
    char pathcomp[FILNAMSIZ];   /* path-component buffer */
1664
    char *pp, *cp=NULL;         /* character pointers */
1665
    char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
1666
#ifdef ACORN_FTYPE_NFS
1667
    char *lastcomma=(char *)NULL;  /* pointer to last comma in pathcomp */
1668
    RO_extra_block *ef_spark;      /* pointer Acorn FTYPE ef block */
1669
#endif
1670
    int killed_ddot = FALSE;    /* is set when skipping "../" pathcomp */
1671
    int error;
1672
    register unsigned workch;   /* hold the character being tested */
1673
 
1674
 
1675
/*---------------------------------------------------------------------------
1676
    Initialize various pointers and counters and stuff.
1677
  ---------------------------------------------------------------------------*/
1678
 
1679
    /* can create path as long as not just freshening, or if user told us */
1680
    G.create_dirs = (!uO.fflag || renamed);
1681
 
1682
    G.created_dir = FALSE;      /* not yet */
1683
    G.renamed_fullpath = FALSE;
1684
    G.fnlen = strlen(G.filename);
1685
 
1686
    if (renamed) {
1687
        cp = G.filename;    /* point to beginning of renamed name... */
1688
        if (*cp) do {
1689
            if (*cp == '\\')    /* convert backslashes to forward */
1690
                *cp = '/';
1691
        } while (*PREINCSTR(cp));
1692
        cp = G.filename;
1693
        /* use temporary rootpath if user gave full pathname */
1694
        if (G.filename[0] == '/') {
1695
            G.renamed_fullpath = TRUE;
1696
            pathcomp[0] = '/';  /* copy the '/' and terminate */
1697
            pathcomp[1] = '\0';
1698
            ++cp;
1699
        } else if (isalpha((uch)G.filename[0]) && G.filename[1] == ':') {
1700
            G.renamed_fullpath = TRUE;
1701
            pp = pathcomp;
1702
            *pp++ = *cp++;      /* copy the "d:" (+ '/', possibly) */
1703
            *pp++ = *cp++;
1704
            if (*cp == '/')
1705
                *pp++ = *cp++;  /* otherwise add "./"? */
1706
            *pp = '\0';
1707
        }
1708
    }
1709
 
1710
    /* pathcomp is ignored unless renamed_fullpath is TRUE: */
1711
    if ((error = checkdir(__G__ pathcomp, INIT)) != 0)    /* init path buffer */
1712
        return error;           /* ...unless no mem or vol label on hard disk */
1713
 
1714
    *pathcomp = '\0';           /* initialize translation buffer */
1715
    pp = pathcomp;              /* point to translation buffer */
1716
    if (!renamed) {             /* cp already set if renamed */
1717
        if (uO.jflag)           /* junking directories */
1718
            cp = (char *)MBSRCHR(G.filename, '/');
1719
        if (cp == NULL)         /* no '/' or not junking dirs */
1720
            cp = G.filename;    /* point to internal zipfile-member pathname */
1721
        else
1722
            ++cp;               /* point to start of last component of path */
1723
    }
1724
 
1725
/*---------------------------------------------------------------------------
1726
    Begin main loop through characters in filename.
1727
  ---------------------------------------------------------------------------*/
1728
 
1729
    for (; (workch = (uch)*cp) != 0; INCSTR(cp)) {
1730
 
1731
        switch (workch) {
1732
            case '/':             /* can assume -j flag not given */
1733
                *pp = '\0';
1734
                maskDOSdevice(__G__ pathcomp);
1735
                if (strcmp(pathcomp, ".") == 0) {
1736
                    /* don't bother appending "./" to the path */
1737
                    *pathcomp = '\0';
1738
                } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
1739
                    /* "../" dir traversal detected, skip over it */
1740
                    *pathcomp = '\0';
1741
                    killed_ddot = TRUE;     /* set "show message" flag */
1742
                }
1743
                /* when path component is not empty, append it now */
1744
                if (*pathcomp != '\0' &&
1745
                    ((error = checkdir(__G__ pathcomp, APPEND_DIR))
1746
                     & MPN_MASK) > MPN_INF_TRUNC)
1747
                    return error;
1748
                pp = pathcomp;    /* reset conversion buffer for next piece */
1749
                lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
1750
                break;
1751
 
1752
            case ':':             /* drive spec not stored, so no colon allowed */
1753
            case '\\':            /* '\\' may come as normal filename char (not */
1754
            case '<':             /*  dir sep char!) from unix-like file system */
1755
            case '>':             /* no redirection symbols allowed either */
1756
            case '|':             /* no pipe signs allowed */
1757
            case '"':             /* no double quotes allowed */
1758
            case '?':             /* no wildcards allowed */
1759
            case '*':
1760
                *pp++ = '_';      /* these rules apply equally to FAT and NTFS */
1761
                break;
1762
            case ';':             /* start of VMS version? */
1763
                lastsemi = pp;    /* remove VMS version later... */
1764
                *pp++ = ';';      /*  but keep semicolon for now */
1765
                break;
1766
 
1767
#ifdef ACORN_FTYPE_NFS
1768
            case ',':             /* NFS filetype extension */
1769
                lastcomma = pp;
1770
                *pp++ = ',';      /* keep for now; may need to remove */
1771
                break;            /*  later, if requested */
1772
#endif
1773
 
1774
            case ' ':             /* keep spaces unless specifically */
1775
                /* NT cannot create filenames with spaces on FAT volumes */
1776
                if (uO.sflag || IsVolumeOldFAT(__G__ G.filename))
1777
                    *pp++ = '_';
1778
                else
1779
                    *pp++ = ' ';
1780
                break;
1781
 
1782
            default:
1783
                /* allow European characters in filenames: */
1784
                if (isprint(workch) || workch >= 127)
1785
#ifdef _MBCS
1786
                {
1787
                    memcpy(pp, cp, CLEN(cp));
1788
                    INCSTR(pp);
1789
                }
1790
#else
1791
                    *pp++ = (char)workch;
1792
#endif
1793
        } /* end switch */
1794
 
1795
    } /* end while loop */
1796
 
1797
    /* Show warning when stripping insecure "parent dir" path components */
1798
    if (killed_ddot && QCOND2) {
1799
        Info(slide, 0, ((char *)slide,
1800
          "warning:  skipped \"../\" path component(s) in %s\n",
1801
          FnFilter1(G.filename)));
1802
        if (!(error & ~MPN_MASK))
1803
            error = (error & MPN_MASK) | PK_WARN;
1804
    }
1805
 
1806
/*---------------------------------------------------------------------------
1807
    Report if directory was created (and no file to create:  filename ended
1808
    in '/'), check name to be sure it exists, and combine path and name be-
1809
    fore exiting.
1810
  ---------------------------------------------------------------------------*/
1811
 
1812
    if (lastchar(G.filename, G.fnlen) == '/') {
1813
#ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
1814
        char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
1815
 
1816
        INTERN_TO_ISO(G.filename, ansi_name);
1817
#       define Ansi_Fname  ansi_name
1818
#else
1819
#       define Ansi_Fname  G.filename
1820
#endif
1821
        checkdir(__G__ G.filename, GETPATH);
1822
        if (G.created_dir) {
1823
            if (QCOND2) {
1824
                Info(slide, 0, ((char *)slide, "   creating: %-22s\n",
1825
                  FnFilter1(G.filename)));
1826
            }
1827
 
1828
            /* set file attributes:
1829
               The default for newly created directories is "DIR attribute
1830
               flags set", so there is no need to change attributes unless
1831
               one of the DOS style attribute flags is set. The readonly
1832
               attribute need not be masked, since it does not prevent
1833
               modifications in the new directory. */
1834
            if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
1835
                if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
1836
                    Info(slide, 1, ((char *)slide,
1837
                      "\nwarning (%d): could not set file attributes for %s\n",
1838
                      (int)GetLastError(), FnFilter1(G.filename)));
1839
            }
1840
 
1841
            /* set dir time (note trailing '/') */
1842
            return (error & ~MPN_MASK) | MPN_CREATED_DIR;
1843
        } else if (IS_OVERWRT_ALL) {
1844
            /* overwrite attributes of existing directory on user's request */
1845
 
1846
            /* set file attributes: */
1847
            if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
1848
                if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
1849
                    Info(slide, 1, ((char *)slide,
1850
                      "\nwarning (%d): could not set file attributes for %s\n",
1851
                      (int)GetLastError(), FnFilter1(G.filename)));
1852
            }
1853
        }
1854
        /* dir existed already; don't look for data to extract */
1855
        return (error & ~MPN_MASK) | MPN_INF_SKIP;
1856
    }
1857
 
1858
    *pp = '\0';                   /* done with pathcomp:  terminate it */
1859
 
1860
    /* if not saving them, remove VMS version numbers (appended "###") */
1861
    if (!uO.V_flag && lastsemi) {
1862
        pp = lastsemi + 1;        /* semi-colon was kept:  expect #'s after */
1863
        while (isdigit((uch)(*pp)))
1864
            ++pp;
1865
        if (*pp == '\0')          /* only digits between ';' and end:  nuke */
1866
            *lastsemi = '\0';
1867
    }
1868
 
1869
#ifdef ACORN_FTYPE_NFS
1870
    /* translate Acorn filetype information if asked to do so */
1871
    if (uO.acorn_nfs_ext &&
1872
        (ef_spark = (RO_extra_block *)
1873
                    getRISCOSexfield(G.extra_field, G.lrec.extra_field_length))
1874
        != (RO_extra_block *)NULL)
1875
    {
1876
        /* file *must* have a RISC OS extra field */
1877
        long ft = (long)makelong(ef_spark->loadaddr);
1878
        /*32-bit*/
1879
        if (lastcomma) {
1880
            pp = lastcomma + 1;
1881
            while (isxdigit((uch)(*pp))) ++pp;
1882
            if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */
1883
        }
1884
        if ((ft & 1<<31)==0) ft=0x000FFD00;
1885
        sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF);
1886
    }
1887
#endif /* ACORN_FTYPE_NFS */
1888
 
1889
    maskDOSdevice(__G__ pathcomp);
1890
 
1891
    if (*pathcomp == '\0') {
1892
        Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
1893
          FnFilter1(G.filename)));
1894
        return (error & ~MPN_MASK) | MPN_ERR_SKIP;
1895
    }
1896
 
1897
    checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
1898
    checkdir(__G__ G.filename, GETPATH);
1899
 
1900
    if (G.pInfo->vollabel) {    /* set the volume label now */
1901
        char drive[4];
1902
#ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
1903
        char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
1904
        INTERN_TO_ISO(G.filename, ansi_name);
1905
#       define Ansi_Fname  ansi_name
1906
#else
1907
#       define Ansi_Fname  G.filename
1908
#endif
1909
 
1910
        /* Build a drive string, e.g. "b:" */
1911
        drive[0] = (char)('a' + G.nLabelDrive - 1);
1912
        strcpy(drive + 1, ":\\");
1913
        if (QCOND2)
1914
            Info(slide, 0, ((char *)slide, "labelling %s %-22s\n", drive,
1915
              FnFilter1(G.filename)));
1916
        if (!SetVolumeLabelA(drive, Ansi_Fname)) {
1917
            Info(slide, 1, ((char *)slide,
1918
              "mapname:  error setting volume label\n"));
1919
            return (error & ~MPN_MASK) | MPN_ERR_SKIP;
1920
        }
1921
        /* success:  skip the "extraction" quietly */
1922
        return (error & ~MPN_MASK) | MPN_INF_SKIP;
1923
#undef Ansi_Fname
1924
    }
1925
 
1926
    Trace((stderr, "mapname returns with filename = [%s] (error = %d)\n\n",
1927
      FnFilter1(G.filename), error));
1928
    return error;
1929
 
1930
} /* end function mapname() */
1931
 
1932
 
1933
 
1934
 
1935
/****************************/
1936
/* Function maskDOSdevice() */
1937
/****************************/
1938
 
1939
static void maskDOSdevice(__G__ pathcomp)
1940
    __GDEF
1941
    char *pathcomp;
1942
{
1943
/*---------------------------------------------------------------------------
1944
    Put an underscore in front of the file name if the file name is a
1945
    DOS/WINDOWS device name like CON.*, AUX.*, PRN.*, etc. Trying to
1946
    extract such a file would fail at best and wedge us at worst.
1947
  ---------------------------------------------------------------------------*/
1948
#if !defined(S_IFCHR) && defined(_S_IFCHR)
1949
#  define S_IFCHR _S_IFCHR
1950
#endif
1951
#if !defined(S_ISCHR)
1952
# if defined(_S_ISCHR)
1953
#  define S_ISCHR(m) _S_ISCHR(m)
1954
# elif defined(S_IFCHR)
1955
#  define S_ISCHR(m) ((m) & S_IFCHR)
1956
# endif
1957
#endif
1958
 
1959
#ifdef DEBUG
1960
    if (zstat(pathcomp, &G.statbuf) == 0) {
1961
        Trace((stderr,
1962
               "maskDOSdevice() stat(\"%s\", buf) st_mode result: %X, %o\n",
1963
               FnFilter1(pathcomp), G.statbuf.st_mode, G.statbuf.st_mode));
1964
    } else {
1965
        Trace((stderr, "maskDOSdevice() stat(\"%s\", buf) failed\n",
1966
               FnFilter1(pathcomp)));
1967
    }
1968
#endif
1969
    if (zstat(pathcomp, &G.statbuf) == 0 && S_ISCHR(G.statbuf.st_mode)) {
1970
        extent i;
1971
 
1972
        /* pathcomp contains a name of a DOS character device (builtin or
1973
         * installed device driver).
1974
         * Prepend a '_' to allow creation of the item in the file system.
1975
         */
1976
        for (i = strlen(pathcomp) + 1; i > 0; --i)
1977
            pathcomp[i] = pathcomp[i - 1];
1978
        pathcomp[0] = '_';
1979
    }
1980
} /* end function maskDOSdevice() */
1981
 
1982
 
1983
 
1984
 
1985
 
1986
/**********************/
1987
/* Function map2fat() */        /* Not quite identical to OS/2 version */
1988
/**********************/
1989
 
1990
static void map2fat(pathcomp, pEndFAT)
1991
    char *pathcomp, **pEndFAT;
1992
{
1993
    char *ppc = pathcomp;       /* variable pointer to pathcomp */
1994
    char *pEnd = *pEndFAT;      /* variable pointer to buildpathFAT */
1995
    char *pBegin = *pEndFAT;    /* constant pointer to start of this comp. */
1996
    char *last_dot = NULL;      /* last dot not converted to underscore */
1997
    register unsigned workch;   /* hold the character being tested */
1998
 
1999
 
2000
    /* Only need check those characters which are legal in NTFS but not
2001
     * in FAT:  to get here, must already have passed through mapname.
2002
     * Also must truncate path component to ensure 8.3 compliance.
2003
     */
2004
    while ((workch = (uch)*ppc++) != 0) {
2005
        switch (workch) {
2006
            case '[':
2007
            case ']':
2008
            case '+':
2009
            case ',':
2010
            case ';':
2011
            case '=':
2012
                *pEnd++ = '_';      /* convert brackets to underscores */
2013
                break;
2014
 
2015
            case '.':
2016
                if (pEnd == *pEndFAT) {   /* nothing appended yet... */
2017
                    if (*ppc == '\0')     /* don't bother appending a */
2018
                        break;            /*  "./" component to the path */
2019
                    else if (*ppc == '.' && ppc[1] == '\0') {   /* "../" */
2020
                        *pEnd++ = '.';    /*  add first dot, */
2021
                        *pEnd++ = '.';    /*  add second dot, and */
2022
                        ++ppc;            /*  skip over to pathcomp's end */
2023
                    } else {              /* FAT doesn't allow null filename */
2024
                        *pEnd++ = '_';    /*  bodies, so map .exrc -> _exrc */
2025
                    }                     /*  (_.exr would keep max 3 chars) */
2026
                } else {                  /* found dot within path component */
2027
                    last_dot = pEnd;      /*  point at last dot so far... */
2028
                    *pEnd++ = '_';        /*  convert to underscore for now */
2029
                }
2030
                break;
2031
 
2032
            default:
2033
                *pEnd++ = (char)workch;
2034
 
2035
        } /* end switch */
2036
    } /* end while loop */
2037
 
2038
    *pEnd = '\0';                 /* terminate buildpathFAT */
2039
 
2040
    /* NOTE:  keep in mind that pEnd points to the end of the path
2041
     * component, and *pEndFAT still points to the *beginning* of it...
2042
     * Also note that the algorithm does not try to get too fancy:
2043
     * if there are no dots already, the name either gets truncated
2044
     * at 8 characters or the last underscore is converted to a dot
2045
     * (only if more characters are saved that way).  In no case is
2046
     * a dot inserted between existing characters.
2047
     */
2048
    if (last_dot == NULL) {       /* no dots:  check for underscores... */
2049
        char *plu = MBSRCHR(pBegin, '_');   /* pointer to last underscore */
2050
 
2051
        if ((plu != NULL) &&      /* found underscore: convert to dot? */
2052
            (MIN(plu - pBegin, 8) + MIN(pEnd - plu - 1, 3) > 8)) {
2053
            last_dot = plu;       /* be lazy:  drop through to next if-blk */
2054
        } else if ((pEnd - *pEndFAT) > 8) {
2055
            /* no underscore; or converting underscore to dot would save less
2056
               chars than leaving everything in the basename */
2057
            *pEndFAT += 8;        /* truncate at 8 chars */
2058
            **pEndFAT = '\0';
2059
        } else
2060
            *pEndFAT = pEnd;      /* whole thing fits into 8 chars or less */
2061
    }
2062
 
2063
    if (last_dot != NULL) {       /* one dot is OK: */
2064
        *last_dot = '.';          /* put it back in */
2065
 
2066
        if ((last_dot - pBegin) > 8) {
2067
            char *p, *q;
2068
            int i;
2069
 
2070
            p = last_dot;
2071
            q = last_dot = pBegin + 8;
2072
            for (i = 0;  (i < 4) && *p;  ++i)  /* too many chars in basename: */
2073
                *q++ = *p++;                   /*  shift .ext left and trun- */
2074
            *q = '\0';                         /*  cate/terminate it */
2075
            *pEndFAT = q;
2076
        } else if ((pEnd - last_dot) > 4) {    /* too many chars in extension */
2077
            *pEndFAT = last_dot + 4;
2078
            **pEndFAT = '\0';
2079
        } else
2080
            *pEndFAT = pEnd;   /* filename is fine; point at terminating zero */
2081
 
2082
        if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ')
2083
            last_dot[-1] = '_';                /* NO blank in front of '.'! */
2084
    }
2085
} /* end function map2fat() */
2086
 
2087
 
2088
 
2089
 
2090
/***********************/       /* Borrowed from os2.c for UnZip 5.1.        */
2091
/* Function checkdir() */       /* Difference: no EA stuff                   */
2092
/***********************/       /*             HPFS stuff works on NTFS too  */
2093
 
2094
int checkdir(__G__ pathcomp, flag)
2095
    __GDEF
2096
    char *pathcomp;
2097
    int flag;
2098
/*
2099
 * returns:
2100
 *  MPN_OK          - no problem detected
2101
 *  MPN_INF_TRUNC   - (on APPEND_NAME) truncated filename
2102
 *  MPN_INF_SKIP    - path doesn't exist, not allowed to create
2103
 *  MPN_ERR_SKIP    - path doesn't exist, tried to create and failed; or path
2104
 *                    exists and is not a directory, but is supposed to be
2105
 *  MPN_ERR_TOOLONG - path is too long
2106
 *  MPN_NOMEM       - can't allocate memory for filename buffers
2107
 */
2108
{
2109
 /* static int rootlen = 0;     */   /* length of rootpath */
2110
 /* static char *rootpath;      */   /* user's "extract-to" directory */
2111
 /* static char *buildpathHPFS; */   /* full path (so far) to extracted file, */
2112
 /* static char *buildpathFAT;  */   /*  both HPFS/EA (main) and FAT versions */
2113
 /* static char *endHPFS;       */   /* corresponding pointers to end of */
2114
 /* static char *endFAT;        */   /*  buildpath ('\0') */
2115
 
2116
#   define FN_MASK   7
2117
#   define FUNCTION  (flag & FN_MASK)
2118
 
2119
 
2120
 
2121
/*---------------------------------------------------------------------------
2122
    APPEND_DIR:  append the path component to the path being built and check
2123
    for its existence.  If doesn't exist and we are creating directories, do
2124
    so for this one; else signal success or error as appropriate.
2125
  ---------------------------------------------------------------------------*/
2126
 
2127
    if (FUNCTION == APPEND_DIR) {
2128
        char *p = pathcomp;
2129
        int too_long = FALSE;
2130
 
2131
        Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
2132
        while ((*G.endHPFS = *p++) != '\0')     /* copy to HPFS filename */
2133
            ++G.endHPFS;
2134
        if (!IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
2135
            p = pathcomp;
2136
            while ((*G.endFAT = *p++) != '\0')  /* copy to FAT filename, too */
2137
                ++G.endFAT;
2138
        } else
2139
            map2fat(pathcomp, &G.endFAT);   /* map into FAT fn, update endFAT */
2140
 
2141
        /* GRR:  could do better check, see if overrunning buffer as we go:
2142
         * check endHPFS-buildpathHPFS after each append, set warning variable
2143
         * if within 20 of FILNAMSIZ; then if var set, do careful check when
2144
         * appending.  Clear variable when begin new path. */
2145
 
2146
        /* next check:  need to append '/', at least one-char name, '\0' */
2147
        if ((G.endHPFS-G.buildpathHPFS) > FILNAMSIZ-3)
2148
            too_long = TRUE;                    /* check if extracting dir? */
2149
#ifdef FIX_STAT_BUG
2150
        /* Borland C++ 5.0 does not handle a call to stat() well if the
2151
         * directory does not exist (it tends to crash in strange places.)
2152
         * This is apparently a problem only when compiling for GUI rather
2153
         * than console. The code below attempts to work around this problem.
2154
         */
2155
        if (access(G.buildpathFAT, 0) != 0) {
2156
            if (!G.create_dirs) { /* told not to create (freshening) */
2157
                free(G.buildpathHPFS);
2158
                free(G.buildpathFAT);
2159
                /* path doesn't exist:  nothing to do */
2160
                return MPN_INF_SKIP;
2161
            }
2162
            if (too_long) {   /* GRR:  should allow FAT extraction w/o EAs */
2163
                Info(slide, 1, ((char *)slide,
2164
                  "checkdir error:  path too long: %s\n",
2165
                  FnFilter1(G.buildpathHPFS)));
2166
                free(G.buildpathHPFS);
2167
                free(G.buildpathFAT);
2168
                /* no room for filenames:  fatal */
2169
                return MPN_ERR_TOOLONG;
2170
            }
2171
            if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
2172
                Info(slide, 1, ((char *)slide,
2173
                  "checkdir error:  cannot create %s\n\
2174
                 %s\n\
2175
                 unable to process %s.\n",
2176
                  FnFilter2(G.buildpathFAT),
2177
                  strerror(errno),
2178
                  FnFilter1(G.filename)));
2179
                free(G.buildpathHPFS);
2180
                free(G.buildpathFAT);
2181
                /* path didn't exist, tried to create, failed */
2182
                return MPN_ERR_SKIP;
2183
            }
2184
            G.created_dir = TRUE;
2185
        }
2186
#endif /* FIX_STAT_BUG */
2187
        if (SSTAT(G.buildpathFAT, &G.statbuf))   /* path doesn't exist */
2188
        {
2189
            if (!G.create_dirs) { /* told not to create (freshening) */
2190
                free(G.buildpathHPFS);
2191
                free(G.buildpathFAT);
2192
                /* path doesn't exist:  nothing to do */
2193
                return MPN_INF_SKIP;
2194
            }
2195
            if (too_long) {   /* GRR:  should allow FAT extraction w/o EAs */
2196
                Info(slide, 1, ((char *)slide,
2197
                  "checkdir error:  path too long: %s\n",
2198
                  FnFilter1(G.buildpathHPFS)));
2199
                free(G.buildpathHPFS);
2200
                free(G.buildpathFAT);
2201
                /* no room for filenames:  fatal */
2202
                return MPN_ERR_TOOLONG;
2203
            }
2204
            if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
2205
                Info(slide, 1, ((char *)slide,
2206
                  "checkdir error:  cannot create %s\n\
2207
                 %s\n\
2208
                 unable to process %s.\n",
2209
                  FnFilter2(G.buildpathFAT),
2210
                  strerror(errno),
2211
                  FnFilter1(G.filename)));
2212
                free(G.buildpathHPFS);
2213
                free(G.buildpathFAT);
2214
                /* path didn't exist, tried to create, failed */
2215
                return MPN_ERR_SKIP;
2216
            }
2217
            G.created_dir = TRUE;
2218
        } else if (!S_ISDIR(G.statbuf.st_mode)) {
2219
            Info(slide, 1, ((char *)slide,
2220
              "checkdir error:  %s exists but is not directory\n\
2221
                 unable to process %s.\n",
2222
              FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
2223
            free(G.buildpathHPFS);
2224
            free(G.buildpathFAT);
2225
            /* path existed but wasn't dir */
2226
            return MPN_ERR_SKIP;
2227
        }
2228
        if (too_long) {
2229
            Info(slide, 1, ((char *)slide,
2230
              "checkdir error:  path too long: %s\n",
2231
              FnFilter1(G.buildpathHPFS)));
2232
            free(G.buildpathHPFS);
2233
            free(G.buildpathFAT);
2234
            /* no room for filenames:  fatal */
2235
            return MPN_ERR_TOOLONG;
2236
        }
2237
        *G.endHPFS++ = '/';
2238
        *G.endFAT++ = '/';
2239
        *G.endHPFS = *G.endFAT = '\0';
2240
        Trace((stderr, "buildpathHPFS now = [%s]\nbuildpathFAT now =  [%s]\n",
2241
          FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
2242
        return MPN_OK;
2243
 
2244
    } /* end if (FUNCTION == APPEND_DIR) */
2245
 
2246
/*---------------------------------------------------------------------------
2247
    GETPATH:  copy full FAT path to the string pointed at by pathcomp (want
2248
    filename to reflect name used on disk, not EAs; if full path is HPFS,
2249
    buildpathFAT and buildpathHPFS will be identical).  Also free both paths.
2250
  ---------------------------------------------------------------------------*/
2251
 
2252
    if (FUNCTION == GETPATH) {
2253
        Trace((stderr, "getting and freeing FAT path [%s]\n",
2254
          FnFilter1(G.buildpathFAT)));
2255
        Trace((stderr, "freeing HPFS path [%s]\n",
2256
          FnFilter1(G.buildpathHPFS)));
2257
        strcpy(pathcomp, G.buildpathFAT);
2258
        free(G.buildpathFAT);
2259
        free(G.buildpathHPFS);
2260
        G.buildpathHPFS = G.buildpathFAT = G.endHPFS = G.endFAT = NULL;
2261
        return MPN_OK;
2262
    }
2263
 
2264
/*---------------------------------------------------------------------------
2265
    APPEND_NAME:  assume the path component is the filename; append it and
2266
    return without checking for existence.
2267
  ---------------------------------------------------------------------------*/
2268
 
2269
    if (FUNCTION == APPEND_NAME) {
2270
        char *p = pathcomp;
2271
        int error = MPN_OK;
2272
 
2273
        Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
2274
        /* The buildpathHPFS buffer has been allocated large enough to
2275
         * hold the complete combined name, so there is no need to check
2276
         * for OS filename size limit overflow within the copy loop.
2277
         */
2278
        while ((*G.endHPFS = *p++) != '\0') {   /* copy to HPFS filename */
2279
            ++G.endHPFS;
2280
        }
2281
        /* Now, check for OS filename size overflow.  When detected, the
2282
         * mapped HPFS name is truncated and a warning message is shown.
2283
         */
2284
        if ((G.endHPFS-G.buildpathHPFS) >= FILNAMSIZ) {
2285
            G.buildpathHPFS[FILNAMSIZ-1] = '\0';
2286
            Info(slide, 1, ((char *)slide,
2287
              "checkdir warning:  path too long; truncating\n \
2288
              %s\n                -> %s\n",
2289
              FnFilter1(G.filename), FnFilter2(G.buildpathHPFS)));
2290
            error = MPN_INF_TRUNC;  /* filename truncated */
2291
        }
2292
 
2293
        /* The buildpathFAT buffer has the same allocated size as the
2294
         * buildpathHPFS buffer, so there is no need for an overflow check
2295
         * within the following copy loop, either.
2296
         */
2297
        if (G.pInfo->vollabel || !IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
2298
            /* copy to FAT filename, too */
2299
            p = pathcomp;
2300
            while ((*G.endFAT = *p++) != '\0')
2301
                ++G.endFAT;
2302
        } else
2303
            /* map into FAT fn, update endFAT */
2304
            map2fat(pathcomp, &G.endFAT);
2305
 
2306
        /* Check that the FAT path does not exceed the FILNAMSIZ limit, and
2307
         * truncate when neccessary.
2308
         * Note that truncation can only happen when the HPFS path (which is
2309
         * never shorter than the FAT path) has been already truncated.
2310
         * So, emission of the warning message and setting the error code
2311
         * has already happened.
2312
         */
2313
        if ((G.endFAT-G.buildpathFAT) >= FILNAMSIZ)
2314
            G.buildpathFAT[FILNAMSIZ-1] = '\0';
2315
        Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT:  %s\n",
2316
          FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
2317
 
2318
        return error;  /* could check for existence, prompt for new name... */
2319
 
2320
    } /* end if (FUNCTION == APPEND_NAME) */
2321
 
2322
/*---------------------------------------------------------------------------
2323
    INIT:  allocate and initialize buffer space for the file currently being
2324
    extracted.  If file was renamed with an absolute path, don't prepend the
2325
    extract-to path.
2326
  ---------------------------------------------------------------------------*/
2327
 
2328
    if (FUNCTION == INIT) {
2329
        Trace((stderr, "initializing buildpathHPFS and buildpathFAT to "));
2330
#ifdef ACORN_FTYPE_NFS
2331
        if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+
2332
                                              (uO.acorn_nfs_ext ? 5 : 1)))
2333
#else
2334
        if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+1))
2335
#endif
2336
            == NULL)
2337
            return MPN_NOMEM;
2338
#ifdef ACORN_FTYPE_NFS
2339
        if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+
2340
                                             (uO.acorn_nfs_ext ? 5 : 1)))
2341
#else
2342
        if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+1))
2343
#endif
2344
            == NULL) {
2345
            free(G.buildpathHPFS);
2346
            return MPN_NOMEM;
2347
        }
2348
        if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */
2349
/* GRR:  for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
2350
            if (G.renamed_fullpath && pathcomp[1] == ':')
2351
                *G.buildpathHPFS = (char)ToLower(*pathcomp);
2352
            else if (!G.renamed_fullpath && G.rootlen > 1 &&
2353
                     G.rootpath[1] == ':')
2354
                *G.buildpathHPFS = (char)ToLower(*G.rootpath);
2355
            else {
2356
                char tmpN[MAX_PATH], *tmpP;
2357
                if (GetFullPathNameA(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH)
2358
                { /* by definition of MAX_PATH we should never get here */
2359
                    Info(slide, 1, ((char *)slide,
2360
                      "checkdir warning: current dir path too long\n"));
2361
                    return MPN_INF_TRUNC;   /* can't get drive letter */
2362
                }
2363
                G.nLabelDrive = *tmpN - 'a' + 1;
2364
                *G.buildpathHPFS = (char)(G.nLabelDrive - 1 + 'a');
2365
            }
2366
            G.nLabelDrive = *G.buildpathHPFS - 'a' + 1; /* save for mapname() */
2367
            if (uO.volflag == 0 || *G.buildpathHPFS < 'a' /* no labels/bogus? */
2368
                || (uO.volflag == 1 && !isfloppy(G.nLabelDrive))) { /* !fixed */
2369
                free(G.buildpathHPFS);
2370
                free(G.buildpathFAT);
2371
                return MPN_VOL_LABEL;  /* skipping with message */
2372
            }
2373
            *G.buildpathHPFS = '\0';
2374
        } else if (G.renamed_fullpath) /* pathcomp = valid data */
2375
            strcpy(G.buildpathHPFS, pathcomp);
2376
        else if (G.rootlen > 0)
2377
            strcpy(G.buildpathHPFS, G.rootpath);
2378
        else
2379
            *G.buildpathHPFS = '\0';
2380
        G.endHPFS = G.buildpathHPFS;
2381
        G.endFAT = G.buildpathFAT;
2382
        while ((*G.endFAT = *G.endHPFS) != '\0') {
2383
            ++G.endFAT;
2384
            ++G.endHPFS;
2385
        }
2386
        Trace((stderr, "[%s]\n", FnFilter1(G.buildpathHPFS)));
2387
        return MPN_OK;
2388
    }
2389
 
2390
/*---------------------------------------------------------------------------
2391
    ROOT:  if appropriate, store the path in rootpath and create it if neces-
2392
    sary; else assume it's a zipfile member and return.  This path segment
2393
    gets used in extracting all members from every zipfile specified on the
2394
    command line.  Note that under OS/2 and MS-DOS, if a candidate extract-to
2395
    directory specification includes a drive letter (leading "x:"), it is
2396
    treated just as if it had a trailing '/'--that is, one directory level
2397
    will be created if the path doesn't exist, unless this is otherwise pro-
2398
    hibited (e.g., freshening).
2399
  ---------------------------------------------------------------------------*/
2400
 
2401
#if (!defined(SFX) || defined(SFX_EXDIR))
2402
    if (FUNCTION == ROOT) {
2403
        Trace((stderr, "initializing root path to [%s]\n",
2404
          FnFilter1(pathcomp)));
2405
        if (pathcomp == NULL) {
2406
            G.rootlen = 0;
2407
            return MPN_OK;
2408
        }
2409
        if (G.rootlen > 0)      /* rootpath was already set, nothing to do */
2410
            return MPN_OK;
2411
        if ((G.rootlen = strlen(pathcomp)) > 0) {
2412
            int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE;
2413
            char *tmproot;
2414
 
2415
            if ((tmproot = (char *)malloc(G.rootlen+3)) == (char *)NULL) {
2416
                G.rootlen = 0;
2417
                return MPN_NOMEM;
2418
            }
2419
            strcpy(tmproot, pathcomp);
2420
            if (isalpha((uch)tmproot[0]) && tmproot[1] == ':')
2421
                has_drive = TRUE;   /* drive designator */
2422
            if (tmproot[G.rootlen-1] == '/' || tmproot[G.rootlen-1] == '\\') {
2423
                tmproot[--G.rootlen] = '\0';
2424
                had_trailing_pathsep = TRUE;
2425
            }
2426
            if (has_drive && (G.rootlen == 2)) {
2427
                if (!had_trailing_pathsep)   /* i.e., original wasn't "x:/" */
2428
                    add_dot = TRUE;    /* relative path: add '.' before '/' */
2429
            } else if (G.rootlen > 0) {   /* need not check "x:." and "x:/" */
2430
                if (SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
2431
                {
2432
                    /* path does not exist */
2433
                    if (!G.create_dirs /* || iswild(tmproot) */ ) {
2434
                        free(tmproot);
2435
                        G.rootlen = 0;
2436
                        /* treat as stored file */
2437
                        return MPN_INF_SKIP;
2438
                    }
2439
                    /* create directory (could add loop here scanning tmproot
2440
                     * to create more than one level, but really necessary?) */
2441
                    if (MKDIR(tmproot, 0777) == -1) {
2442
                        Info(slide, 1, ((char *)slide,
2443
                          "checkdir:  cannot create extraction directory: %s\n",
2444
                          FnFilter1(tmproot)));
2445
                        free(tmproot);
2446
                        G.rootlen = 0;
2447
                        /* path didn't exist, tried to create, failed: */
2448
                        /* file exists, or need 2+ subdir levels */
2449
                        return MPN_ERR_SKIP;
2450
                    }
2451
                }
2452
            }
2453
            if (add_dot)                    /* had just "x:", make "x:." */
2454
                tmproot[G.rootlen++] = '.';
2455
            tmproot[G.rootlen++] = '/';
2456
            tmproot[G.rootlen] = '\0';
2457
            if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
2458
                free(tmproot);
2459
                G.rootlen = 0;
2460
                return MPN_NOMEM;
2461
            }
2462
            Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
2463
        }
2464
        return MPN_OK;
2465
    }
2466
#endif /* !SFX || SFX_EXDIR */
2467
 
2468
/*---------------------------------------------------------------------------
2469
    END:  free rootpath, immediately prior to program exit.
2470
  ---------------------------------------------------------------------------*/
2471
 
2472
    if (FUNCTION == END) {
2473
        Trace((stderr, "freeing rootpath\n"));
2474
        if (G.rootlen > 0) {
2475
            free(G.rootpath);
2476
            G.rootlen = 0;
2477
        }
2478
        return MPN_OK;
2479
    }
2480
 
2481
    return MPN_INVALID; /* should never reach */
2482
 
2483
} /* end function checkdir() */
2484
 
2485
 
2486
 
2487
 
2488
 
2489
#ifndef SFX
2490
 
2491
/*************************/
2492
/* Function dateformat() */
2493
/*************************/
2494
 
2495
int dateformat()
2496
{
2497
  char df[2];   /* LOCALE_IDATE has a maximum value of 2 */
2498
 
2499
  if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDATE, df, 2) != 0) {
2500
    switch (df[0])
2501
    {
2502
      case '0':
2503
        return DF_MDY;
2504
      case '1':
2505
        return DF_DMY;
2506
      case '2':
2507
        return DF_YMD;
2508
    }
2509
  }
2510
  return DF_MDY;
2511
}
2512
 
2513
 
2514
/****************************/
2515
/* Function dateseparator() */
2516
/****************************/
2517
 
2518
char dateseparator()
2519
{
2520
  char df[2];   /* use only if it is one character */
2521
 
2522
  if ((GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDATE, df, 2) != 0) &&
2523
      (df[0] != '\0'))
2524
    return df[0];
2525
  else
2526
    return '-';
2527
}
2528
 
2529
 
2530
#ifndef WINDLL
2531
 
2532
/************************/
2533
/*  Function version()  */
2534
/************************/
2535
 
2536
void version(__G)
2537
    __GDEF
2538
{
2539
    int len;
2540
#if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DJGPP__))
2541
    char buf[80];
2542
#if (defined(_MSC_VER) && (_MSC_VER > 900))
2543
    char buf2[80];
2544
#endif
2545
#endif
2546
 
2547
    len = sprintf((char *)slide, CompiledWith,
2548
 
2549
#if defined(_MSC_VER)  /* MSC == VC++, but what about SDK compiler? */
2550
      (sprintf(buf, "Microsoft C %d.%02d ", _MSC_VER/100, _MSC_VER%100), buf),
2551
#  if (_MSC_VER == 800)
2552
      "(Visual C++ v1.1)",
2553
#  elif (_MSC_VER == 850)
2554
      "(Windows NT v3.5 SDK)",
2555
#  elif (_MSC_VER == 900)
2556
      "(Visual C++ v2.x)",
2557
#  elif (_MSC_VER > 900)
2558
      (sprintf(buf2, "(Visual C++ %d.%d)", _MSC_VER/100 - 6, _MSC_VER%100/10),
2559
        buf2),
2560
#  else
2561
      "(bad version)",
2562
#  endif
2563
#elif defined(__WATCOMC__)
2564
#  if (__WATCOMC__ % 10 > 0)
2565
      (sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
2566
       __WATCOMC__ % 100), buf), "",
2567
#  else
2568
      (sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
2569
       (__WATCOMC__ % 100) / 10), buf), "",
2570
#  endif
2571
#elif defined(__BORLANDC__)
2572
      "Borland C++",
2573
#  if (__BORLANDC__ < 0x0200)
2574
      " 1.0",
2575
#  elif (__BORLANDC__ == 0x0200)
2576
      " 2.0",
2577
#  elif (__BORLANDC__ == 0x0400)
2578
      " 3.0",
2579
#  elif (__BORLANDC__ == 0x0410)   /* __TURBOC__ = 0x0310 */
2580
      " 3.1",
2581
#  elif (__BORLANDC__ == 0x0452)   /* __TURBOC__ = 0x0320 */
2582
      " 4.0 or 4.02",
2583
#  elif (__BORLANDC__ == 0x0460)   /* __TURBOC__ = 0x0340 */
2584
      " 4.5",
2585
#  elif (__BORLANDC__ == 0x0500)   /* __TURBOC__ = 0x0340 */
2586
      " 5.0",
2587
#  elif (__BORLANDC__ == 0x0520)   /* __TURBOC__ = 0x0520 */
2588
      " 5.2 (C++ Builder 1.0)",
2589
#  elif (__BORLANDC__ == 0x0530)   /* __TURBOC__ = 0x0530 */
2590
      " 5.3 (C++ Builder 3.0)",
2591
#  elif (__BORLANDC__ == 0x0540)   /* __TURBOC__ = 0x0540 */
2592
      " 5.4 (C++ Builder 4.0)",
2593
#  elif (__BORLANDC__ == 0x0550)   /* __TURBOC__ = 0x0550 */
2594
      " 5.5 (C++ Builder 5.0)",
2595
#  elif (__BORLANDC__ == 0x0551)   /* __TURBOC__ = 0x0551 */
2596
      " 5.5.1 (C++ Builder 5.0.1)",
2597
#  elif (__BORLANDC__ == 0x0560)   /* __TURBOC__ = 0x0560 */
2598
      " 6.0 (C++ Builder 6.0)",
2599
#  else
2600
      " later than 6.0",
2601
#  endif
2602
#elif defined(__LCC__)
2603
      "LCC-Win32", "",
2604
#elif defined(__GNUC__)
2605
#  if defined(__RSXNT__)
2606
#    if (defined(__DJGPP__) && !defined(__EMX__))
2607
      (sprintf(buf, "rsxnt(djgpp v%d.%02d) / gcc ",
2608
        __DJGPP__, __DJGPP_MINOR__), buf),
2609
#    elif defined(__DJGPP__)
2610
      (sprintf(buf, "rsxnt(emx+djgpp v%d.%02d) / gcc ",
2611
        __DJGPP__, __DJGPP_MINOR__), buf),
2612
#    elif (defined(__GO32__) && !defined(__EMX__))
2613
      "rsxnt(djgpp v1.x) / gcc ",
2614
#    elif defined(__GO32__)
2615
      "rsxnt(emx + djgpp v1.x) / gcc ",
2616
#    elif defined(__EMX__)
2617
      "rsxnt(emx)+gcc ",
2618
#    else
2619
      "rsxnt(unknown) / gcc ",
2620
#    endif
2621
#  elif defined(__CYGWIN__)
2622
      "cygnus win32 / gcc ",
2623
#  elif defined(__MINGW32__)
2624
      "mingw32 / gcc ",
2625
#  else
2626
      "gcc ",
2627
#  endif
2628
      __VERSION__,
2629
#else /* !_MSC_VER, !__WATCOMC__, !__BORLANDC__, !__LCC__, !__GNUC__ */
2630
      "unknown compiler (SDK?)", "",
2631
#endif /* ?compilers */
2632
 
2633
      "\nWindows 9x / Windows NT/2K/XP/2K3", " (32-bit)",
2634
 
2635
#ifdef __DATE__
2636
      " on ", __DATE__
2637
#else
2638
      "", ""
2639
#endif
2640
    );
2641
 
2642
    (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
2643
 
2644
    return;
2645
 
2646
} /* end function version() */
2647
 
2648
#endif /* !WINDLL */
2649
#endif /* !SFX */
2650
 
2651
 
2652
 
2653
#ifdef MORE
2654
 
2655
int screensize(int *tt_rows, int *tt_cols)
2656
{
2657
    HANDLE hstdout;
2658
    CONSOLE_SCREEN_BUFFER_INFO scr;
2659
 
2660
    hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
2661
    GetConsoleScreenBufferInfo(hstdout, &scr);
2662
    if (tt_rows != NULL) *tt_rows = scr.srWindow.Bottom - scr.srWindow.Top + 1;
2663
    if (tt_cols != NULL) *tt_cols = scr.srWindow.Right - scr.srWindow.Left + 1;
2664
    return 0;           /* signal success */
2665
}
2666
 
2667
#endif /* MORE */
2668
 
2669
 
2670
 
2671
#ifdef W32_STAT_BANDAID
2672
 
2673
/* All currently known variants of WIN32 operating systems (Windows 95/98,
2674
 * WinNT 3.x, 4.0, 5.x) have a nasty bug in the OS kernel concerning
2675
 * conversions between UTC and local time: In the time conversion functions
2676
 * of the Win32 API, the timezone offset (including seasonal daylight saving
2677
 * shift) between UTC and local time evaluation is erratically based on the
2678
 * current system time. The correct evaluation must determine the offset
2679
 * value as it {was/is/will be} for the actual time to be converted.
2680
 *
2681
 * Newer versions of MS C runtime lib's stat() returns utc time-stamps so
2682
 * that localtime(timestamp) corresponds to the (potentially false) local
2683
 * time shown by the OS' system programs (Explorer, command shell dir, etc.)
2684
 * The RSXNT port follows the same strategy, but fails to recognize the
2685
 * access-time attribute.
2686
 *
2687
 * For the NTFS file system (and other filesystems that store time-stamps
2688
 * as UTC values), this results in st_mtime (, st_{c|a}time) fields which
2689
 * are not stable but vary according to the seasonal change of "daylight
2690
 * saving time in effect / not in effect".
2691
 *
2692
 * Other C runtime libs (CygWin), or the crtdll.dll supplied with Win9x/NT
2693
 * return the unix-time equivalent of the UTC FILETIME values as got back
2694
 * from the Win32 API call. This time, return values from NTFS are correct
2695
 * whereas utimes from files on (V)FAT volumes vary according to the DST
2696
 * switches.
2697
 *
2698
 * To achieve timestamp consistency of UTC (UT extra field) values in
2699
 * Zip archives, the Info-ZIP programs require work-around code for
2700
 * proper time handling in stat() (and other time handling routines).
2701
 *
2702
 * However, nowadays most other programs on Windows systems use the
2703
 * time conversion strategy of Microsofts C runtime lib "msvcrt.dll".
2704
 * To improve interoperability in environments where a "consistent" (but
2705
 * false) "UTC<-->LocalTime" conversion is preferred over "stable" time
2706
 * stamps, the Info-ZIP specific time conversion handling can be
2707
 * deactivated by defining the preprocessor flag NO_W32TIMES_IZFIX.
2708
 */
2709
/* stat() functions under Windows95 tend to fail for root directories.   *
2710
 * Watcom and Borland, at least, are affected by this bug.  Watcom made  *
2711
 * a partial fix for 11.0 but still missed some cases.  This substitute  *
2712
 * detects the case and fills in reasonable values.  Otherwise we get    *
2713
 * effects like failure to extract to a root dir because it's not found. */
2714
 
2715
int zstat_win32(__W32STAT_GLOBALS__ const char *path, z_stat *buf)
2716
{
2717
    if (!zstat(path, buf))
2718
    {
2719
        /* stat was successful, now redo the time-stamp fetches */
2720
#ifndef NO_W32TIMES_IZFIX
2721
        int fs_uses_loctime = FStampIsLocTime(__G__ path);
2722
#endif
2723
        HANDLE h;
2724
        FILETIME Modft, Accft, Creft;
2725
#ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
2726
        char *ansi_path = (char *)alloca(strlen(path) + 1);
2727
 
2728
        INTERN_TO_ISO(path, ansi_path);
2729
#       define Ansi_Path  ansi_path
2730
#else
2731
#       define Ansi_Path  path
2732
#endif
2733
 
2734
        TTrace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime));
2735
        h = CreateFileA(Ansi_Path, GENERIC_READ,
2736
                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2737
                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2738
        if (h != INVALID_HANDLE_VALUE) {
2739
            BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
2740
            CloseHandle(h);
2741
 
2742
            if (ftOK) {
2743
                FTTrace((stdout, "GetFileTime returned Modft", 0, &Modft));
2744
                FTTrace((stdout, "GetFileTime returned Creft", 0, &Creft));
2745
#ifndef NO_W32TIMES_IZFIX
2746
                if (!fs_uses_loctime) {
2747
                    /*  On a filesystem that stores UTC timestamps, we refill
2748
                     *  the time fields of the struct stat buffer by directly
2749
                     *  using the UTC values as returned by the Win32
2750
                     *  GetFileTime() API call.
2751
                     */
2752
                    NtfsFileTime2utime(&Modft, &(buf->st_mtime));
2753
                    if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
2754
                        NtfsFileTime2utime(&Accft, &(buf->st_atime));
2755
                    else
2756
                        buf->st_atime = buf->st_mtime;
2757
                    if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
2758
                        NtfsFileTime2utime(&Creft, &(buf->st_ctime));
2759
                    else
2760
                        buf->st_ctime = buf->st_mtime;
2761
                    TTrace((stdout,"NTFS, recalculated modtime %08lx\n",
2762
                            buf->st_mtime));
2763
                } else
2764
#endif /* NO_W32TIMES_IZFIX */
2765
                {
2766
                    /*  On VFAT and FAT-like filesystems, the FILETIME values
2767
                     *  are converted back to the stable local time before
2768
                     *  converting them to UTC unix time-stamps.
2769
                     */
2770
                    VFatFileTime2utime(&Modft, &(buf->st_mtime));
2771
                    if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
2772
                        VFatFileTime2utime(&Accft, &(buf->st_atime));
2773
                    else
2774
                        buf->st_atime = buf->st_mtime;
2775
                    if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
2776
                        VFatFileTime2utime(&Creft, &(buf->st_ctime));
2777
                    else
2778
                        buf->st_ctime = buf->st_mtime;
2779
                    TTrace((stdout, "VFAT, recalculated modtime %08lx\n",
2780
                            buf->st_mtime));
2781
                }
2782
            }
2783
        }
2784
#       undef Ansi_Path
2785
        return 0;
2786
    }
2787
#ifdef W32_STATROOT_FIX
2788
    else
2789
    {
2790
        DWORD flags;
2791
#ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
2792
        char *ansi_path = (char *)alloca(strlen(path) + 1);
2793
 
2794
        INTERN_TO_ISO(path, ansi_path);
2795
#       define Ansi_Path  ansi_path
2796
#else
2797
#       define Ansi_Path  path
2798
#endif
2799
 
2800
        flags = GetFileAttributesA(Ansi_Path);
2801
        if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
2802
            Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
2803
                   FnFilter1(path)));
2804
            memset(buf, 0, sizeof(z_stat));
2805
            buf->st_atime = buf->st_ctime = buf->st_mtime =
2806
              dos_to_unix_time(DOSTIME_MINIMUM);        /* 1-1-80 */
2807
            buf->st_mode = S_IFDIR | S_IREAD |
2808
                           ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
2809
            return 0;
2810
        } /* assumes: stat() won't fail on non-dirs without good reason */
2811
#       undef Ansi_Path
2812
    }
2813
#endif /* W32_STATROOT_FIX */
2814
    return -1;
2815
}
2816
 
2817
#endif /* W32_STAT_BANDAID */
2818
 
2819
 
2820
 
2821
#ifdef W32_USE_IZ_TIMEZONE
2822
#include "timezone.h"
2823
#define SECSPERMIN      60
2824
#define MINSPERHOUR     60
2825
#define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
2826
static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule);
2827
 
2828
static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule)
2829
{
2830
    if (lpw32tm->wYear != 0) {
2831
        ptrule->r_type = JULIAN_DAY;
2832
        ptrule->r_day = ydays[lpw32tm->wMonth - 1] + lpw32tm->wDay;
2833
    } else {
2834
        ptrule->r_type = MONTH_NTH_DAY_OF_WEEK;
2835
        ptrule->r_mon = lpw32tm->wMonth;
2836
        ptrule->r_day = lpw32tm->wDayOfWeek;
2837
        ptrule->r_week = lpw32tm->wDay;
2838
    }
2839
    ptrule->r_time = (long)lpw32tm->wHour * SECSPERHOUR +
2840
                     (long)(lpw32tm->wMinute * SECSPERMIN) +
2841
                     (long)lpw32tm->wSecond;
2842
}
2843
 
2844
int GetPlatformLocalTimezone(register struct state * ZCONST sp,
2845
        void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res,
2846
                                        ZCONST struct rule * ZCONST start,
2847
                                        ZCONST struct rule * ZCONST end))
2848
{
2849
    TIME_ZONE_INFORMATION tzinfo;
2850
    DWORD res;
2851
 
2852
    /* read current timezone settings from registry if TZ envvar missing */
2853
    res = GetTimeZoneInformation(&tzinfo);
2854
    if (res != TIME_ZONE_ID_INVALID)
2855
    {
2856
        struct rule startrule, stoprule;
2857
 
2858
        conv_to_rule(&(tzinfo.StandardDate), &stoprule);
2859
        conv_to_rule(&(tzinfo.DaylightDate), &startrule);
2860
        sp->timecnt = 0;
2861
        sp->ttis[0].tt_abbrind = 0;
2862
        if ((sp->charcnt =
2863
             WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1,
2864
                                 sp->chars, sizeof(sp->chars), NULL, NULL))
2865
            == 0)
2866
            sp->chars[sp->charcnt++] = '\0';
2867
        sp->ttis[1].tt_abbrind = sp->charcnt;
2868
        sp->charcnt +=
2869
            WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1,
2870
                                sp->chars + sp->charcnt,
2871
                                sizeof(sp->chars) - sp->charcnt, NULL, NULL);
2872
        if ((sp->charcnt - sp->ttis[1].tt_abbrind) == 0)
2873
            sp->chars[sp->charcnt++] = '\0';
2874
        sp->ttis[0].tt_gmtoff = - (tzinfo.Bias + tzinfo.StandardBias)
2875
                                * MINSPERHOUR;
2876
        sp->ttis[1].tt_gmtoff = - (tzinfo.Bias + tzinfo.DaylightBias)
2877
                                * MINSPERHOUR;
2878
        sp->ttis[0].tt_isdst = 0;
2879
        sp->ttis[1].tt_isdst = 1;
2880
        sp->typecnt = (startrule.r_mon == 0 && stoprule.r_mon == 0) ? 1 : 2;
2881
 
2882
        if (sp->typecnt > 1)
2883
            (*fill_tzstate_from_rules)(sp, &startrule, &stoprule);
2884
        return TRUE;
2885
    }
2886
    return FALSE;
2887
}
2888
#endif /* W32_USE_IZ_TIMEZONE */
2889
 
2890
#endif /* !FUNZIP */
2891
 
2892
 
2893
 
2894
#ifndef WINDLL
2895
/* This replacement getch() function was originally created for Watcom C
2896
 * and then additionally used with CYGWIN. Since UnZip 5.4, all other Win32
2897
 * ports apply this replacement rather that their supplied getch() (or
2898
 * alike) function.  There are problems with unabsorbed LF characters left
2899
 * over in the keyboard buffer under Win95 (and 98) when ENTER was pressed.
2900
 * (Under Win95, ENTER returns two(!!) characters: CR-LF.)  This problem
2901
 * does not appear when run on a WinNT console prompt!
2902
 */
2903
 
2904
/* Watcom 10.6's getch() does not handle Alt+. */
2905
/* Note that if PASSWD_FROM_STDIN is defined, the file containing   */
2906
/* the password must have a carriage return after the word, not a   */
2907
/* Unix-style newline (linefeed only).  This discards linefeeds.    */
2908
 
2909
int getch_win32(void)
2910
{
2911
  HANDLE stin;
2912
  DWORD rc;
2913
  unsigned char buf[2];
2914
  int ret = -1;
2915
  DWORD odemode = ~(DWORD)0;
2916
 
2917
#  ifdef PASSWD_FROM_STDIN
2918
  stin = GetStdHandle(STD_INPUT_HANDLE);
2919
#  else
2920
  stin = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE,
2921
                     FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
2922
  if (stin == INVALID_HANDLE_VALUE)
2923
    return -1;
2924
#  endif
2925
  if (GetConsoleMode(stin, &odemode))
2926
    SetConsoleMode(stin, ENABLE_PROCESSED_INPUT);  /* raw except ^C noticed */
2927
  if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
2928
    ret = buf[0];
2929
  /* when the user hits return we get CR LF.  We discard the LF, not the CR,
2930
   * because when we call this for the first time after a previous input
2931
   * such as the one for "replace foo? [y]es, ..." the LF may still be in
2932
   * the input stream before whatever the user types at our prompt. */
2933
  if (ret == '\n')
2934
    if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
2935
      ret = buf[0];
2936
  if (odemode != ~(DWORD)0)
2937
    SetConsoleMode(stin, odemode);
2938
#  ifndef PASSWD_FROM_STDIN
2939
  CloseHandle(stin);
2940
#  endif
2941
  return ret;
2942
}
2943
#endif /* !WINDLL */
2944
 
2945
 
2946
 
2947
#if (defined(UNICODE_SUPPORT) && !defined(FUNZIP))
2948
/* convert wide character string to multi-byte character string */
2949
char *wide_to_local_string(wide_string, escape_all)
2950
  ZCONST zwchar *wide_string;
2951
  int escape_all;
2952
{
2953
  int i;
2954
  wchar_t wc;
2955
  int bytes_char;
2956
  int default_used;
2957
  int wsize = 0;
2958
  int max_bytes = 9;
2959
  char buf[9];
2960
  char *buffer = NULL;
2961
  char *local_string = NULL;
2962
 
2963
  for (wsize = 0; wide_string[wsize]; wsize++) ;
2964
 
2965
  if (max_bytes < MB_CUR_MAX)
2966
    max_bytes = MB_CUR_MAX;
2967
 
2968
  if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
2969
    return NULL;
2970
  }
2971
 
2972
  /* convert it */
2973
  buffer[0] = '\0';
2974
  for (i = 0; i < wsize; i++) {
2975
    if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
2976
      /* wchar_t probably 2 bytes */
2977
      /* could do surrogates if state_dependent and wctomb can do */
2978
      wc = zwchar_to_wchar_t_default_char;
2979
    } else {
2980
      wc = (wchar_t)wide_string[i];
2981
    }
2982
    /* Unter some vendor's C-RTL, the Wide-to-MultiByte conversion functions
2983
     * (like wctomb() et. al.) do not use the same codepage as the other
2984
     * string arguments I/O functions (fopen, mkdir, rmdir etc.).
2985
     * Therefore, we have to fall back to the underlying Win32-API call to
2986
     * achieve a consistent behaviour for all supported compiler environments.
2987
     * Failing RTLs are for example:
2988
     *   Borland (locale uses OEM-CP as default, but I/O functions expect ANSI
2989
     *            names)
2990
     *   Watcom  (only "C" locale, wctomb() always uses OEM CP)
2991
     * (in other words: all supported environments except the Microsoft RTLs)
2992
     */
2993
    bytes_char = WideCharToMultiByte(
2994
                          CP_ACP, WC_COMPOSITECHECK,
2995
                          &wc, 1,
2996
                          (LPSTR)buf, sizeof(buf),
2997
                          NULL, &default_used);
2998
    if (default_used)
2999
      bytes_char = -1;
3000
    if (escape_all) {
3001
      if (bytes_char == 1 && (uch)buf[0] <= 0x7f) {
3002
        /* ASCII */
3003
        strncat(buffer, buf, 1);
3004
      } else {
3005
        /* use escape for wide character */
3006
        char *escape_string = wide_to_escape_string(wide_string[i]);
3007
        strcat(buffer, escape_string);
3008
        free(escape_string);
3009
      }
3010
    } else if (bytes_char > 0) {
3011
      /* multi-byte char */
3012
      strncat(buffer, buf, bytes_char);
3013
    } else {
3014
      /* no MB for this wide */
3015
      /* use escape for wide character */
3016
      char *escape_string = wide_to_escape_string(wide_string[i]);
3017
      strcat(buffer, escape_string);
3018
      free(escape_string);
3019
    }
3020
  }
3021
  if ((local_string = (char *)realloc(buffer, strlen(buffer) + 1)) == NULL) {
3022
    free(buffer);
3023
    return NULL;
3024
  }
3025
 
3026
  return local_string;
3027
}
3028
 
3029
 
3030
#if 0
3031
wchar_t *utf8_to_wchar_string(utf8_string)
3032
  char *utf8_string;       /* path to get utf-8 name for */
3033
{
3034
  wchar_t  *qw;
3035
  int       ulen;
3036
  int       ulenw;
3037
 
3038
  if (utf8_string == NULL)
3039
    return NULL;
3040
 
3041
    /* get length */
3042
    ulenw = MultiByteToWideChar(
3043
                CP_UTF8,           /* UTF-8 code page */
3044
                0,                 /* flags for character-type options */
3045
                utf8_string,       /* string to convert */
3046
                -1,                /* string length (-1 = NULL terminated) */
3047
                NULL,              /* buffer */
3048
 
3049
    if (ulenw == 0) {
3050
      /* failed */
3051
      return NULL;
3052
    }
3053
    ulenw++;
3054
    /* get length in bytes */
3055
    ulen = sizeof(wchar_t) * (ulenw + 1);
3056
    if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
3057
      return NULL;
3058
    }
3059
    /* convert multibyte to wide */
3060
    ulen = MultiByteToWideChar(
3061
               CP_UTF8,           /* UTF-8 code page */
3062
               0,                 /* flags for character-type options */
3063
               utf8_string,       /* string to convert */
3064
               -1,                /* string length (-1 = NULL terminated) */
3065
               qw,                /* buffer */
3066
               ulenw);            /* buffer length (0 = return length) */
3067
    if (ulen == 0) {
3068
      /* failed */
3069
      free(qw);
3070
      return NULL;
3071
    }
3072
 
3073
  return qw;
3074
}
3075
 
3076
wchar_t *local_to_wchar_string(local_string)
3077
  char *local_string;       /* path of local name */
3078
{
3079
  wchar_t  *qw;
3080
  int       ulen;
3081
  int       ulenw;
3082
 
3083
  if (local_string == NULL)
3084
    return NULL;
3085
 
3086
    /* get length */
3087
    ulenw = MultiByteToWideChar(
3088
                CP_ACP,            /* ANSI code page */
3089
                0,                 /* flags for character-type options */
3090
                local_string,      /* string to convert */
3091
                -1,                /* string length (-1 = NULL terminated) */
3092
                NULL,              /* buffer */
3093
 
3094
    if (ulenw == 0) {
3095
      /* failed */
3096
      return NULL;
3097
    }
3098
    ulenw++;
3099
    /* get length in bytes */
3100
    ulen = sizeof(wchar_t) * (ulenw + 1);
3101
    if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
3102
      return NULL;
3103
    }
3104
    /* convert multibyte to wide */
3105
    ulen = MultiByteToWideChar(
3106
               CP_ACP,            /* ANSI code page */
3107
               0,                 /* flags for character-type options */
3108
               local_string,      /* string to convert */
3109
               -1,                /* string length (-1 = NULL terminated) */
3110
               qw,                /* buffer */
3111
               ulenw);            /* buffer length (0 = return length) */
3112
    if (ulen == 0) {
3113
      /* failed */
3114
      free(qw);
3115
      return NULL;
3116
    }
3117
 
3118
  return qw;
3119
}
3120
#endif /* 0 */
3121
#endif /* UNICODE_SUPPORT && !FUNZIP */
3122
 
3123
 
3124
 
3125
/* --------------------------------------------------- */
3126
/* Large File Support
3127
 *
3128
 * Initial functions by E. Gordon and R. Nausedat
3129
 * 9/10/2003
3130
 * Lifted from Zip 3b, win32.c and place here by Myles Bennett
3131
 * 7/6/2004
3132
 *
3133
 * These implement 64-bit file support for Windows.  The
3134
 * defines and headers are in win32/w32cfg.h.
3135
 *
3136
 * Moved to win32i64.c by Mike White to avoid conflicts in
3137
 * same name functions in WiZ using UnZip and Zip libraries.
3138
 * 9/25/2003
3139
 */