Subversion Repositories autosfx

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 daniel-mar 1
#include "stdafx.h"
2
#pragma hdrstop
3
#include "ZipOp.h"
4
#include "dz_errs.h"
5
 
6
#undef _DZ_FILE_
7
#define _DZ_FILE_ DZ_ZIPWIN32_CPP
8
 
9
/* Win32Zip.c
10
 * Copyright (C) 1990-1996 Mark Adler, Richard B. Wales, Jean-loup Gailly,
11
 * Kai Uwe Rommel, Onno van der Linden and Igor Mandrichenko.
12
 * This version modified by Chris Vleghert and Eric Engler for BCB/Delphi Zip.
13
 ** distributed under LGPL license ** see license.txt for details
14
 
15
  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
16
 
17
  See the accompanying file LICENSE, version 2007-Mar-4 or later
18
  (the contents of which are also included in zip.h) for terms of use.
19
  If, for some reason, all these files are missing, the Info-ZIP license
20
  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
21
 
22
  parts Copyright (C) 1997 Mike White, Eric W. Engler
23
************************************************************************
24
 Copyright (C) 2009, 2010  by Russell J. Peters, Roger Aelbrecht
25
 
26
   This file is part of TZipMaster Version 1.9.
27
 
28
    TZipMaster is free software: you can redistribute it and/or modify
29
    it under the terms of the GNU Lesser General Public License as published by
30
    the Free Software Foundation, either version 3 of the License, or
31
    (at your option) any later version.
32
 
33
    TZipMaster is distributed in the hope that it will be useful,
34
    but WITHOUT ANY WARRANTY; without even the implied warranty of
35
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36
    GNU Lesser General Public License for more details.
37
 
38
    You should have received a copy of the GNU Lesser General Public License
39
    along with TZipMaster.  If not, see <http://www.gnu.org/licenses/>.
40
 
41
    contact: problems@delphizip.org (include ZipMaster in the subject).
42
    updates: http://www.delphizip.org
43
    DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip
44
************************************************************************/
45
 
46
#include <direct.h>                   // for rmdir()
47
#include <time.h>
48
#include <io.h>
49
#include <ctype.h>
50
#include <sys\stat.h>
51
#ifndef __BORLANDC__
52
#define stati64 _stati64
53
#endif
54
 
55
const char *GetLongPathEA(void);
56
 
57
#define PATH_END      BSLASH //'\\'            // SLASH
58
#define HIDD_SYS_BITS (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
59
 
60
class ZDir
61
{
62
                WIN32_FIND_DATA fdata;
63
        bool    ffirst;
64
        bool    fdone;
65
        bool    hidden;
66
        bool    archiveOnly;
67
        ZipOp *Owner;
68
        HANDLE  d_hFindFile;
69
        ZDir();
70
        ZDir(const ZDir&);
71
        ZDir& operator=(const ZDir&);
72
        DWORD __fastcall GetAttrs() const;
73
        DZStrW __fastcall GetFilename() const;
74
        __int64 __fastcall GetSize() const;
75
 
76
    protected:
77
        bool __fastcall next(void);
78
 
79
    public:
80
        ZDir(ZipOp* theOwner, const DZStrW& path);
81
        ~ZDir(void);
82
        bool __fastcall Read();
83
        __property DWORD Attrs = {read = GetAttrs};
84
        __property DZStrW Filename = {read = GetFilename};
85
        __property bool Done = {read = fdone};
86
        __property __int64 size = {read = GetSize};
87
};
88
 
89
ZDir::ZDir(ZipOp* theOwner, const DZStrW& path)
90
{
91
    Owner = theOwner;
92
    fdone = true;
93
    hidden = Owner->fhidden_files;
94
    archiveOnly = Owner->fArchiveFiles;
95
 
96
    DZStrW tmp;
97
    if (!Is_DrvEx(path))
98
        tmp = Owner->CurBase->Base;
99
 
100
    tmp += path;
101
    if (tmp.LastChar() != BSLASH)
102
        tmp += BSLASH;
103
 
104
    tmp += _T("*.*");   // "*.*" MS-DOS match-all spec
105
    d_hFindFile = FindFirstFile(tmp, &fdata);
106
    fdone = d_hFindFile == INVALID_HANDLE_VALUE;
107
}
108
 
109
ZDir::~ZDir(void)
110
{
111
    if (d_hFindFile != INVALID_HANDLE_VALUE)
112
        FindClose(d_hFindFile);
113
}
114
 
