Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6725 siemargl 1
/*
2
  Copyright (c) 1990-2009 Info-ZIP.  All rights reserved.
3
 
4
  See the accompanying file LICENSE, version 2009-Jan-02 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
  list.c
12
 
13
  This file contains the non-ZipInfo-specific listing routines for UnZip.
14
 
15
  Contains:  list_files()
16
             get_time_stamp()   [optional feature]
17
             ratio()
18
             fnprint()
19
 
20
  ---------------------------------------------------------------------------*/
21
 
22
 
23
#define UNZIP_INTERNAL
24
#include "unzip.h"
25
#ifdef WINDLL
26
#  ifdef POCKET_UNZIP
27
#    include "wince/intrface.h"
28
#  else
29
#    include "windll/windll.h"
30
#  endif
31
#endif
32
 
33
 
34
#ifdef TIMESTAMP
35
   static int  fn_is_dir   OF((__GPRO));
36
#endif
37
 
38
#ifndef WINDLL
39
   static ZCONST char Far CompFactorStr[] = "%c%d%%";
40
   static ZCONST char Far CompFactor100[] = "100%%";
41
 
42
#ifdef OS2_EAS
43
   static ZCONST char Far HeadersS[]  =
44
     "  Length     EAs   ACLs     Date    Time    Name";
45
   static ZCONST char Far HeadersS1[] =
46
     "---------    ---   ----  ---------- -----   ----";
47
#else
48
   static ZCONST char Far HeadersS[]  =
49
     "  Length      Date    Time    Name";
50
   static ZCONST char Far HeadersS1[] =
51
     "---------  ---------- -----   ----";
52
#endif
53
 
54
   static ZCONST char Far HeadersL[]  =
55
     " Length   Method    Size  Cmpr    Date    Time   CRC-32   Name";
56
   static ZCONST char Far HeadersL1[] =
57
     "--------  ------  ------- ---- ---------- ----- --------  ----";
58
   static ZCONST char Far *Headers[][2] =
59
     { {HeadersS, HeadersS1}, {HeadersL, HeadersL1} };
60
 
61
   static ZCONST char Far CaseConversion[] =
62
     "%s (\"^\" ==> case\n%s   conversion)\n";
63
   static ZCONST char Far LongHdrStats[] =
64
     "%s  %-7s%s %4s %02u%c%02u%c%02u %02u:%02u %08lx %c";
65
   static ZCONST char Far LongFileTrailer[] =
66
     "--------          -------  ---                       \
67
     -------\n%s         %s %4s                            %lu file%s\n";
68
#ifdef OS2_EAS
69
   static ZCONST char Far ShortHdrStats[] =
70
     "%s %6lu %6lu  %02u%c%02u%c%02u %02u:%02u  %c";
71
   static ZCONST char Far ShortFileTrailer[] =
72
     "---------  -----  -----                \
73
     -------\n%s %6lu %6lu                     %lu file%s\n";
74
   static ZCONST char Far OS2ExtAttrTrailer[] =
75
     "%lu file%s %lu bytes of OS/2 extended attributes attached.\n";
76
   static ZCONST char Far OS2ACLTrailer[] =
77
     "%lu file%s %lu bytes of access control lists attached.\n";
78
#else
79
   static ZCONST char Far ShortHdrStats[] =
80
     "%s  %02u%c%02u%c%02u %02u:%02u  %c";
81
   static ZCONST char Far ShortFileTrailer[] =
82
     "---------                     -------\n%s\
83
                     %lu file%s\n";
84
#endif /* ?OS2_EAS */
85
#endif /* !WINDLL */
86
 
87
 
88
 
89
 
90
 
91
/*************************/
92
/* Function list_files() */
93
/*************************/
94
 
95
int list_files(__G)    /* return PK-type error code */
96
    __GDEF
