~ubuntu-branches/ubuntu/precise/boinc/precise

« back to all changes in this revision

Viewing changes to zip/unzip/win32/win32.c

Tags: 6.12.8+dfsg-1
* New upstream release.
* Simplified debian/rules

Show diffs side-by-side

added added

removed removed

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