115
bool __fastcall ZDir::next(void)
116
{
117
    if (Done)
118
        return false;
119
 
120
    if (ffirst)
121
    {
122
        ffirst = false;
123
        return true;
124
    }
125
 
126
    if (!FindNextFile(d_hFindFile, &fdata))
127
        fdone = true;
128
 
129
    return !Done;
130
}
131
 
132
DWORD __fastcall ZDir::GetAttrs() const
133
{
134
    if (Done)
135
        return 0;
136
 
137
    return fdata.dwFileAttributes & 0xFF; // ignore rest
138
}
139
 
140
DZStrW __fastcall ZDir::GetFilename() const
141
{
142
    if (Done)
143
        return DZStrW(_T(""));
144
 
145
    return DZStrW(fdata.cFileName);
146
}
147
 
148
__int64 __fastcall ZDir::GetSize() const
149
{
150
    if (Done)
151
        return 0;
152
 
153
    __int64 x = fdata.nFileSizeHigh;
154
    x <<= 32;
155
    return x + fdata.nFileSizeLow;
156
}
157
 
158
 
159
bool __fastcall ZDir::Read(void)
160
{
161
    if (Done)
162
        return false;
163
 
164
    unsigned        cnt = 0;
165
    DWORD attrs;
166
 
167
    // Loop to read all dir entries, until next normal entry is found
168
    do
169
        {
170
        if (!next())
171
            break;
172
 
173
        if ((++cnt & 0x1F) == 0)        // added 1.71.00
174
        {
175
            // tickle and check cancel
176
            if (Owner->CB->UserCB(zacTick) < CALLBACK_IGNORED)
177
                return false;
178
                }
179
                attrs = Attrs;
180
    }
181
    // Loop to read all dir entries, until next normal entry is found   
182
    while ((!hidden && (attrs & HIDD_SYS_BITS))
183
                 || (archiveOnly && !(attrs & FILE_ATTRIBUTE_DIRECTORY)
184
                                         && !(attrs & FILE_ATTRIBUTE_ARCHIVE)));
185
    return !Done;
186
}
187
 
188
 