97
{
98
    int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL;
99
#ifndef WINDLL
100
    char sgn, cfactorstr[10];
101
    int longhdr=(uO.vflag>1);
102
#endif
103
    int date_format;
104
    char dt_sepchar;
105
    ulg members=0L;
106
    zusz_t j;
107
    unsigned methnum;
108
#ifdef USE_EF_UT_TIME
109
    iztimes z_utime;
110
    struct tm *t;
111
#endif
112
    unsigned yr, mo, dy, hh, mm;
113
    zusz_t csiz, tot_csize=0L, tot_ucsize=0L;
114
#ifdef OS2_EAS
115
    ulg ea_size, tot_easize=0L, tot_eafiles=0L;
116
    ulg acl_size, tot_aclsize=0L, tot_aclfiles=0L;
117
#endif
118
    min_info info;
119
    char methbuf[8];
120
    static ZCONST char dtype[]="NXFS";  /* see zi_short() */
121
    static ZCONST char Far method[NUM_METHODS+1][8] =
122
        {"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4",
123
         "Implode", "Token", "Defl:#", "Def64#", "ImplDCL", "BZip2",
124
         "LZMA", "Terse", "IBMLZ77", "WavPack", "PPMd", "Unk:###"};
125
 
126
 
127
 
128
/*---------------------------------------------------------------------------
129
    Unlike extract_or_test_files(), this routine confines itself to the cen-
130
    tral directory.  Thus its structure is somewhat simpler, since we can do
131
    just a single loop through the entire directory, listing files as we go.
132
 
133
    So to start off, print the heading line and then begin main loop through
134
    the central directory.  The results will look vaguely like the following:
135
 
136
 Length   Method    Size  Ratio   Date   Time   CRC-32    Name ("^" ==> case
137
--------  ------  ------- -----   ----   ----   ------    ----   conversion)
138
   44004  Implode   13041  71%  11-02-89 19:34  8b4207f7  Makefile.UNIX
139
    3438  Shrunk     2209  36%  09-15-90 14:07  a2394fd8 ^dos-file.ext
140
   16717  Defl:X     5252  69%  11-03-97 06:40  1ce0f189  WHERE
141
--------          -------  ---                            -------
142
   64159            20502  68%                            3 files
143
  ---------------------------------------------------------------------------*/
144
 
145
    G.pInfo = &info;
146
    date_format = DATE_FORMAT;
147
    dt_sepchar = DATE_SEPCHAR;
148
 
149
#ifndef WINDLL
150
    if (uO.qflag < 2) {
151
        if (uO.L_flag)
152
            Info(slide, 0, ((char *)slide, LoadFarString(CaseConversion),
153
              LoadFarStringSmall(Headers[longhdr][0]),
154
              LoadFarStringSmall2(Headers[longhdr][1])));
155
        else
156
            Info(slide, 0, ((char *)slide, "%s\n%s\n",
157
               LoadFarString(Headers[longhdr][0]),
158
               LoadFarStringSmall(Headers[longhdr][1])));
159
    }
160
#endif /* !WINDLL */
161
 
162
    for (j = 1L;;j++) {
163
 
164
        if (readbuf(__G__ G.sig, 4) == 0)
165
            return PK_EOF;
166
        if (memcmp(G.sig, central_hdr_sig, 4)) {  /* is it a CentDir entry? */
167
            /* no new central directory entry
168
             * -> is the number of processed entries compatible with the
169
             *    number of entries as stored in the end_central record?
170
             */
171
            if (((j - 1) &
172
                 (ulg)(G.ecrec.have_ecr64 ? MASK_ZUCN64 : MASK_ZUCN16))
173
                == (ulg)G.ecrec.total_entries_central_dir)
174
            {
175
                /* "j modulus 4T/64k" matches the reported 64/16-bit-unsigned
176
                 * number of directory entries -> probably, the regular
177
                 * end of the central directory has been reached
178
                 */
179
                break;
180
            } else {
181
                Info(slide, 0x401,
182
                     ((char *)slide, LoadFarString(CentSigMsg), j));
183
                Info(slide, 0x401,
184
                     ((char *)slide, LoadFarString(ReportMsg)));
185
                return PK_BADERR;   /* sig not found */
186
            }
187
        }
188
        /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag, ...: */
189
        if ((error = process_cdir_file_hdr(__G)) != PK_COOL)
190
            return error;       /* only PK_EOF defined */
191
 
192
        /*
193
         * We could DISPLAY the filename instead of storing (and possibly trun-
194
         * cating, in the case of a very long name) and printing it, but that
195
         * has the disadvantage of not allowing case conversion--and it's nice
196
         * to be able to see in the listing precisely how you have to type each
197
         * filename in order for unzip to consider it a match.  Speaking of
198
         * which, if member names were specified on the command line, check in
199
         * with match() to see if the current file is one of them, and make a
200
         * note of it if it is.
201
         */
202
 
203
        if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) !=
204
             PK_COOL)   /*  ^--(uses pInfo->lcflag) */
