2
Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
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
9
/*---------------------------------------------------------------------------
13
This file contains the non-ZipInfo-specific listing routines for UnZip.
15
Contains: list_files()
16
get_time_stamp() [optional feature]
20
---------------------------------------------------------------------------*/
23
#define UNZIP_INTERNAL
27
# include "wince/intrface.h"
29
# include "windll/windll.h"
35
static int fn_is_dir OF((__GPRO));
39
static ZCONST char Far CompFactorStr[] = "%c%d%%";
40
static ZCONST char Far CompFactor100[] = "100%%";
43
static ZCONST char Far HeadersS[] =
44
" Length EAs ACLs Date Time Name";
45
static ZCONST char Far HeadersS1[] =
46
" -------- --- ---- ---- ---- ----";
48
static ZCONST char Far HeadersS[] = " Length Date Time Name";
49
static ZCONST char Far HeadersS1[] = " -------- ---- ---- ----";
52
static ZCONST char Far HeadersL[] =
53
" Length Method Size Ratio Date Time CRC-32 Name";
54
static ZCONST char Far HeadersL1[] =
55
"-------- ------ ------- ----- ---- ---- ------ ----";
56
static ZCONST char Far *Headers[][2] =
57
{ {HeadersS, HeadersS1}, {HeadersL, HeadersL1} };
59
static ZCONST char Far CaseConversion[] =
60
"%s (\"^\" ==> case\n%s conversion)\n";
61
static ZCONST char Far LongHdrStats[] =
62
"%8lu %-7s%8lu %4s %02u-%02u-%02u %02u:%02u %08lx %c";
63
static ZCONST char Far LongFileTrailer[] =
64
"-------- ------- --- \
65
-------\n%8lu %8lu %4s %lu file%s\n";
67
static ZCONST char Far ShortHdrStats[] =
68
"%9lu %6lu %6lu %02u-%02u-%02u %02u:%02u %c";
69
static ZCONST char Far ShortFileTrailer[] = " -------- ----- ----- \
70
-------\n%9lu %6lu %6lu %lu file%s\n";
71
static ZCONST char Far OS2ExtAttrTrailer[] =
72
"%lu file%s %lu bytes of OS/2 extended attributes attached.\n";
73
static ZCONST char Far OS2ACLTrailer[] =
74
"%lu file%s %lu bytes of access control lists attached.\n";
76
static ZCONST char Far ShortHdrStats[] =
77
"%9lu %02u-%02u-%02u %02u:%02u %c";
78
static ZCONST char Far ShortFileTrailer[] = " -------- \
79
-------\n%9lu %lu file%s\n";
87
/*************************/
88
/* Function list_files() */
89
/*************************/
91
int list_files(__G) /* return PK-type error code */
94
int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL;
96
char sgn, cfactorstr[10];
97
int longhdr=(uO.vflag>1);
102
#ifdef USE_EF_UT_TIME
106
unsigned yr, mo, dy, hh, mm;
107
ulg csiz, tot_csize=0L, tot_ucsize=0L;
109
ulg ea_size, tot_easize=0L, tot_eafiles=0L;
110
ulg acl_size, tot_aclsize=0L, tot_aclfiles=0L;
114
static ZCONST char dtype[]="NXFS"; /* see zi_short() */
115
static ZCONST char Far method[NUM_METHODS+1][8] =
116
{"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4",
117
"Implode", "Token", "Defl:#", "Def64#", "ImplDCL", "Unk:###"};
121
/*---------------------------------------------------------------------------
122
Unlike extract_or_test_files(), this routine confines itself to the cen-
123
tral directory. Thus its structure is somewhat simpler, since we can do
124
just a single loop through the entire directory, listing files as we go.
126
So to start off, print the heading line and then begin main loop through
127
the central directory. The results will look vaguely like the following:
129
Length Method Size Ratio Date Time CRC-32 Name ("^" ==> case
130
-------- ------ ------- ----- ---- ---- ------ ---- conversion)
131
44004 Implode 13041 71% 11-02-89 19:34 8b4207f7 Makefile.UNIX
132
3438 Shrunk 2209 36% 09-15-90 14:07 a2394fd8 ^dos-file.ext
133
16717 Defl:X 5252 69% 11-03-97 06:40 1ce0f189 WHERE
134
-------- ------- --- -------
135
64159 20502 68% 3 files
136
---------------------------------------------------------------------------*/
139
date_format = DATE_FORMAT;
144
Info(slide, 0, ((char *)slide, LoadFarString(CaseConversion),
145
LoadFarStringSmall(Headers[longhdr][0]),
146
LoadFarStringSmall2(Headers[longhdr][1])));
148
Info(slide, 0, ((char *)slide, "%s\n%s\n",
149
LoadFarString(Headers[longhdr][0]),
150
LoadFarStringSmall(Headers[longhdr][1])));
156
if (readbuf(__G__ G.sig, 4) == 0)
158
if (strncmp(G.sig, central_hdr_sig, 4)) { /* is it a CentDir entry? */
159
if (((unsigned)(j - 1) & (unsigned)0xFFFF) ==
160
(unsigned)G.ecrec.total_entries_central_dir) {
161
/* "j modulus 64k" matches the reported 16-bit-unsigned
162
* number of directory entries -> probably, the regular
163
* end of the central directory has been reached
168
((char *)slide, LoadFarString(CentSigMsg), j));
170
((char *)slide, LoadFarString(ReportMsg)));
171
return PK_BADERR; /* sig not found */
174
/* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag, ...: */
175
if ((error = process_cdir_file_hdr(__G)) != PK_COOL)
176
return error; /* only PK_EOF defined */
179
* We could DISPLAY the filename instead of storing (and possibly trun-
180
* cating, in the case of a very long name) and printing it, but that
181
* has the disadvantage of not allowing case conversion--and it's nice
182
* to be able to see in the listing precisely how you have to type each
183
* filename in order for unzip to consider it a match. Speaking of
184
* which, if member names were specified on the command line, check in
185
* with match() to see if the current file is one of them, and make a
186
* note of it if it is.
189
if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) !=
190
PK_COOL) /* ^--(uses pInfo->lcflag) */
192
error_in_archive = error;
193
if (error > PK_WARN) /* fatal: can't continue */
196
if (G.extra_field != (uch *)NULL) {
198
G.extra_field = (uch *)NULL;
200
if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD))
203
error_in_archive = error;
204
if (error > PK_WARN) /* fatal */
207
if (!G.process_all_files) { /* check if specified on command line */
210
do_this_file = FALSE;
211
for (i = 0; i < G.filespecs; i++)
212
if (match(G.filename, G.pfnames[i], uO.C_flag)) {
214
break; /* found match, so stop looping */
216
if (do_this_file) { /* check if this is an excluded file */
217
for (i = 0; i < G.xfilespecs; i++)
218
if (match(G.filename, G.pxnames[i], uO.C_flag)) {
219
do_this_file = FALSE; /* ^-- ignore case in match */
225
* If current file was specified on command line, or if no names were
226
* specified, do the listing for this file. Otherwise, get rid of the
227
* file comment and go back for the next file.
230
if (G.process_all_files || do_this_file) {
233
/* this is used by UzpFileTree() to allow easy processing of lists
234
* of zip directory contents */
235
if (G.processExternally) {
236
if ((G.processExternally)(G.filename, &G.crec))
243
uch *ef_ptr = G.extra_field;
244
int ef_size, ef_len = G.crec.extra_field_length;
245
ea_size = acl_size = 0;
247
while (ef_len >= EB_HEADSIZE) {
248
ef_size = makeword(&ef_ptr[EB_LEN]);
249
switch (makeword(&ef_ptr[EB_ID])) {
251
ea_size = makelong(&ef_ptr[EB_HEADSIZE]);
254
acl_size = makelong(&ef_ptr[EB_HEADSIZE]);
257
ef_ptr += (ef_size + EB_HEADSIZE);
258
ef_len -= (ef_size + EB_HEADSIZE);
262
#ifdef USE_EF_UT_TIME
267
(ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1,
268
G.crec.last_mod_dos_datetime, &z_utime, NULL)
271
TIMET_TO_NATIVE(z_utime.mtime) /* NOP unless MSC 7.0, Mac */
272
t = localtime(&(z_utime.mtime));
274
t = (struct tm *)NULL;
275
if (t != (struct tm *)NULL) {
276
mo = (unsigned)(t->tm_mon + 1);
277
dy = (unsigned)(t->tm_mday);
278
yr = (unsigned)(t->tm_year % 100);
279
hh = (unsigned)(t->tm_hour);
280
mm = (unsigned)(t->tm_min);
282
#endif /* USE_EF_UT_TIME */
284
yr = ((((unsigned)(G.crec.last_mod_dos_datetime >> 25) & 0x7f)
285
+ 80) % (unsigned)100);
286
mo = ((unsigned)(G.crec.last_mod_dos_datetime >> 21) & 0x0f);
287
dy = ((unsigned)(G.crec.last_mod_dos_datetime >> 16) & 0x1f);
288
hh = (((unsigned)G.crec.last_mod_dos_datetime >> 11) & 0x1f);
289
mm = (((unsigned)G.crec.last_mod_dos_datetime >> 5) & 0x3f);
291
/* permute date so it displays according to nat'l convention
292
* ('methnum' is not yet set, it is used as temporary buffer) */
293
switch (date_format) {
296
mo = yr; yr = dy; dy = methnum;
300
mo = dy; dy = methnum;
304
if (G.crec.general_purpose_bit_flag & 1)
305
csiz -= 12; /* if encrypted, don't count encryption header */
306
if ((cfactor = ratio(G.crec.ucsize, csiz)) < 0) {
310
cfactor = (-cfactor + 5) / 10;
315
cfactor = (cfactor + 5) / 10;
318
methnum = MIN(G.crec.compression_method, NUM_METHODS);
319
zfstrcpy(methbuf, method[methnum]);
320
if (methnum == DEFLATED || methnum == ENHDEFLATED) {
321
methbuf[5] = dtype[(G.crec.general_purpose_bit_flag>>1) & 3];
322
} else if (methnum >= NUM_METHODS) {
323
sprintf(&methbuf[4], "%03u", G.crec.compression_method);
326
#if 0 /* GRR/Euro: add this? */
327
#if defined(DOS_FLX_NLM_OS2_W32) || defined(THEOS) || defined(UNIX)
328
for (p = G.filename; *p; ++p)
330
*p = '?'; /* change non-printable chars to '?' */
331
#endif /* DOS_FLX_NLM_OS2_W32 || THEOS || UNIX */
335
/* send data to application for formatting and printing */
336
(*G.lpUserFunctions->SendApplicationMessage)(G.crec.ucsize, csiz,
337
(unsigned)cfactor, mo, dy, yr, hh, mm,
338
(char)(G.pInfo->lcflag ? '^' : ' '),
339
(LPSTR)fnfilter(G.filename, slide), (LPSTR)methbuf, G.crec.crc32,
340
(char)((G.crec.general_purpose_bit_flag & 1) ? 'E' : ' '));
343
sprintf(cfactorstr, LoadFarString(CompFactor100));
345
sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
347
Info(slide, 0, ((char *)slide, LoadFarString(LongHdrStats),
348
G.crec.ucsize, methbuf, csiz, cfactorstr, mo, dy,
349
yr, hh, mm, G.crec.crc32, (G.pInfo->lcflag? '^':' ')));
352
Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats),
353
G.crec.ucsize, ea_size, acl_size,
354
mo, dy, yr, hh, mm, (G.pInfo->lcflag? '^':' ')));
356
Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats),
358
mo, dy, yr, hh, mm, (G.pInfo->lcflag? '^':' ')));
363
if ((error = do_string(__G__ G.crec.file_comment_length,
364
QCOND? DISPL_8 : SKIP)) != 0)
366
error_in_archive = error; /* might be just warning */
367
if (error > PK_WARN) /* fatal */
370
tot_ucsize += G.crec.ucsize;
375
tot_easize += ea_size;
379
tot_aclsize += acl_size;
384
} /* end of "if (G.processExternally) {...} else {..." */
386
} else { /* not listing this file */
387
SKIP_(G.crec.file_comment_length)
389
} /* end for-loop (j: files in central directory) */
391
/*---------------------------------------------------------------------------
392
Print footer line and totals (compressed size, uncompressed size, number
393
of members in zipfile).
394
---------------------------------------------------------------------------*/
398
&& !G.processExternally
401
if ((cfactor = ratio(tot_ucsize, tot_csize)) < 0) {
405
cfactor = (-cfactor + 5) / 10;
410
cfactor = (cfactor + 5) / 10;
413
/* pass the totals back to the calling application */
414
G.lpUserFunctions->TotalSizeComp = tot_csize;
415
G.lpUserFunctions->TotalSize = tot_ucsize;
416
G.lpUserFunctions->CompFactor = (ulg)cfactor;
417
G.lpUserFunctions->NumMembers = members;
421
sprintf(cfactorstr, LoadFarString(CompFactor100));
423
sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
425
Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer),
426
tot_ucsize, tot_csize, cfactorstr, members, members==1? "":"s"));
428
if (tot_easize || tot_aclsize)
429
Info(slide, 0, ((char *)slide, "\n"));
430
if (tot_eafiles && tot_easize)
431
Info(slide, 0, ((char *)slide, LoadFarString(OS2ExtAttrTrailer),
432
tot_eafiles, tot_eafiles == 1? " has" : "s have a total of",
434
if (tot_aclfiles && tot_aclsize)
435
Info(slide, 0, ((char *)slide, LoadFarString(OS2ACLTrailer),
436
tot_aclfiles, tot_aclfiles == 1? " has" : "s have a total of",
441
Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer),
442
tot_ucsize, tot_easize, tot_aclsize, members, members == 1?
445
Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer),
446
tot_ucsize, members, members == 1? "" : "s"));
451
/*---------------------------------------------------------------------------
452
Double check that we're back at the end-of-central-directory record.
453
---------------------------------------------------------------------------*/
455
if (strncmp(G.sig, end_central_sig, 4)) { /* just to make sure again */
456
Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
457
error_in_archive = PK_WARN; /* didn't find sig */
459
if (members == 0L && error_in_archive <= PK_WARN)
460
error_in_archive = PK_FIND;
462
return error_in_archive;
464
} /* end function list_files() */
472
/************************/
473
/* Function fn_is_dir() */
474
/************************/
476
static int fn_is_dir(__G) /* returns TRUE if G.filename is directory */
479
extent fn_len = strlen(G.filename);
483
((endc = lastchar(G.filename, fn_len)) == '/' ||
484
(G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/') &&
492
/*****************************/
493
/* Function get_time_stamp() */
494
/*****************************/
496
int get_time_stamp(__G__ last_modtime, nmember) /* return PK-type error code */
498
time_t *last_modtime;
501
int do_this_file=FALSE, error, error_in_archive=PK_COOL;
503
#ifdef USE_EF_UT_TIME
509
/*---------------------------------------------------------------------------
510
Unlike extract_or_test_files() but like list_files(), this function works
511
on information in the central directory alone. Thus we have a single,
512
large loop through the entire directory, searching for the latest time
514
---------------------------------------------------------------------------*/
516
*last_modtime = 0L; /* assuming no zipfile data older than 1970 */
522
if (readbuf(__G__ G.sig, 4) == 0)
524
if (strncmp(G.sig, central_hdr_sig, 4)) { /* is it a CentDir entry? */
525
if (((unsigned)(j - 1) & (unsigned)0xFFFF) ==
526
(unsigned)G.ecrec.total_entries_central_dir) {
527
/* "j modulus 64k" matches the reported 16-bit-unsigned
528
* number of directory entries -> probably, the regular
529
* end of the central directory has been reached
534
((char *)slide, LoadFarString(CentSigMsg), j));
536
((char *)slide, LoadFarString(ReportMsg)));
537
return PK_BADERR; /* sig not found */
540
/* process_cdir_file_hdr() sets pInfo->lcflag: */
541
if ((error = process_cdir_file_hdr(__G)) != PK_COOL)
542
return error; /* only PK_EOF defined */
543
if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) != PK_OK)
544
{ /* ^-- (uses pInfo->lcflag) */
545
error_in_archive = error;
546
if (error > PK_WARN) /* fatal: can't continue */
549
if (G.extra_field != (uch *)NULL) {
551
G.extra_field = (uch *)NULL;
553
if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD))
556
error_in_archive = error;
557
if (error > PK_WARN) /* fatal */
560
if (!G.process_all_files) { /* check if specified on command line */
563
do_this_file = FALSE;
564
for (i = 0; i < G.filespecs; i++)
565
if (match(G.filename, G.pfnames[i], uO.C_flag)) {
567
break; /* found match, so stop looping */
569
if (do_this_file) { /* check if this is an excluded file */
570
for (i = 0; i < G.xfilespecs; i++)
571
if (match(G.filename, G.pxnames[i], uO.C_flag)) {
572
do_this_file = FALSE; /* ^-- ignore case in match */
578
/* If current file was specified on command line, or if no names were
579
* specified, check the time for this file. Either way, get rid of the
580
* file comment and go back for the next file.
581
* Directory entries are always ignored, to stay compatible with both
584
if ((G.process_all_files || do_this_file) && !fn_is_dir(__G)) {
585
#ifdef USE_EF_UT_TIME
590
(ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1,
591
G.crec.last_mod_dos_datetime, &z_utime, NULL)
594
if (*last_modtime < z_utime.mtime)
595
*last_modtime = z_utime.mtime;
597
#endif /* USE_EF_UT_TIME */
599
time_t modtime = dos_to_unix_time(G.crec.last_mod_dos_datetime);
601
if (*last_modtime < modtime)
602
*last_modtime = modtime;
606
SKIP_(G.crec.file_comment_length)
608
} /* end for-loop (j: files in central directory) */
610
/*---------------------------------------------------------------------------
611
Double check that we're back at the end-of-central-directory record.
612
---------------------------------------------------------------------------*/
614
if (strncmp(G.sig, end_central_sig, 4)) { /* just to make sure again */
615
Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
616
error_in_archive = PK_WARN;
618
if (*nmember == 0L && error_in_archive <= PK_WARN)
619
error_in_archive = PK_FIND;
621
return error_in_archive;
623
} /* end function get_time_stamp() */
625
#endif /* TIMESTAMP */
631
/********************/
632
/* Function ratio() */ /* also used by ZipInfo routines */
633
/********************/
642
if (uc > 2000000L) { /* risk signed overflow if multiply numerator */
645
(int) ((uc-c + (denom>>1)) / denom) :
646
-((int) ((c-uc + (denom>>1)) / denom)));
647
} else { /* ^^^^^^^^ rounding */
650
(int) ((1000L*(uc-c) + (denom>>1)) / denom) :
651
-((int) ((1000L*(c-uc) + (denom>>1)) / denom)));
652
} /* ^^^^^^^^ rounding */
659
/************************/
660
/* Function fnprint() */ /* also used by ZipInfo routines */
661
/************************/
663
void fnprint(__G) /* print filename (after filtering) and newline */
666
char *name = fnfilter(G.filename, slide);
668
(*G.message)((zvoid *)&G, (uch *)name, (ulg)strlen(name), 0);
669
(*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0);
671
} /* end function fnprint() */
673
const char *BOINC_RCSID_670c4eb825 = "$Id: list.c 4979 2005-01-02 18:29:53Z ballen $";