189
// If not in exclude mode, expand the pattern based on the contents of the
190
//   file system. This function is used while gathering filenames to be added
191
//   or updated w :: Path/pattern to match. Possible return values: ZEN_MISS,
192
//   DZ_ERR_GOOD, ZEN_ABORT, ZEN_MEM or ZEN_PARMS.
193
int ZipOp::Wild(const DZStrW &w)
194
{
195
        int   WError;           // Result of Wild()
196
        int   r;                // Result / temp var.
197
    bool  StopRecurs = false; // No recursion if filespec is file.
198
 
199
    if (Verbose < 0)
200
                Notify(ITRACE, _T("in Wild of win32zip.c, pattern=%s recurse=%d"), w.c_str(),
201
               frecurse);
202
 
203
    // diag(fewemsg, pG);
204
    // "zip -$ foo a:" can be used to force a drive name once. // v1.6017
205
    if (fvolume_label == 1)
206
    {
207
                fvolume_label = 2;
208
        flabel = getVolumeLabel(w, &flabel_time, &flabel_mode, &flabel_utim);
209
 
210
                // 1.78.4.1 RP - reject empty label
211
        if (!flabel.IsEmpty())
212
            (void)newname(flabel, 0);
213
 
214
        if (Is_Drv(w) == 1)
215
            return DZ_ERR_GOOD;
216
    }
217
 
218
    // Allocate and copy pattern
219
    // Separate path and name into p and q
220
    // We have '\' or '\name' or 'path1\path2\name2' or 'C:\path\name' but NOT
221
    // 'C:\name'
222
        DZStrW path(w);
223
        DZStrW name;
224
        DZStrW cdir;
225
        int cpos = w.ReverseFind(BSLASH);
226
        if (cpos >= 0 && (cpos > 0 && w[cpos - 1] != _T(':')))
227
    {
228
        path = w.Left(cpos);   // before sep
229
        if (path.IsEmpty())
230
            cdir = _T("\\.");
231
                name = w.Mid(cpos + 1);
232
    }
233
    else
234
    {
235
                cpos = w.ReverseFind(_T(':'));
236
        if (cpos > 0)
237
        {
238
            // We have 'C:' or 'C:\' or 'C:\name'
239
            if ((cpos + 1) < (int) w.length() && w[cpos + 1] == BSLASH)
240
                cpos++;
241
 
242
            path = w.Left(cpos + 1);
243
            name = w.Mid(cpos + 1);
244
            path += _T('.');
245
                        cdir = path + _T(':');
246
        }
247
                else
248
                        if (frecurse && (!w.Compare(_T(".")) || !w.Compare(_T(".."))))
249
            {
250
                // current or parent directory
251
                // Get "zip -r foo ." to work. Allow the dubious "zip -r foo .." but
252
                                //   reject "zip -r -m foo ..". "dispose" means wipe out source path.
253
                if (fdispose && !w.Compare(_T("..")))
254
                    DZException(DZ_ERM_BAD_OPTIONS);
255
 
256
                name = _T("*.*");
257
            }
258
            else
259
            {
260
                                // no path or device
261
                name = w;
262
                cdir = _T(".");
263
                path = cdir;
264
            }
265
 
266
    }
267
 
268
        if (frecurse && name.IsEmpty())
269
        name = _T("*.*");
270
 
271
    // take out a possibly redundant dir name of "."
272
    DZStrW tmp = path.Right(2);
273
 
274
    if (!tmp.Compare(_T(":.")) || !tmp.Compare(_T("\\.")))
275
        path = path.Left(path.length() - 1);
276
 
277
        // Only filename (not the path) can have special matching characters
278
    if (IsWild(path))
279
    {
280
        diag(_T("path has illegal chars"));
281
        return DZ_ERM_INVAL_NAME;
282
    }
283
 
284
    if (!IsWild(name))
285
    {
286
                // Speed up checking if file exits in case there are no wildcards
287
        struct stati64 s;  // and no recursion and no archiving v1.6016
288
 
289
                if (!frecurse && !fArchiveFiles)
290
        {
291
                        if (!ZStat(GetFullPath(w), &s))  // file exists ?
292
                return procname(w, false);
293
 
294
                        return DZ_ERM_MISS;  // woops, no wildcards where is the file!
295
                }
296
    }
297
 
298
    // Now that we have a dir spec, along with an fspec, we'll step in the dir
299
    //   specified to see if there's any matches against the fspec.
300
    WError = DZ_ERM_MISS; //ZEN_MISS02;
301
 
302
    ZDir dir(this, path);
303
 
304
    if (path[0] != _T('.') && path.LastChar() != BSLASH)
305
        path += BSLASH;
306
 
307
    if (!dir.Done)
308
        {
309
        while (dir.Read())
310
        {
311
            if (Abort_Flag)
312
                                Fatal(DZ_ERM_ABORT, 0);
313
 
314
            DZStrW n = dir.Filename;
315
 
316
            // if e is NOT '.' or '..', and is a dir or match fspec.
317
            if (!n.Compare(_T(".")) || !n.Compare(_T("..")))
318
                continue;
319
 
320
            if (dir.Attrs & FILE_ATTRIBUTE_DIRECTORY)
321
            {
322
                // We do not save dirs or go into dirs if norecursefiles==1 and we
323
                // have a file without * or ? specs.
324
                if (!StopRecurs && (fdirnames || frecurse))
325
                {
326
                    if (!path.IsEmpty() && path[0] == _T('.'))
327
                        path.Empty();
328
 
329
                    if (!path.IsEmpty())
330
                    {
331
                        if (path.LastChar() != BSLASH)
332
                            path += BSLASH;
333
 
334
                        n = path + n;
335
                    }
336
 
337
                    if (fdirnames)
338
                    {
339
                        // Save directory names also.
340
                        r = procname(n, false);
341
 
342
                        if (ZEN_Rank(r) > ZEN_Rank(WError))
343
                            WError = r;
344
 
345
                        if (DZ_ERR(r) == DZ_ERR_INVAL_NAME)
346
                            continue; // ignore invalid name
347
 
348
                                                if (ZEN_Rank(r) > 0)
349
                                                        break;
350
                    }
351
 
352
                    if (frecurse)
353
                    {
354
                                                // Recursively go into dir and check for other pattern matches.
355
                        if (n.LastChar() != BSLASH)
356
                            n += BSLASH;
357
 
358
                        n += name;  // Add the original pattern.
359
 
360
                        r = Wild(n);
361
 
362
                                                // We keep a DZ_ERR_GOOD even when DZ_ERR_MISS occurs.
363
                        if (ZEN_Rank(r) > ZEN_Rank(WError))
364
                            WError = r;
365
 
366
                        if (DZ_ERR(r) == DZ_ERR_INVAL_NAME)
367
                            continue; // ignore invalid name
368
 
369
                        if (ZEN_Rank(r) > 0)
370
                            break;                        // An error, stop processing.
371
                    }
372
                }
373
            }
374
            else   // not a directory
375
                if (ZMatch(name, n))
376
                {
377
                    if (!path.Compare(_T(".")))
378
                        r = procname(n, false);
379
                    else
380
                    {
381
                        n = path + n;
382
                        r = procname(n, false);
383
                    }
384
 
385
                                        if (ZEN_Rank(r) > ZEN_Rank(WError))
386
                        WError = r;
387
 
388
                    if (DZ_ERR(r) == DZ_ERR_INVAL_NAME)
389
                        continue; // ignore invalid name
390
 
391
                                        if (ZEN_Rank(r) > 0)
392
                        break;
393
                                }
394
                }                                         // end while
395
    }
396
    else
397
                diag(_T("can't open dir"));
398
 
399
    return WError;
400
}
401
 