205
        {
206
            error_in_archive = error;
207
            if (error > PK_WARN)   /* fatal:  can't continue */
208
                return error;
209
        }
210
        if (G.extra_field != (uch *)NULL) {
211
            free(G.extra_field);
212
            G.extra_field = (uch *)NULL;
213
        }
214
        if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD))
215
            != 0)
216
        {
217
            error_in_archive = error;
218
            if (error > PK_WARN)      /* fatal */
219
                return error;
220
        }
221
        if (!G.process_all_files) {   /* check if specified on command line */
222
            unsigned i;
223
 
224
            if (G.filespecs == 0)
225
                do_this_file = TRUE;
226
            else {  /* check if this entry matches an `include' argument */
227
                do_this_file = FALSE;
228
                for (i = 0; i < G.filespecs; i++)
229
                    if (match(G.filename, G.pfnames[i], uO.C_flag WISEP)) {
230
                        do_this_file = TRUE;
231
                        break;       /* found match, so stop looping */
232
                    }
233
            }
234
            if (do_this_file) {  /* check if this is an excluded file */
235
                for (i = 0; i < G.xfilespecs; i++)
236
                    if (match(G.filename, G.pxnames[i], uO.C_flag WISEP)) {
237
                        do_this_file = FALSE;  /* ^-- ignore case in match */
238
                        break;
239
                    }
240
            }
241
        }
242
        /*
243
         * If current file was specified on command line, or if no names were
244
         * specified, do the listing for this file.  Otherwise, get rid of the
245
         * file comment and go back for the next file.
246
         */
247
 
