1 /* 2 Copyright (c) 1990-2001 Info-ZIP. All rights reserved. 3 4 See the accompanying file LICENSE, version 2000-Apr-09 or later 5 (the contents of which are also included in unzip.h) for terms of use. 6 If, for some reason, all these files are missing, the Info-ZIP license 7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html 8 */ 9 /*--------------------------------------------------------------------------- 10 11 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[] = " Length Date Time Name"; 49 static ZCONST char Far HeadersS1[] = " -------- ---- ---- ----"; 50 #endif 51 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} }; 58 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"; 66 #ifdef OS2_EAS 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"; 75 #else 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"; 80 #endif /* ?OS2_EAS */ 81 #endif /* !WINDLL */ 82 83 84 85 86 87 /*************************/ 88 /* Function list_files() */ 89 /*************************/ 90 91 int list_files(__G) /* return PK-type error code */ 92 __GDEF 93 { 94 int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL; 95 #ifndef WINDLL 96 char sgn, cfactorstr[10]; 97 int longhdr=(uO.vflag>1); 98 #endif 99 int date_format; 100 ulg j, members=0L; 101 unsigned methnum; 102 #ifdef USE_EF_UT_TIME 103 iztimes z_utime; 104 struct tm *t; 105 #endif 106 unsigned yr, mo, dy, hh, mm; 107 ulg csiz, tot_csize=0L, tot_ucsize=0L; 108 #ifdef OS2_EAS 109 ulg ea_size, tot_easize=0L, tot_eafiles=0L; 110 ulg acl_size, tot_aclsize=0L, tot_aclfiles=0L; 111 #endif 112 min_info info; 113 char methbuf[8]; 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:###"}; 118 119 120 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. 125 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: 128 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 ---------------------------------------------------------------------------*/ 137 138 G.pInfo = &info; 139 date_format = DATE_FORMAT; 140 141 #ifndef WINDLL 142 if (uO.qflag < 2) { 143 if (uO.L_flag) 144 Info(slide, 0, ((char *)slide, LoadFarString(CaseConversion), 145 LoadFarStringSmall(Headers[longhdr][0]), 146 LoadFarStringSmall2(Headers[longhdr][1]))); 147 else 148 Info(slide, 0, ((char *)slide, "%s\n%s\n", 149 LoadFarString(Headers[longhdr][0]), 150 LoadFarStringSmall(Headers[longhdr][1]))); 151 } 152 #endif /* !WINDLL */ 153 154 for (j = 1L;;j++) { 155 156 if (readbuf(__G__ G.sig, 4) == 0) 157 return PK_EOF; 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 164 */ 165 break; 166 } else { 167 Info(slide, 0x401, 168 ((char *)slide, LoadFarString(CentSigMsg), j)); 169 Info(slide, 0x401, 170 ((char *)slide, LoadFarString(ReportMsg))); 171 return PK_BADERR; /* sig not found */ 172 } 173 } 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 */ 177 178 /* 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. 187 */ 188 189 if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) != 190 PK_COOL) /* ^--(uses pInfo->lcflag) */ 191 { 192 error_in_archive = error; 193 if (error > PK_WARN) /* fatal: can't continue */ 194 return error; 195 } 196 if (G.extra_field != (uch *)NULL) { 197 free(G.extra_field); 198 G.extra_field = (uch *)NULL; 199 } 200 if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD)) 201 != 0) 202 { 203 error_in_archive = error; 204 if (error > PK_WARN) /* fatal */ 205 return error; 206 } 207 if (!G.process_all_files) { /* check if specified on command line */ 208 unsigned i; 209 210 do_this_file = FALSE; 211 for (i = 0; i < G.filespecs; i++) 212 if (match(G.filename, G.pfnames[i], uO.C_flag)) { 213 do_this_file = TRUE; 214 break; /* found match, so stop looping */ 215 } 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 */ 220 break; 221 } 222 } 223 } 224 /* 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. 228 */ 229 230 if (G.process_all_files || do_this_file) { 231 232 #ifdef OS2DLL 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)) 237 break; 238 ++members; 239 } else { 240 #endif 241 #ifdef OS2_EAS 242 { 243 uch *ef_ptr = G.extra_field; 244 int ef_size, ef_len = G.crec.extra_field_length; 245 ea_size = acl_size = 0; 246 247 while (ef_len >= EB_HEADSIZE) { 248 ef_size = makeword(&ef_ptr[EB_LEN]); 249 switch (makeword(&ef_ptr[EB_ID])) { 250 case EF_OS2: 251 ea_size = makelong(&ef_ptr[EB_HEADSIZE]); 252 break; 253 case EF_ACL: 254 acl_size = makelong(&ef_ptr[EB_HEADSIZE]); 255 break; 256 } 257 ef_ptr += (ef_size + EB_HEADSIZE); 258 ef_len -= (ef_size + EB_HEADSIZE); 259 } 260 } 261 #endif 262 #ifdef USE_EF_UT_TIME 263 if (G.extra_field && 264 #ifdef IZ_CHECK_TZ 265 G.tz_is_valid && 266 #endif 267 (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1, 268 G.crec.last_mod_dos_datetime, &z_utime, NULL) 269 & EB_UT_FL_MTIME)) 270 { 271 TIMET_TO_NATIVE(z_utime.mtime) /* NOP unless MSC 7.0, Mac */ 272 t = localtime(&(z_utime.mtime)); 273 } else 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); 281 } else 282 #endif /* USE_EF_UT_TIME */ 283 { 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); 290 } 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) { 294 case DF_YMD: 295 methnum = mo; 296 mo = yr; yr = dy; dy = methnum; 297 break; 298 case DF_DMY: 299 methnum = mo; 300 mo = dy; dy = methnum; 301 } 302 303 csiz = G.crec.csize; 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) { 307 #ifndef WINDLL 308 sgn = '-'; 309 #endif 310 cfactor = (-cfactor + 5) / 10; 311 } else { 312 #ifndef WINDLL 313 sgn = ' '; 314 #endif 315 cfactor = (cfactor + 5) / 10; 316 } 317 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); 324 } 325 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) 329 if (!isprint(*p)) 330 *p = '?'; /* change non-printable chars to '?' */ 331 #endif /* DOS_FLX_NLM_OS2_W32 || THEOS || UNIX */ 332 #endif /* 0 */ 333 334 #ifdef WINDLL 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' : ' ')); 341 #else /* !WINDLL */ 342 if (cfactor == 100) 343 sprintf(cfactorstr, LoadFarString(CompFactor100)); 344 else 345 sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor); 346 if (longhdr) 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? '^':' '))); 350 else 351 #ifdef OS2_EAS 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? '^':' '))); 355 #else 356 Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats), 357 G.crec.ucsize, 358 mo, dy, yr, hh, mm, (G.pInfo->lcflag? '^':' '))); 359 #endif 360 fnprint(__G); 361 #endif /* ?WINDLL */ 362 363 if ((error = do_string(__G__ G.crec.file_comment_length, 364 QCOND? DISPL_8 : SKIP)) != 0) 365 { 366 error_in_archive = error; /* might be just warning */ 367 if (error > PK_WARN) /* fatal */ 368 return error; 369 } 370 tot_ucsize += G.crec.ucsize; 371 tot_csize += csiz; 372 ++members; 373 #ifdef OS2_EAS 374 if (ea_size) { 375 tot_easize += ea_size; 376 ++tot_eafiles; 377 } 378 if (acl_size) { 379 tot_aclsize += acl_size; 380 ++tot_aclfiles; 381 } 382 #endif 383 #ifdef OS2DLL 384 } /* end of "if (G.processExternally) {...} else {..." */ 385 #endif 386 } else { /* not listing this file */ 387 SKIP_(G.crec.file_comment_length) 388 } 389 } /* end for-loop (j: files in central directory) */ 390 391 /*--------------------------------------------------------------------------- 392 Print footer line and totals (compressed size, uncompressed size, number 393 of members in zipfile). 394 ---------------------------------------------------------------------------*/ 395 396 if (uO.qflag < 2 397 #ifdef OS2DLL 398 && !G.processExternally 399 #endif 400 ) { 401 if ((cfactor = ratio(tot_ucsize, tot_csize)) < 0) { 402 #ifndef WINDLL 403 sgn = '-'; 404 #endif 405 cfactor = (-cfactor + 5) / 10; 406 } else { 407 #ifndef WINDLL 408 sgn = ' '; 409 #endif 410 cfactor = (cfactor + 5) / 10; 411 } 412 #ifdef WINDLL 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; 418 419 #else /* !WINDLL */ 420 if (cfactor == 100) 421 sprintf(cfactorstr, LoadFarString(CompFactor100)); 422 else 423 sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor); 424 if (longhdr) { 425 Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer), 426 tot_ucsize, tot_csize, cfactorstr, members, members==1? "":"s")); 427 #ifdef OS2_EAS 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", 433 tot_easize)); 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", 437 tot_aclsize)); 438 #endif /* OS2_EAS */ 439 } else 440 #ifdef OS2_EAS 441 Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer), 442 tot_ucsize, tot_easize, tot_aclsize, members, members == 1? 443 "" : "s")); 444 #else 445 Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer), 446 tot_ucsize, members, members == 1? "" : "s")); 447 #endif /* OS2_EAS */ 448 #endif /* ?WINDLL */ 449 } 450 451 /*--------------------------------------------------------------------------- 452 Double check that we're back at the end-of-central-directory record. 453 ---------------------------------------------------------------------------*/ 454 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 */ 458 } 459 if (members == 0L && error_in_archive <= PK_WARN) 460 error_in_archive = PK_FIND; 461 462 return error_in_archive; 463 464 } /* end function list_files() */ 465 466 467 468 469 470 #ifdef TIMESTAMP 471 472 /************************/ 473 /* Function fn_is_dir() */ 474 /************************/ 475 476 static int fn_is_dir(__G) /* returns TRUE if G.filename is directory */ 477 __GDEF 478 { 479 extent fn_len = strlen(G.filename); 480 register char endc; 481 482 return fn_len > 0 && 483 ((endc = lastchar(G.filename, fn_len)) == '/' || 484 (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/') && 485 endc == '\\')); 486 } 487 488 489 490 491 492 /*****************************/ 493 /* Function get_time_stamp() */ 494 /*****************************/ 495 496 int get_time_stamp(__G__ last_modtime, nmember) /* return PK-type error code */ 497 __GDEF 498 time_t *last_modtime; 499 ulg *nmember; 500 { 501 int do_this_file=FALSE, error, error_in_archive=PK_COOL; 502 ulg j; 503 #ifdef USE_EF_UT_TIME 504 iztimes z_utime; 505 #endif 506 min_info info; 507 508 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 513 stamp. 514 ---------------------------------------------------------------------------*/ 515 516 *last_modtime = 0L; /* assuming no zipfile data older than 1970 */ 517 *nmember = 0L; 518 G.pInfo = &info; 519 520 for (j = 1L;; j++) { 521 522 if (readbuf(__G__ G.sig, 4) == 0) 523 return PK_EOF; 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 530 */ 531 break; 532 } else { 533 Info(slide, 0x401, 534 ((char *)slide, LoadFarString(CentSigMsg), j)); 535 Info(slide, 0x401, 536 ((char *)slide, LoadFarString(ReportMsg))); 537 return PK_BADERR; /* sig not found */ 538 } 539 } 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 */ 547 return error; 548 } 549 if (G.extra_field != (uch *)NULL) { 550 free(G.extra_field); 551 G.extra_field = (uch *)NULL; 552 } 553 if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD)) 554 != 0) 555 { 556 error_in_archive = error; 557 if (error > PK_WARN) /* fatal */ 558 return error; 559 } 560 if (!G.process_all_files) { /* check if specified on command line */ 561 unsigned i; 562 563 do_this_file = FALSE; 564 for (i = 0; i < G.filespecs; i++) 565 if (match(G.filename, G.pfnames[i], uO.C_flag)) { 566 do_this_file = TRUE; 567 break; /* found match, so stop looping */ 568 } 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 */ 573 break; 574 } 575 } 576 } 577 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 582 * Zip and PKZIP. 583 */ 584 if ((G.process_all_files || do_this_file) && !fn_is_dir(__G)) { 585 #ifdef USE_EF_UT_TIME 586 if (G.extra_field && 587 #ifdef IZ_CHECK_TZ 588 G.tz_is_valid && 589 #endif 590 (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1, 591 G.crec.last_mod_dos_datetime, &z_utime, NULL) 592 & EB_UT_FL_MTIME)) 593 { 594 if (*last_modtime < z_utime.mtime) 595 *last_modtime = z_utime.mtime; 596 } else 597 #endif /* USE_EF_UT_TIME */ 598 { 599 time_t modtime = dos_to_unix_time(G.crec.last_mod_dos_datetime); 600 601 if (*last_modtime < modtime) 602 *last_modtime = modtime; 603 } 604 ++*nmember; 605 } 606 SKIP_(G.crec.file_comment_length) 607 608 } /* end for-loop (j: files in central directory) */ 609 610 /*--------------------------------------------------------------------------- 611 Double check that we're back at the end-of-central-directory record. 612 ---------------------------------------------------------------------------*/ 613 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; 617 } 618 if (*nmember == 0L && error_in_archive <= PK_WARN) 619 error_in_archive = PK_FIND; 620 621 return error_in_archive; 622 623 } /* end function get_time_stamp() */ 624 625 #endif /* TIMESTAMP */ 626 627 628 629 630 631 /********************/ 632 /* Function ratio() */ /* also used by ZipInfo routines */ 633 /********************/ 634 635 int ratio(uc, c) 636 ulg uc, c; 637 { 638 ulg denom; 639 640 if (uc == 0) 641 return 0; 642 if (uc > 2000000L) { /* risk signed overflow if multiply numerator */ 643 denom = uc / 1000L; 644 return ((uc >= c) ? 645 (int) ((uc-c + (denom>>1)) / denom) : 646 -((int) ((c-uc + (denom>>1)) / denom))); 647 } else { /* ^^^^^^^^ rounding */ 648 denom = uc; 649 return ((uc >= c) ? 650 (int) ((1000L*(uc-c) + (denom>>1)) / denom) : 651 -((int) ((1000L*(c-uc) + (denom>>1)) / denom))); 652 } /* ^^^^^^^^ rounding */ 653 } 654 655 656 657 658 659 /************************/ 660 /* Function fnprint() */ /* also used by ZipInfo routines */ 661 /************************/ 662 663 void fnprint(__G) /* print filename (after filtering) and newline */ 664 __GDEF 665 { 666 char *name = fnfilter(G.filename, slide); 667 668 (*G.message)((zvoid *)&G, (uch *)name, (ulg)strlen(name), 0); 669 (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0); 670 671 } /* end function fnprint() */ 672