402
// Process a name or wildcard expression to operate on (or exclude). We will
403
//   only arrive here if we do a Freshen or Delete. Return an error code in the
404
//   ZEN_ class. DZ_ERR_GOOD, ZEN_ABORT, ZEN_MISS03, ZEN_MISS04, ZEN_MISS05,
405
//   ZEN_MEM22, ZEN_MEM23 ArgName :: Name to process.
406
int ZipOp::procname(const DZStrW &ArgName, bool RecurseDir)
407
{
408
        int           m;                            // matched flag
409
    int           pnError;                      // ProcName error
410
 
411
    struct stati64 StatRes;                    // result of stat()
412
    ZipItem  *z;                           // steps through zfiles list
413
 
414
    if (Verbose < 0)
415
        Notify(ITRACE, _T("in procname, name=%s recurse=%d"), ArgName.c_str(),
416
               RecurseDir);
417
 
418
    m = 1;                                      // set dflt for success indicator
419
 
420
    ///* (0=success)
421
 
422
    if (Abort_Flag)
423
                Fatal(DZ_ERM_ABORT, 0);
424
 
425
    if (ArgName.IsEmpty())
426
        return DZ_ERM_MISS;
427
 
428
    // LSSTAT returns 0 if it's arg is any kind of file (even a dir).
429
    // IsShExp returns true if a wildcard symbol is found, or NULL if none
430
        //   were found -- IsShExp is in util.c
431
    if (IsWild(ArgName) || ZStat(GetFullPath(ArgName), &StatRes))
432
    {
433
        // diag("not a file or dir - 'ArgName' must be a wildcard fspec");
434
        // Upon finding a wildcard fspec, we need to mark entries in
435
        // the "zfiles" list that are included by the wildcard.
436
        // convert the "external" (native) filename to an internal
437
                //   ZIP-archive-compatible filename.
438
        DZStrW p = ex2IntForm(ArgName, false);  // shouldn't affect matching chars
439
 
440
        if (Verbose < 0)
441
                        Notify(ITRACE, _T("in procname, searching %s"), p.c_str());
442
 
443
        // does any file already in the archive match this spec?
444
        // Note that we need the pathname and filename together for this
445
 
446
        for (z = fzfiles; z; z = z->nxt)
447
        {
448
            if (z->mark)
449
            {
450
#ifdef ZDEBUG
451
                if (Verbose < 0)
452
                    Notify(ITRACE, _T("%s already marked"), z->IName.c_str());
453
#endif
454
                continue;       // only mark once
455
            }
456
 
457
            // z->name = 'external' version of zname for unmatched names
458
            if (ZMatch(p, z->IName))
459
            {
460
                // name is in archive - mark it for updating
461
                z->mark = fpcount ? !ZMatch(fExcludes, z->IName) : 1;
462
                if (Verbose)
463
                    Notify(0, _T("%scluding %s"), z->mark ? _T("in") : _T("ex"), z->IName.c_str());
464
 
465
                if (z->mark)
466
                                {
467
                    if (Is_Drv(ArgName) > 0  && ArgName[2] == BSLASH)
468
                    {
469
                        z->XName = ArgName.Left(3) + z->IName;
470
                    }
471
 
472
                    // RA password added
473
                    z->Passw = fkey;
474
                    z->Base = CurBase->Base;
475
                    z->options.keepver = fversion ? 1 : 0;
476
 
477
                    m = 0;  // we had at least one file in the archive that we marked
478
                }
479
 
480
                // if not wild it can only match once
481
                if (!IsWild(ArgName))
482
                    break;
483
            }
484
        }
485
 
486
        // returns 1 if no "zfiles" entries were marked, 0 if at least one entry
487
        //   was marked
488
        if (m)
489
        {
490
            // diag("returning ZEN_MISS04 from procname");
491
            return DZ_ERM_MISS;
492
        }
493
 
494
        // diag("returning DZ_ERR_GOOD from procname");
495
        return DZ_ERR_GOOD;
496
    }                         // end of "if (LSSTAT..."
497
 
498
    // Existing and good filename or directory-- add the name if it's a file,
499
    //   recurse if directory
500
    // diag("good entry to add, or a dir to go into");
501
    // check the status returned by LSSTAT earlier to see if 'ArgName' is a dir
502
    pnError = DZ_ERR_GOOD;
503
 
504
    if (!(StatRes.st_mode & S_IFDIR))
505
    {
506
        // it's not a directory - add file to found list
507
        if (Verbose)
508
            Notify(IVERBOSE, _T("Adding file %s to found list"), ArgName.c_str());
509
 
510
        // newname (fileio.c) adds to found list. If error m!=0 on return
511
        if ((m = newname(ArgName, StatRes.st_size)) != DZ_ERR_GOOD)
512
        {
513
            if (Verbose < 0)
514
                Notify(ITRACE, _T("returning %d from procname after newname call"), m);
515
 
516
            return m;
517
        }
518
    }
519
    else
520
    {
521
        // It is a directory - Add trailing / to the directory name
522
        if (Verbose < 0)
523
            Notify(ITRACE, _T("procname dir = %s"), ArgName.c_str());
524
 
525
                // diag("Spot 2, directory found");
526
        DZStrW p;
527
 
528
                if (ArgName.Compare(_T(".")) && ArgName.Compare(_T("\\.")))
529
        {
530
                        if (Verbose)
531
                                Notify(IVERBOSE, _T("Adding folder %s to found list"), ArgName.c_str());
532
                        p = ArgName;
533
            if (p.LastChar() != BSLASH)
534
                p += BSLASH;
535
 
536
            // newname (fileio.c) adds to found list. If error m != 0 on return
537
            if (fdirnames && (m = newname(p, 0)) != DZ_ERR_GOOD)
538
            {
539
                if (Verbose < 0)
540
                    Notify(ITRACE, _T("returning %d from procname after 2nd newname call"),
541
                        DZ_ERR(m));
542
 
543
                return m;
544
            }
545
        }
546
 
547
        // recurse into directory
548
        // p = empty or dirname
549
        // diag("spot 4: optional recurse into dir");
550
        if (RecurseDir)
551
        {
552
                        ZDir dir(this, ArgName);
553
            while (dir.Read())
554
            {
555
                if (Abort_Flag)
556
                                        Fatal(DZ_ERM_ABORT, 0);
557
                                DZStrW a(p);
558
 
559
                a += dir.Filename;
560
 
561
                // form the new dir's pathname followed by the fname just read
562
                // (we need to send in the dir and fname, or it won't be detected
563
                                //   as a valid file by LSSTAT)
564
 
565
                // diag("DOING RECURSIVE CALL TO PROCNAME FROM PROCNAME");
566
                if ((m = procname(a, RecurseDir)) != DZ_ERR_GOOD)
567
                {
568
                                        // recursive call failed; return code not DZ_ERR_GOOD
569
                                        // unknown error; RCV error handling changed
570
                                        pnError = m;
571
                                        break;
572
                }
573
            }                       // end while
574
 
575
        }
576
    }                           // (StatRes.st_mode & S_IFDIR) == 0)
577
 
578
    // diag("returning ZEN_ class from procname");
579
    return pnError;
580
}
581
 