248
        if (G.process_all_files || do_this_file) {
249
 
250
#ifdef OS2DLL
251
            /* this is used by UzpFileTree() to allow easy processing of lists
252
             * of zip directory contents */
253
            if (G.processExternally) {
254
                if ((G.processExternally)(G.filename, &G.crec))
255
                    break;
256
                ++members;
257
            } else {
258
#endif
259
#ifdef OS2_EAS
260
            {
261
                uch *ef_ptr = G.extra_field;
262
                int ef_size, ef_len = G.crec.extra_field_length;
263
                ea_size = acl_size = 0;
264
 
265
                while (ef_len >= EB_HEADSIZE) {
266
                    ef_size = makeword(&ef_ptr[EB_LEN]);
267
                    switch (makeword(&ef_ptr[EB_ID])) {
268
                        case EF_OS2:
269
                            ea_size = makelong(&ef_ptr[EB_HEADSIZE]);
270
                            break;
271
                        case EF_ACL:
272
                            acl_size = makelong(&ef_ptr[EB_HEADSIZE]);
273
                            break;
274
                    }
275
                    ef_ptr += (ef_size + EB_HEADSIZE);
276
                    ef_len -= (ef_size + EB_HEADSIZE);
277
                }
278
            }
279
#endif
280
#ifdef USE_EF_UT_TIME
281
            if (G.extra_field &&
282
#ifdef IZ_CHECK_TZ
283
                G.tz_is_valid &&
284
#endif
285
                (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1,
286
                                  G.crec.last_mod_dos_datetime, &z_utime, NULL)
287
                 & EB_UT_FL_MTIME))
288
            {
289
                TIMET_TO_NATIVE(z_utime.mtime)   /* NOP unless MSC 7.0, Mac */
290
                t = localtime(&(z_utime.mtime));
291
            } else
292
                t = (struct tm *)NULL;
293
            if (t != (struct tm *)NULL) {
294
                mo = (unsigned)(t->tm_mon + 1);
295
                dy = (unsigned)(t->tm_mday);
296
                yr = (unsigned)(t->tm_year + 1900);
297
                hh = (unsigned)(t->tm_hour);
298
                mm = (unsigned)(t->tm_min);
299
            } else
300
#endif /* USE_EF_UT_TIME */
301
            {
302
                yr = ((((unsigned)(G.crec.last_mod_dos_datetime >> 25) & 0x7f)
303
                       + 1980));
304
                mo = ((unsigned)(G.crec.last_mod_dos_datetime >> 21) & 0x0f);
305
                dy = ((unsigned)(G.crec.last_mod_dos_datetime >> 16) & 0x1f);
306
                hh = (((unsigned)G.crec.last_mod_dos_datetime >> 11) & 0x1f);
307
                mm = (((unsigned)G.crec.last_mod_dos_datetime >> 5) & 0x3f);
308
            }
309
            /* permute date so it displays according to nat'l convention
310
             * ('methnum' is not yet set, it is used as temporary buffer) */
311
            switch (date_format) {
312
                case DF_YMD:
313
                    methnum = mo;
314
                    mo = yr; yr = dy; dy = methnum;
315
                    break;
316
                case DF_DMY:
317
                    methnum = mo;
318
                    mo = dy; dy = methnum;
319
            }
320
 
321
            csiz = G.crec.csize;
322
            if (G.crec.general_purpose_bit_flag & 1)
323
                csiz -= 12;   /* if encrypted, don't count encryption header */
324
            if ((cfactor = ratio(G.crec.ucsize, csiz)) < 0) {
325
#ifndef WINDLL
326
                sgn = '-';
327
#endif
328
                cfactor = (-cfactor + 5) / 10;
329
            } else {
330
#ifndef WINDLL
331
                sgn = ' ';
332
#endif
333
                cfactor = (cfactor + 5) / 10;
334
            }
335
 
336
            methnum = find_compr_idx(G.crec.compression_method);
337
            zfstrcpy(methbuf, method[methnum]);
338
            if (G.crec.compression_method == DEFLATED ||
339
                G.crec.compression_method == ENHDEFLATED) {
340
                methbuf[5] = dtype[(G.crec.general_purpose_bit_flag>>1) & 3];
341
            } else if (methnum >= NUM_METHODS) {
342
                sprintf(&methbuf[4], "%03u", G.crec.compression_method);
343
            }
344
 
345
#if 0       /* GRR/Euro:  add this? */
346
#if defined(DOS_FLX_NLM_OS2_W32) || defined(THEOS) || defined(UNIX)
347
            for (p = G.filename;  *p;  ++p)
348
                if (!isprint(*p))
349
                    *p = '?';  /* change non-printable chars to '?' */
350
#endif /* DOS_FLX_NLM_OS2_W32 || THEOS || UNIX */
351
#endif /* 0 */
352
 
353
#ifdef WINDLL
354
            /* send data to application for formatting and printing */
355
            if (G.lpUserFunctions->SendApplicationMessage != NULL)
356
                (*G.lpUserFunctions->SendApplicationMessage)(G.crec.ucsize,
357
                  csiz, (unsigned)cfactor, mo, dy, yr, hh, mm,
358
                  (char)(G.pInfo->lcflag ? '^' : ' '),
359
                  (LPCSTR)fnfilter(G.filename, slide, (WSIZE>>1)),
360
                  (LPCSTR)methbuf, G.crec.crc32,
361
                  (char)((G.crec.general_purpose_bit_flag & 1) ? 'E' : ' '));
362
            else if (G.lpUserFunctions->SendApplicationMessage_i32 != NULL) {
363
                unsigned long ucsize_lo, csiz_lo;
364
                unsigned long ucsize_hi=0L, csiz_hi=0L;
365
                ucsize_lo = (unsigned long)(G.crec.ucsize);
366
                csiz_lo = (unsigned long)(csiz);
367
#ifdef ZIP64_SUPPORT
368
                ucsize_hi = (unsigned long)(G.crec.ucsize >> 32);
369
                csiz_hi = (unsigned long)(csiz >> 32);
370
#endif /* ZIP64_SUPPORT */
371
                (*G.lpUserFunctions->SendApplicationMessage_i32)(ucsize_lo,
372
                    ucsize_hi, csiz_lo, csiz_hi, (unsigned)cfactor,
373
                    mo, dy, yr, hh, mm,
374
                    (char)(G.pInfo->lcflag ? '^' : ' '),
375
                    (LPCSTR)fnfilter(G.filename, slide, (WSIZE>>1)),
376
                    (LPCSTR)methbuf, G.crec.crc32,
377
                    (char)((G.crec.general_purpose_bit_flag & 1) ? 'E' : ' '));
378
            }
379
#else /* !WINDLL */
380
            if (cfactor == 100)
381
                sprintf(cfactorstr, LoadFarString(CompFactor100));
382
            else
383
                sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
384
            if (longhdr)
385
                Info(slide, 0, ((char *)slide, LoadFarString(LongHdrStats),
386
                  FmZofft(G.crec.ucsize, "8", "u"), methbuf,
387
                  FmZofft(csiz, "8", "u"), cfactorstr,
388
                  mo, dt_sepchar, dy, dt_sepchar, yr, hh, mm,
389
                  G.crec.crc32, (G.pInfo->lcflag? '^':' ')));
390
            else
391
#ifdef OS2_EAS
392
                Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats),
