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