582
#if 0
583
// ** moved to DzOp
584
// Convert the external file name to an "internal" file name form,
585
//   returning the malloc'ed string, or NULL if not enough memory.
586
//   I.e. Strip the drive if present, strip the path
587
//if we
588
//   don't want one and change the name to 8.3 if needed. Not implemented, but
589
//   also 'put in' change the short path to a long path.
590
DZStrW ZipOp::ex2IntForm(const DZStrW &exname, bool ignore)
591
{
592
    bool  pathput;
593
 
594
    if (ignore)
595
        {
596
        pathput = true;
597
    }
598
    else
599
        {
600
        pathput = fpathput;
601
    }
602
 
603
        DZStrW XName(exname);
604
 
605
    if (XName.IsEmpty())
606
        return XName;
607
 
608
        DZStrW nname = StrExtSep(XName);
609
    int p = DriveLen(nname);
610
 
611
    int len = nname.length();
612
    // Strip leading "\" to convert an absolute path into a relative path
613
 
614
    while (p < len && nname[p] == BSLASH)
615
        p++;
616
 
617
    // Strip leading "./" as well as drive letter v1.6017
618
    while ((p + 2) < len && (nname[p] == _T('.') && nname[p + 1] == BSLASH))
619
        p += 2;
620
 
621
    // This is where the dirname gets stripped if user doesn't want it
622
    if (!pathput)
623
    {
624
        int t = nname.ReverseFind(BSLASH);
625
 
626
        if (t >= p)
627
            p = ++t;
628
    }
629
 
630
    if (p)
631
    {
632
        nname = nname.Mid(p);
633
    }
634
 
635
    if (nname.length() > MAX_PATH)
636
    {
637
        int t = nname.length();
638
        XName = nname.Left(MAX_PATH);
639
 
640
        if (Verbose) // < 0)
641
            Notify(IWARNING, _T("File name %s is too long [%d]. Truncated to %s"),
642
                   nname.c_str(), t, XName.c_str());
643
 
644
        nname = XName;
645
    }
646
 
647
    return nname;
648
}
649
#endif
650
 