393
                  FmZofft(G.crec.ucsize, "9", "u"), ea_size, acl_size,
394
                  mo, dt_sepchar, dy, dt_sepchar, yr, hh, mm,
395
                  (G.pInfo->lcflag? '^':' ')));
396
#else
397
                Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats),
398
                  FmZofft(G.crec.ucsize, "9", "u"),
399
                  mo, dt_sepchar, dy, dt_sepchar, yr, hh, mm,
400
                  (G.pInfo->lcflag? '^':' ')));
401
#endif
402
            fnprint(__G);
403
#endif /* ?WINDLL */
404
 
405
            if ((error = do_string(__G__ G.crec.file_comment_length,
406
                                   QCOND? DISPL_8 : SKIP)) != 0)
407
            {
408
                error_in_archive = error;  /* might be just warning */
409
                if (error > PK_WARN)       /* fatal */
410
                    return error;
411
            }
412
            tot_ucsize += G.crec.ucsize;
413
            tot_csize += csiz;
414
            ++members;
415
#ifdef OS2_EAS
416
            if (ea_size) {
417
                tot_easize += ea_size;
418
                ++tot_eafiles;
419
            }
420
            if (acl_size) {
421
                tot_aclsize += acl_size;
422
                ++tot_aclfiles;
423
            }
424
#endif
425
#ifdef OS2DLL
426
            } /* end of "if (G.processExternally) {...} else {..." */
427
#endif
428
        } else {        /* not listing this file */
429
            SKIP_(G.crec.file_comment_length)
430
        }
431
    } /* end for-loop (j: files in central directory) */
432
 
433
/*---------------------------------------------------------------------------
434
    Print footer line and totals (compressed size, uncompressed size, number
435
    of members in zipfile).
436
  ---------------------------------------------------------------------------*/
437
 
438
    if (uO.qflag < 2
439
#ifdef OS2DLL
440
                     && !G.processExternally
441
#endif
442
                                            ) {
443
        if ((cfactor = ratio(tot_ucsize, tot_csize)) < 0) {
444
#ifndef WINDLL
445
            sgn = '-';
446
#endif
447
            cfactor = (-cfactor + 5) / 10;
448
        } else {
449
#ifndef WINDLL
450
            sgn = ' ';
451
#endif
452
            cfactor = (cfactor + 5) / 10;
453
        }
454
#ifdef WINDLL
455
        /* pass the totals back to the calling application */
456
        G.lpUserFunctions->TotalSizeComp = tot_csize;
457
        G.lpUserFunctions->TotalSize = tot_ucsize;
458
        G.lpUserFunctions->CompFactor = (ulg)cfactor;
459
        G.lpUserFunctions->NumMembers = members;
460
 
461
#else /* !WINDLL */
462
        if (cfactor == 100)
463
            sprintf(cfactorstr, LoadFarString(CompFactor100));
464
        else
465
            sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
466
        if (longhdr) {
467
            Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer),
468
              FmZofft(tot_ucsize, "8", "u"), FmZofft(tot_csize, "8", "u"),
469
              cfactorstr, members, members==1? "":"s"));
470
#ifdef OS2_EAS
471
            if (tot_easize || tot_aclsize)
472
                Info(slide, 0, ((char *)slide, "\n"));
473
            if (tot_eafiles && tot_easize)
474
                Info(slide, 0, ((char *)slide, LoadFarString(OS2ExtAttrTrailer),
475
                  tot_eafiles, tot_eafiles == 1? " has" : "s have a total of",
476
                  tot_easize));
477
            if (tot_aclfiles && tot_aclsize)
478
                Info(slide, 0, ((char *)slide, LoadFarString(OS2ACLTrailer),
479
                  tot_aclfiles,
480
                  tot_aclfiles == 1 ? " has" : "s have a total of",
481
                  tot_aclsize));
482
#endif /* OS2_EAS */
483
        } else
484
#ifdef OS2_EAS
485
            Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer),
486
              FmZofft(tot_ucsize, "9", "u"), tot_easize, tot_aclsize,
487
              members, members == 1 ? "" : "s"));
488
#else
489
            Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer),
490
              FmZofft(tot_ucsize, "9", "u"),
491
              members, members == 1 ? "" : "s"));
492
#endif /* OS2_EAS */
493
#endif /* ?WINDLL */
494
    }
495
 
496
    /* Skip the following checks in case of a premature listing break. */
497
    if (error_in_archive <= PK_WARN) {
498
 
499
/*---------------------------------------------------------------------------
500
    Double check that we're back at the end-of-central-directory record.
501
  ---------------------------------------------------------------------------*/
502
 
503
        if ( (memcmp(G.sig,
504
                     (G.ecrec.have_ecr64 ?
505
                      end_central64_sig : end_central_sig),
506
                     4) != 0)
507
            && (!G.ecrec.is_zip64_archive)
508
            && (memcmp(G.sig, end_central_sig, 4) != 0)
509
           ) {          /* just to make sure again */
510
            Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
511
            error_in_archive = PK_WARN;   /* didn't find sig */
512
        }
513
 
514
        /* Set specific return code when no files have been found. */
515
        if (members == 0L && error_in_archive <= PK_WARN)
516
            error_in_archive = PK_FIND;
517
 
518
    }
519
 
520
    return error_in_archive;
521
 
522
} /* end function list_files() */
523
 
524
 
525
 
526
 
527
 
528
#ifdef TIMESTAMP
529
 
530
/************************/
531
/* Function fn_is_dir() */
532
/************************/
533
 
534
static int fn_is_dir(__G)    /* returns TRUE if G.filename is directory */
535
    __GDEF
536
{
537
    extent fn_len = strlen(G.filename);
538
    register char   endc;
539
 
540
    return  fn_len > 0 &&
541
            ((endc = lastchar(G.filename, fn_len)) == '/' ||
542
             (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/') &&
543
              endc == '\\'));
544
}
545
 
546
 
547
 
548
 
549
 
550
/*****************************/
551
/* Function get_time_stamp() */
552
/*****************************/
553
 
554
int get_time_stamp(__G__ last_modtime, nmember)  /* return PK-type error code */
555
    __GDEF
556
    time_t *last_modtime;
557
    ulg *nmember;
558
{
559
    int do_this_file=FALSE, error, error_in_archive=PK_COOL;
560
    ulg j;
561
#ifdef USE_EF_UT_TIME
562
    iztimes z_utime;
563
#endif
564
    min_info info;
565
 
566
 
567
/*---------------------------------------------------------------------------
568
    Unlike extract_or_test_files() but like list_files(), this function works
569
    on information in the central directory alone.  Thus we have a single,
570
    large loop through the entire directory, searching for the latest time
571
    stamp.
572
  ---------------------------------------------------------------------------*/
573
 
574
    *last_modtime = 0L;         /* assuming no zipfile data older than 1970 */
575
    *nmember = 0L;
576
    G.pInfo = &info;
577
 
578
    for (j = 1L;; j++) {
579
 
580
        if (readbuf(__G__ G.sig, 4) == 0)
581
            return PK_EOF;
582
        if (memcmp(G.sig, central_hdr_sig, 4)) {  /* is it a CentDir entry? */
583
            if (((unsigned)(j - 1) & (unsigned)0xFFFF) ==
584
                (unsigned)G.ecrec.total_entries_central_dir) {
585
                /* "j modulus 64k" matches the reported 16-bit-unsigned
586
                 * number of directory entries -> probably, the regular
587
                 * end of the central directory has been reached
588
                 */
589
                break;
590
            } else {
591
                Info(slide, 0x401,
592
                     ((char *)slide, LoadFarString(CentSigMsg), j));
593
                Info(slide, 0x401,
594
                     ((char *)slide, LoadFarString(ReportMsg)));
595
                return PK_BADERR;   /* sig not found */
596
            }
597
        }
598
        /* process_cdir_file_hdr() sets pInfo->lcflag: */
599
        if ((error = process_cdir_file_hdr(__G)) != PK_COOL)
600
            return error;       /* only PK_EOF defined */
601
        if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) != PK_OK)
602
        {        /*  ^-- (uses pInfo->lcflag) */
603
            error_in_archive = error;
604
            if (error > PK_WARN)   /* fatal:  can't continue */
605
                return error;
606
        }
607
        if (G.extra_field != (uch *)NULL) {
608
            free(G.extra_field);
609
            G.extra_field = (uch *)NULL;
610
        }
611
        if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD))
612
            != 0)