651
// Set last updated and accessed time of file f to the DOS time d. This is
652
//   called by dllzip.c to set date/time of the zipfile. RCV Removed __TURBOC__
653
//   version. f :: name of file to change. d :: dos-style time to change it to.
654
typedef struct  DosDate
655
{
656
    WORD  lo;
657
    WORD  hi;
658
}dosdate;
659
 
660
void stamp(const DZStrW& f, ulg d)
661
{
662
    HANDLE    fHandle;
663
    FILETIME  LocalFT,
664
    FT;
665
 
666
    fHandle = CreateFile(f, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
667
                         FILE_ATTRIBUTE_ARCHIVE, NULL);
668
 
669
    if (fHandle != INVALID_HANDLE_VALUE)
670
    {
671
        if (DosDateTimeToFileTime(((struct DosDate *) &d)->hi,
672
                                  ((struct DosDate *) &d)->lo, &LocalFT)
673
                && LocalFileTimeToFileTime(&LocalFT, &FT))
674
            SetFileTime(fHandle, NULL, NULL, &FT);
675
 
676
        CloseHandle(fHandle);
677
    }
678
}
679
 
680
/*********************************/
681
/* Function NtfsFileTime2utime() */
682
/*********************************/
683
 
684
/* scale factor and offset for conversion time_t -> FILETIME */
685
#define NT_QUANTA_PER_UNIX 10000000L
686
#define UNIX_TIME_ZERO_HI  0x019DB1DEUL
687
#define UNIX_TIME_ZERO_LO  0xD53E8000UL
688
 
689
// /* nonzero if `y' is a leap year, else zero */
690
//#define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0)
691
// /* number of leap years from 1970 to `y' (not including `y' itself) */
692
//#define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400)
693
 
694
int NtfsFileTime2utime(const FILETIME *pft, time_t *ut)
695
{
696
    unsigned __int64 NTtime;
697
 
698
    NTtime = ((unsigned __int64)pft->dwLowDateTime +
699
              ((unsigned __int64)pft->dwHighDateTime << 32));
700
 
701
    NTtime -= ((unsigned __int64)UNIX_TIME_ZERO_LO +
702
               ((unsigned __int64)UNIX_TIME_ZERO_HI << 32));
703
    *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX);
704
    return TRUE;
705
} /* end function NtfsFileTime2utime() */
706
 
707
 
708
// If file *f does not exist, return 0. Else, return the file's last
709
//   modified date and time as an MSDOS date and time. The date and time is
710
//   returned in a long with the date most significant to allow unsigned
711
//   integer comparison of absolute times. Also, if a is not a NULL pointer,
712
//   store the file attributes there, with the high two bytes being the Unix
713
//   attributes, and the low byte being a mapping of that to DOS attributes.
714
//   If n is not NULL, store the file size there.
715
//     If f is "-", use standard input as the file.
716
//     If f is a device, return a file size of -1
717
//     If f is a Volume Name, return a file size of -2
718
//   If t is not NULL, the file's access and modification time are stored there
719
//    as UNIX time_t values.
720
//   f :: Name of file to get info on.
721
//   a :: Return value: file attributes.
722
//   n :: Return value: file size.
723
//   t :: Return value: access and modification time.
724
extern BOOL unixtofile(time_t tim, FILETIME *ftp);
725
 