613
        {
614
            error_in_archive = error;
615
            if (error > PK_WARN)      /* fatal */
616
                return error;
617
        }
618
        if (!G.process_all_files) {   /* check if specified on command line */
619
            unsigned i;
620
 
621
            if (G.filespecs == 0)
622
                do_this_file = TRUE;
623
            else {  /* check if this entry matches an `include' argument */
624
                do_this_file = FALSE;
625
                for (i = 0; i < G.filespecs; i++)
626
                    if (match(G.filename, G.pfnames[i], uO.C_flag WISEP)) {
627
                        do_this_file = TRUE;
628
                        break;       /* found match, so stop looping */
629
                    }
630
            }
631
            if (do_this_file) {  /* check if this is an excluded file */
632
                for (i = 0; i < G.xfilespecs; i++)
633
                    if (match(G.filename, G.pxnames[i], uO.C_flag WISEP)) {
634
                        do_this_file = FALSE;  /* ^-- ignore case in match */
635
                        break;
636
                    }
637
            }
638
        }
639
 
640
        /* If current file was specified on command line, or if no names were
641
         * specified, check the time for this file.  Either way, get rid of the
642
         * file comment and go back for the next file.
643
         * Directory entries are always ignored, to stay compatible with both
644
         * Zip and PKZIP.
645
         */
646
        if ((G.process_all_files || do_this_file) && !fn_is_dir(__G)) {
647
#ifdef USE_EF_UT_TIME
648
            if (G.extra_field &&
649
#ifdef IZ_CHECK_TZ
650
                G.tz_is_valid &&
651
#endif
652
                (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1,
653
                                  G.crec.last_mod_dos_datetime, &z_utime, NULL)
654
                 & EB_UT_FL_MTIME))
655
            {
656
                if (*last_modtime < z_utime.mtime)
657
                    *last_modtime = z_utime.mtime;
658
            } else
659
#endif /* USE_EF_UT_TIME */
660
            {
661
                time_t modtime = dos_to_unix_time(G.crec.last_mod_dos_datetime);
662
 
663
                if (*last_modtime < modtime)
664
                    *last_modtime = modtime;
665
            }
666
            ++*nmember;
667
        }
668
        SKIP_(G.crec.file_comment_length)
669
 
670
    } /* end for-loop (j: files in central directory) */
671
 
672
/*---------------------------------------------------------------------------
673
    Double check that we're back at the end-of-central-directory record.
674
  ---------------------------------------------------------------------------*/
675
 
676
    if (memcmp(G.sig, end_central_sig, 4)) {    /* just to make sure again */
677
        Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
678
        error_in_archive = PK_WARN;
679
    }
680
    if (*nmember == 0L && error_in_archive <= PK_WARN)
681
        error_in_archive = PK_FIND;
682
 
683
    return error_in_archive;
684
 
685
} /* end function get_time_stamp() */
686
 
687
#endif /* TIMESTAMP */
688
 
689
 
690
 
691
 
692
 
693
/********************/
694
/* Function ratio() */    /* also used by ZipInfo routines */
695
/********************/
696
 
697
int ratio(uc, c)
698
    zusz_t uc, c;
699
{
700
    zusz_t denom;
701
 
702
    if (uc == 0)
703
        return 0;
704
    if (uc > 2000000L) {    /* risk signed overflow if multiply numerator */
705
        denom = uc / 1000L;
706
        return ((uc >= c) ?
707
            (int) ((uc-c + (denom>>1)) / denom) :
708
          -((int) ((c-uc + (denom>>1)) / denom)));
709
    } else {             /* ^^^^^^^^ rounding */
710
        denom = uc;
711
        return ((uc >= c) ?
712
            (int) ((1000L*(uc-c) + (denom>>1)) / denom) :
713
          -((int) ((1000L*(c-uc) + (denom>>1)) / denom)));
714
    }                            /* ^^^^^^^^ rounding */
715
}
716
 
717
 
718
 
719
 
720
 
721
/************************/
722
/*  Function fnprint()  */    /* also used by ZipInfo routines */
723
/************************/
724
 
725
void fnprint(__G)    /* print filename (after filtering) and newline */
726
    __GDEF
727
{
728
    char *name = fnfilter(G.filename, slide, (extent)(WSIZE>>1));
729
 
730
    (*G.message)((zvoid *)&G, (uch *)name, (ulg)strlen(name), 0);
731
    (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0);
732
 
733
} /* end function fnprint() */