726
ulg ZipFunc::zfiletime(const DZStrW& f, ulg *a, __int64 *n, ztimbuf *t)
727
{
728
    WIN32_FIND_DATA ff;
729
    HANDLE      hfind;              /* file handle */
730
 
731
    if (f == flabel)
732
    {
733
        if (a != NULL)
734
            *a = flabel_mode;
735
 
736
        if (n != NULL)
737
            *n = ZFT_LABEL;               // convention for a label name
738
 
739
        if (t != NULL)
740
            t->actime = t->modtime = flabel_utim;
741
 
742
        return flabel_time;
743
    }
744
 
745
    int drv = Is_Drv(f);
746
 
747
    if (drv < 0)
748
    {
749
                //stream
750
                ZSData.BufP = 0;
751
        ZSData.Number = (-drv) - 2; // stream number
752
        ZSData.OpCode = zsaIdentify;
753
        int ok = StreamCB() == CALLBACK_TRUE;
754
 
755
        if (ok)
756
        {
757
            if (n)
758
                *n = ZSData.ArgLL;
759
 
760
            if (a != NULL)
761
            {
762
                                DWORD dwAttr = ZSData.ArgA;
763
                *a = (dwAttr & FILE_ATTRIBUTE_READONLY ? A_RONLY : 0) |
764
                     (dwAttr & FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN : 0) |
765
                     (dwAttr & FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM : 0) |
766
                     (dwAttr & FILE_ATTRIBUTE_DIRECTORY ? A_DIR : 0) |
767
                     (dwAttr & FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE : 0);
768
                        }
769
            return ZSData.ArgD;
770
        }
771
 
772
        return 0;
773
    }
774
 
775
    DZStrW fullname = drv ? f : GetFullPath(f);
776
 
777
        // not all systems allow stat'ing a file with / appended, so remove it
778
    if (fullname.LastChar() == BSLASH)
779
        fullname = fullname.Left(fullname.length()-1);
780
 
781
        // Accept about any kind of file including directories
782
    if ((hfind = FindFirstFile(fullname, &ff)) == INVALID_HANDLE_VALUE)
783
    {
784
        if (Verbose < 0)
785
            Notify(ITRACE, _T("Could not find %s"), fullname.c_str());
786
 
787
        return 0;                 // error in stat!
788
    }
789
 
790
        FindClose(hfind);
791
        // found
792
    if (n != NULL)
793
    {
794
        *n = ff.nFileSizeLow  | ((__int64)ff.nFileSizeHigh << 32);
795
    }
796
 
797
    if (a != NULL)
798
    {
799
        DWORD dwAttr = ff.dwFileAttributes;
800
        *a = (dwAttr & FILE_ATTRIBUTE_READONLY ? A_RONLY : 0) |
801
             (dwAttr & FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN : 0) |
802
             (dwAttr & FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM : 0) |
803
             (dwAttr & FILE_ATTRIBUTE_DIRECTORY ? A_DIR : 0) |
804
             (dwAttr & FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE : 0);
805
    }
806
 
807
    if (t != NULL)
808
    {
809
        NtfsFileTime2utime(&ff.ftLastAccessTime, &t->actime);
810
                NtfsFileTime2utime(&ff.ftLastWriteTime, &t->modtime);
811
    }
812
 
813
    return FileTime2DosTime(ff.ftLastWriteTime);
814
}
815
 
816
ulg FileTime2DosTime(_FILETIME ftime)
817
{
818
    _FILETIME local;
819
    WORD dt, tm;
820
 
821
    if (FileTimeToLocalFileTime(&ftime, &local) &&
822
            FileTimeToDosDateTime(&local, &dt, &tm))
823
        return (dt << 16) | tm;
824
 
825
//      Notify(0, "zip diagnostic: GetFileAttributes failed");
826
    return 0;
827
}
828
 
829
#define EAID  0x0009
830
 
831
// NOTE: NTFS is handled by the HPFS code. FAT / HPFS detection.
832
int ZipOp::IsFileSystemOldFAT(const DZStrW &dir)
833
{
834
    DWORD vfnsize;
835
    DWORD vfsflags;
836
 
837
    if (Verbose < 0)
838
        Notify(ITRACE, _T("IsFileSyatemOldFAT called for %s"), dir.c_str());
839
 
840
    // We separate FAT and HPFS+other file systems here. I consider other
841
    //   systems to be similar to HPFS/NTFS, i.e. support for long file names and
842
    //   being case sensitive to some extent.
843
    DZStrW fp = dir;
844
 
845
    if (fp.IsEmpty() || Is_DrvEx(fp) <= 0)
846
    {
847
        fp = fRootDir;   // use current root
848
 
849
        if (fp.IsEmpty() || Is_Drv(fp) <= 0)
850
            return false; // assume ntfs
851
    }
852
 
853
    int dt = Is_DrvEx(fp);
854
 
855
    if (dt < 0)
856
        return false;
857
 
858
    if (dt == 1)
859
    {
860
        fp = fp.Left(1);
861
        fp.ToUpper();
862
        TCHAR r = fp[0];
863
 
864
        if (r == fDrv[0])
865
            return fDrv[1] != 0;  // use cached result
866
 
867
        fp += _T(":\\");
868
    }
869
    else
870
    {
871
        if (dt != 2)
872
            return false;
873
 
874
        // specify \\MyServer\MyShare as \\MyServer\MyShare\.
875
        fp = fp.Left(DriveLen(fp));
876
    }
877
 
878
    if (!GetVolumeInformation(fp, NULL, 0, NULL, &vfnsize, &vfsflags, NULL, 0))
879
    {
880
        if (Verbose)
881
        {
882
            Notify(IVERBOSE, _T(" GetVolumeInformation failed for %s [%s]"),
883
                   fp.c_str(), SysMsg().c_str());
884
        }
885
 
886
        return (false);    // assume NTFS
887
    }
888
 
889
    if (Verbose)
890
        Notify(IVERBOSE, _T("Max component size for %s = %d"), fp.c_str(), vfnsize);
891
 
892
    if (_istascii(fp[0]))
893
    {
894
        fDrv[0] = fp[0];
895
        fDrv[1] = (char)(vfnsize <= 12 ? 1 : 0);
896
    }
897
 
898
    return vfnsize <= 12;
899
}
900
 
901
// access mode bits and time stamp.
902
int ZipOp::GetFileMode(const DZStrW& name)
903
{
904
    DWORD dwAttr;
905
 
906
    dwAttr = GetFileAttributes(GetFullPath(name));   // v1.6017
907
 
908
    if (dwAttr == 0xFFFFFFFF)
909
    {
910
        // RCV Changed: was ...= -1
911
        Notify(0, _T("zip diagnostic: GetFileAttributes failed"));
912
 
913
        // DLLprintf ("zip diagnostic: GetFileAttributes failed\n");
914
        return (0x20);       // the most likely, though why the error? security?
915
    }
916
 
917
    return
918
        (
919
            (dwAttr & FILE_ATTRIBUTE_READONLY ? A_RONLY : 0) |
920
            (dwAttr & FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN : 0) |
921
            (dwAttr & FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM : 0) |
922
            (dwAttr & FILE_ATTRIBUTE_DIRECTORY ? A_DIR : 0) |
923
            (dwAttr & FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE : 0)
924
        );
925
}
926
 
927
const char *GetLongPathEA(void)
928
{
929
    return (NULL);                // volunteers ?
930
}
931
 
932
// If a volume label exists for the given drive, return its name and pretend
933
//   to set its time and mode. The returned name is global data. Drive = drive
934
//   name: 'A' .. 'Z' or '\0' for current drive
935
DZStrW ZipOp::getVolumeLabel(const DZStrW &drv, ulg *vtime, ulg *vmode, time_t *vutim)
936
{
937
    DZStrW Root(drv, 2);
938
    ulg   fnlen,
939
    flags;
940
    long  OldMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
941
    BOOL  Result;
942
 
943
    *vmode = A_ARCHIVE | A_LABEL; // this is what msdos returns
944
    *vtime = dostime(1980, 1, 1, 0, 0, 0);    // no true date info available
945
    *vutim = dos2unixtime(*vtime);
946
 
947
        DZStrW vol;
948
 
949
    if (Is_Drv(drv) != 1)
950
        Root.Empty();
951
    else
952
        Root += BSLASH;
953
 
954
    Result = GetVolumeInformation(Root, vol.GetBuffer(MAX_PATH), MAX_PATH - 1,
955
                                  NULL, &fnlen, &flags, NULL, 0);
956
    SetErrorMode(OldMode);
957
    vol.ReleaseBuffer();
958
 
959
    if (!Result)
960
        vol.Empty();
961
 
962
    return vol;//Result ? fvol : NULL;
963
}
964
 
965
 
966
 
967
 
968