1// List.cpp 2 3#include "StdAfx.h" 4 5#include "../../../Common/IntToString.h" 6#include "../../../Common/MyCom.h" 7#include "../../../Common/StdOutStream.h" 8#include "../../../Common/StringConvert.h" 9#include "../../../Common/UTFConvert.h" 10 11#include "../../../Windows/ErrorMsg.h" 12#include "../../../Windows/FileDir.h" 13#include "../../../Windows/PropVariant.h" 14#include "../../../Windows/PropVariantConv.h" 15 16#include "../Common/OpenArchive.h" 17#include "../Common/PropIDUtils.h" 18 19#include "ConsoleClose.h" 20#include "List.h" 21#include "OpenCallbackConsole.h" 22 23using namespace NWindows; 24using namespace NCOM; 25 26extern CStdOutStream *g_StdStream; 27extern CStdOutStream *g_ErrStream; 28 29static const char * const kPropIdToName[] = 30{ 31 "0" 32 , "1" 33 , "2" 34 , "Path" 35 , "Name" 36 , "Extension" 37 , "Folder" 38 , "Size" 39 , "Packed Size" 40 , "Attributes" 41 , "Created" 42 , "Accessed" 43 , "Modified" 44 , "Solid" 45 , "Commented" 46 , "Encrypted" 47 , "Split Before" 48 , "Split After" 49 , "Dictionary Size" 50 , "CRC" 51 , "Type" 52 , "Anti" 53 , "Method" 54 , "Host OS" 55 , "File System" 56 , "User" 57 , "Group" 58 , "Block" 59 , "Comment" 60 , "Position" 61 , "Path Prefix" 62 , "Folders" 63 , "Files" 64 , "Version" 65 , "Volume" 66 , "Multivolume" 67 , "Offset" 68 , "Links" 69 , "Blocks" 70 , "Volumes" 71 , "Time Type" 72 , "64-bit" 73 , "Big-endian" 74 , "CPU" 75 , "Physical Size" 76 , "Headers Size" 77 , "Checksum" 78 , "Characteristics" 79 , "Virtual Address" 80 , "ID" 81 , "Short Name" 82 , "Creator Application" 83 , "Sector Size" 84 , "Mode" 85 , "Symbolic Link" 86 , "Error" 87 , "Total Size" 88 , "Free Space" 89 , "Cluster Size" 90 , "Label" 91 , "Local Name" 92 , "Provider" 93 , "NT Security" 94 , "Alternate Stream" 95 , "Aux" 96 , "Deleted" 97 , "Tree" 98 , "SHA-1" 99 , "SHA-256" 100 , "Error Type" 101 , "Errors" 102 , "Errors" 103 , "Warnings" 104 , "Warning" 105 , "Streams" 106 , "Alternate Streams" 107 , "Alternate Streams Size" 108 , "Virtual Size" 109 , "Unpack Size" 110 , "Total Physical Size" 111 , "Volume Index" 112 , "SubType" 113 , "Short Comment" 114 , "Code Page" 115 , "Is not archive type" 116 , "Physical Size can't be detected" 117 , "Zeros Tail Is Allowed" 118 , "Tail Size" 119 , "Embedded Stub Size" 120 , "Link" 121 , "Hard Link" 122 , "iNode" 123 , "Stream ID" 124 , "Read-only" 125 , "Out Name" 126 , "Copy Link" 127 , "ArcFileName" 128 , "IsHash" 129 , "Metadata Changed" 130 , "User ID" 131 , "Group ID" 132 , "Device Major" 133 , "Device Minor" 134 , "Dev Major" 135 , "Dev Minor" 136}; 137 138static const char kEmptyAttribChar = '.'; 139 140static const char * const kListing = "Listing archive: "; 141 142static const char * const kString_Files = "files"; 143static const char * const kString_Dirs = "folders"; 144static const char * const kString_AltStreams = "alternate streams"; 145static const char * const kString_Streams = "streams"; 146 147static const char * const kError = "ERROR: "; 148 149static void GetAttribString(UInt32 wa, bool isDir, bool allAttribs, char *s) 150{ 151 if (isDir) 152 wa |= FILE_ATTRIBUTE_DIRECTORY; 153 if (allAttribs) 154 { 155 ConvertWinAttribToString(s, wa); 156 return; 157 } 158 s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0) ? 'D': kEmptyAttribChar; 159 s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar; 160 s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar; 161 s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar; 162 s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar; 163 s[5] = 0; 164} 165 166enum EAdjustment 167{ 168 kLeft, 169 kCenter, 170 kRight 171}; 172 173struct CFieldInfo 174{ 175 PROPID PropID; 176 bool IsRawProp; 177 UString NameU; 178 AString NameA; 179 EAdjustment TitleAdjustment; 180 EAdjustment TextAdjustment; 181 unsigned PrefixSpacesWidth; 182 unsigned Width; 183}; 184 185struct CFieldInfoInit 186{ 187 PROPID PropID; 188 const char *Name; 189 EAdjustment TitleAdjustment; 190 EAdjustment TextAdjustment; 191 unsigned PrefixSpacesWidth; 192 unsigned Width; 193}; 194 195static const CFieldInfoInit kStandardFieldTable[] = 196{ 197 { kpidMTime, " Date Time", kLeft, kLeft, 0, 19 }, 198 { kpidAttrib, "Attr", kRight, kCenter, 1, 5 }, 199 { kpidSize, "Size", kRight, kRight, 1, 12 }, 200 { kpidPackSize, "Compressed", kRight, kRight, 1, 12 }, 201 { kpidPath, "Name", kLeft, kLeft, 2, 24 } 202}; 203 204const unsigned kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width 205static const char *g_Spaces = 206" " ; 207 208static void PrintSpaces(unsigned numSpaces) 209{ 210 if (numSpaces > 0 && numSpaces <= kNumSpacesMax) 211 g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces); 212} 213 214static void PrintSpacesToString(char *dest, unsigned numSpaces) 215{ 216 unsigned i; 217 for (i = 0; i < numSpaces; i++) 218 dest[i] = ' '; 219 dest[i] = 0; 220} 221 222// extern int g_CodePage; 223 224static void PrintUString(EAdjustment adj, unsigned width, const UString &s, AString &temp) 225{ 226 /* 227 // we don't need multibyte align. 228 int codePage = g_CodePage; 229 if (codePage == -1) 230 codePage = CP_OEMCP; 231 if (codePage == CP_UTF8) 232 ConvertUnicodeToUTF8(s, temp); 233 else 234 UnicodeStringToMultiByte2(temp, s, (UINT)codePage); 235 */ 236 237 unsigned numSpaces = 0; 238 239 if (width > s.Len()) 240 { 241 numSpaces = width - s.Len(); 242 unsigned numLeftSpaces = 0; 243 switch (adj) 244 { 245 case kLeft: numLeftSpaces = 0; break; 246 case kCenter: numLeftSpaces = numSpaces / 2; break; 247 case kRight: numLeftSpaces = numSpaces; break; 248 } 249 PrintSpaces(numLeftSpaces); 250 numSpaces -= numLeftSpaces; 251 } 252 253 g_StdOut.PrintUString(s, temp); 254 PrintSpaces(numSpaces); 255} 256 257static void PrintString(EAdjustment adj, unsigned width, const char *s) 258{ 259 unsigned numSpaces = 0; 260 unsigned len = (unsigned)strlen(s); 261 262 if (width > len) 263 { 264 numSpaces = width - len; 265 unsigned numLeftSpaces = 0; 266 switch (adj) 267 { 268 case kLeft: numLeftSpaces = 0; break; 269 case kCenter: numLeftSpaces = numSpaces / 2; break; 270 case kRight: numLeftSpaces = numSpaces; break; 271 } 272 PrintSpaces(numLeftSpaces); 273 numSpaces -= numLeftSpaces; 274 } 275 276 g_StdOut << s; 277 PrintSpaces(numSpaces); 278} 279 280static void PrintStringToString(char *dest, EAdjustment adj, unsigned width, const char *textString) 281{ 282 unsigned numSpaces = 0; 283 unsigned len = (unsigned)strlen(textString); 284 285 if (width > len) 286 { 287 numSpaces = width - len; 288 unsigned numLeftSpaces = 0; 289 switch (adj) 290 { 291 case kLeft: numLeftSpaces = 0; break; 292 case kCenter: numLeftSpaces = numSpaces / 2; break; 293 case kRight: numLeftSpaces = numSpaces; break; 294 } 295 PrintSpacesToString(dest, numLeftSpaces); 296 dest += numLeftSpaces; 297 numSpaces -= numLeftSpaces; 298 } 299 300 memcpy(dest, textString, len); 301 dest += len; 302 PrintSpacesToString(dest, numSpaces); 303} 304 305struct CListUInt64Def 306{ 307 UInt64 Val; 308 bool Def; 309 310 CListUInt64Def(): Val(0), Def(false) {} 311 void Add(UInt64 v) { Val += v; Def = true; } 312 void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); } 313}; 314 315 316struct CListFileTimeDef: public CArcTime 317{ 318 void Update(const CListFileTimeDef &t) 319 { 320 if (t.Def && (!Def || CompareWith(t) < 0)) 321 (*this) = t; 322 } 323}; 324 325 326 327struct CListStat 328{ 329 CListUInt64Def Size; 330 CListUInt64Def PackSize; 331 CListFileTimeDef MTime; 332 UInt64 NumFiles; 333 334 CListStat(): NumFiles(0) {} 335 void Update(const CListStat &st) 336 { 337 Size.Add(st.Size); 338 PackSize.Add(st.PackSize); 339 MTime.Update(st.MTime); 340 NumFiles += st.NumFiles; 341 } 342 void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; } 343}; 344 345struct CListStat2 346{ 347 CListStat MainFiles; 348 CListStat AltStreams; 349 UInt64 NumDirs; 350 351 CListStat2(): NumDirs(0) {} 352 353 void Update(const CListStat2 &st) 354 { 355 MainFiles.Update(st.MainFiles); 356 AltStreams.Update(st.AltStreams); 357 NumDirs += st.NumDirs; 358 } 359 UInt64 GetNumStreams() const { return MainFiles.NumFiles + AltStreams.NumFiles; } 360 CListStat &GetStat(bool altStreamsMode) { return altStreamsMode ? AltStreams : MainFiles; } 361}; 362 363class CFieldPrinter 364{ 365 CObjectVector<CFieldInfo> _fields; 366 367 void AddProp(const wchar_t *name, PROPID propID, bool isRawProp); 368public: 369 const CArc *Arc; 370 bool TechMode; 371 UString FilePath; 372 AString TempAString; 373 UString TempWString; 374 bool IsDir; 375 376 AString LinesString; 377 378 void Clear() { _fields.Clear(); LinesString.Empty(); } 379 void Init(const CFieldInfoInit *standardFieldTable, unsigned numItems); 380 381 HRESULT AddMainProps(IInArchive *archive); 382 HRESULT AddRawProps(IArchiveGetRawProps *getRawProps); 383 384 void PrintTitle(); 385 void PrintTitleLines(); 386 HRESULT PrintItemInfo(UInt32 index, const CListStat &st); 387 void PrintSum(const CListStat &st, UInt64 numDirs, const char *str); 388 void PrintSum(const CListStat2 &stat2); 389}; 390 391void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, unsigned numItems) 392{ 393 Clear(); 394 for (unsigned i = 0; i < numItems; i++) 395 { 396 CFieldInfo &f = _fields.AddNew(); 397 const CFieldInfoInit &fii = standardFieldTable[i]; 398 f.PropID = fii.PropID; 399 f.IsRawProp = false; 400 f.NameA = fii.Name; 401 f.TitleAdjustment = fii.TitleAdjustment; 402 f.TextAdjustment = fii.TextAdjustment; 403 f.PrefixSpacesWidth = fii.PrefixSpacesWidth; 404 f.Width = fii.Width; 405 406 unsigned k; 407 for (k = 0; k < fii.PrefixSpacesWidth; k++) 408 LinesString.Add_Space(); 409 for (k = 0; k < fii.Width; k++) 410 LinesString.Add_Minus(); 411 } 412} 413 414static void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU) 415{ 416 if (propID < Z7_ARRAY_SIZE(kPropIdToName)) 417 { 418 nameA = kPropIdToName[propID]; 419 return; 420 } 421 if (name) 422 nameU = name; 423 else 424 { 425 nameA.Empty(); 426 nameA.Add_UInt32(propID); 427 } 428} 429 430void CFieldPrinter::AddProp(const wchar_t *name, PROPID propID, bool isRawProp) 431{ 432 CFieldInfo f; 433 f.PropID = propID; 434 f.IsRawProp = isRawProp; 435 GetPropName(propID, name, f.NameA, f.NameU); 436 f.NameU += " = "; 437 if (!f.NameA.IsEmpty()) 438 f.NameA += " = "; 439 else 440 { 441 const UString &s = f.NameU; 442 AString sA; 443 unsigned i; 444 for (i = 0; i < s.Len(); i++) 445 { 446 wchar_t c = s[i]; 447 if (c >= 0x80) 448 break; 449 sA += (char)c; 450 } 451 if (i == s.Len()) 452 f.NameA = sA; 453 } 454 _fields.Add(f); 455} 456 457HRESULT CFieldPrinter::AddMainProps(IInArchive *archive) 458{ 459 UInt32 numProps; 460 RINOK(archive->GetNumberOfProperties(&numProps)) 461 for (UInt32 i = 0; i < numProps; i++) 462 { 463 CMyComBSTR name; 464 PROPID propID; 465 VARTYPE vt; 466 RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt)) 467 AddProp(name, propID, false); 468 } 469 return S_OK; 470} 471 472HRESULT CFieldPrinter::AddRawProps(IArchiveGetRawProps *getRawProps) 473{ 474 UInt32 numProps; 475 RINOK(getRawProps->GetNumRawProps(&numProps)) 476 for (UInt32 i = 0; i < numProps; i++) 477 { 478 CMyComBSTR name; 479 PROPID propID; 480 RINOK(getRawProps->GetRawPropInfo(i, &name, &propID)) 481 AddProp(name, propID, true); 482 } 483 return S_OK; 484} 485 486void CFieldPrinter::PrintTitle() 487{ 488 FOR_VECTOR (i, _fields) 489 { 490 const CFieldInfo &f = _fields[i]; 491 PrintSpaces(f.PrefixSpacesWidth); 492 PrintString(f.TitleAdjustment, ((f.PropID == kpidPath) ? 0: f.Width), f.NameA); 493 } 494} 495 496void CFieldPrinter::PrintTitleLines() 497{ 498 g_StdOut << LinesString; 499} 500 501static void PrintTime(char *dest, const CListFileTimeDef &t, bool showNS) 502{ 503 *dest = 0; 504 if (t.IsZero()) 505 return; 506 int prec = kTimestampPrintLevel_SEC; 507 if (showNS) 508 { 509 prec = kTimestampPrintLevel_NTFS; 510 if (t.Prec != 0) 511 { 512 prec = t.GetNumDigits(); 513 if (prec < kTimestampPrintLevel_DAY) 514 prec = kTimestampPrintLevel_NTFS; 515 } 516 } 517 518 ConvertUtcFileTimeToString2(t.FT, t.Ns100, dest, prec); 519} 520 521#ifndef Z7_SFX 522 523static inline char GetHex(Byte value) 524{ 525 return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10))); 526} 527 528static void HexToString(char *dest, const Byte *data, UInt32 size) 529{ 530 for (UInt32 i = 0; i < size; i++) 531 { 532 Byte b = data[i]; 533 dest[0] = GetHex((Byte)((b >> 4) & 0xF)); 534 dest[1] = GetHex((Byte)(b & 0xF)); 535 dest += 2; 536 } 537 *dest = 0; 538} 539 540#endif 541 542#define MY_ENDL endl 543 544HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st) 545{ 546 char temp[128]; 547 size_t tempPos = 0; 548 549 bool techMode = this->TechMode; 550 /* 551 if (techMode) 552 { 553 g_StdOut << "Index = "; 554 g_StdOut << (UInt64)index; 555 g_StdOut << endl; 556 } 557 */ 558 FOR_VECTOR (i, _fields) 559 { 560 const CFieldInfo &f = _fields[i]; 561 562 if (!techMode) 563 { 564 PrintSpacesToString(temp + tempPos, f.PrefixSpacesWidth); 565 tempPos += f.PrefixSpacesWidth; 566 } 567 568 if (techMode) 569 { 570 if (!f.NameA.IsEmpty()) 571 g_StdOut << f.NameA; 572 else 573 g_StdOut << f.NameU; 574 } 575 576 if (f.PropID == kpidPath) 577 { 578 if (!techMode) 579 g_StdOut << temp; 580 g_StdOut.NormalizePrint_UString(FilePath, TempWString, TempAString); 581 if (techMode) 582 g_StdOut << MY_ENDL; 583 continue; 584 } 585 586 const unsigned width = f.Width; 587 588 if (f.IsRawProp) 589 { 590 #ifndef Z7_SFX 591 592 const void *data; 593 UInt32 dataSize; 594 UInt32 propType; 595 RINOK(Arc->GetRawProps->GetRawProp(index, f.PropID, &data, &dataSize, &propType)) 596 597 if (dataSize != 0) 598 { 599 bool needPrint = true; 600 601 if (f.PropID == kpidNtSecure) 602 { 603 if (propType != NPropDataType::kRaw) 604 return E_FAIL; 605 #ifndef Z7_SFX 606 ConvertNtSecureToString((const Byte *)data, dataSize, TempAString); 607 g_StdOut << TempAString; 608 needPrint = false; 609 #endif 610 } 611 else if (f.PropID == kpidNtReparse) 612 { 613 UString s; 614 if (ConvertNtReparseToString((const Byte *)data, dataSize, s)) 615 { 616 needPrint = false; 617 g_StdOut.PrintUString(s, TempAString); 618 } 619 } 620 621 if (needPrint) 622 { 623 if (propType != NPropDataType::kRaw) 624 return E_FAIL; 625 626 const UInt32 kMaxDataSize = 64; 627 628 if (dataSize > kMaxDataSize) 629 { 630 g_StdOut << "data:"; 631 g_StdOut << dataSize; 632 } 633 else 634 { 635 char hexStr[kMaxDataSize * 2 + 4]; 636 HexToString(hexStr, (const Byte *)data, dataSize); 637 g_StdOut << hexStr; 638 } 639 } 640 } 641 642 #endif 643 } 644 else 645 { 646 CPropVariant prop; 647 switch (f.PropID) 648 { 649 case kpidSize: if (st.Size.Def) prop = st.Size.Val; break; 650 case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break; 651 case kpidMTime: 652 { 653 const CListFileTimeDef &mtime = st.MTime; 654 if (mtime.Def) 655 prop.SetAsTimeFrom_FT_Prec_Ns100(mtime.FT, mtime.Prec, mtime.Ns100); 656 break; 657 } 658 default: 659 RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop)) 660 } 661 if (f.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4)) 662 { 663 GetAttribString((prop.vt == VT_EMPTY) ? 0 : prop.ulVal, IsDir, techMode, temp + tempPos); 664 if (techMode) 665 g_StdOut << temp + tempPos; 666 else 667 tempPos += strlen(temp + tempPos); 668 } 669 else if (prop.vt == VT_EMPTY) 670 { 671 if (!techMode) 672 { 673 PrintSpacesToString(temp + tempPos, width); 674 tempPos += width; 675 } 676 } 677 else if (prop.vt == VT_FILETIME) 678 { 679 CListFileTimeDef t; 680 t.Set_From_Prop(prop); 681 PrintTime(temp + tempPos, t, techMode); 682 if (techMode) 683 g_StdOut << temp + tempPos; 684 else 685 { 686 size_t len = strlen(temp + tempPos); 687 tempPos += len; 688 if (len < (unsigned)f.Width) 689 { 690 len = f.Width - len; 691 PrintSpacesToString(temp + tempPos, (unsigned)len); 692 tempPos += len; 693 } 694 } 695 } 696 else if (prop.vt == VT_BSTR) 697 { 698 TempWString.SetFromBstr(prop.bstrVal); 699 // do we need multi-line support here ? 700 g_StdOut.Normalize_UString(TempWString); 701 if (techMode) 702 { 703 g_StdOut.PrintUString(TempWString, TempAString); 704 } 705 else 706 PrintUString(f.TextAdjustment, width, TempWString, TempAString); 707 } 708 else 709 { 710 char s[64]; 711 ConvertPropertyToShortString2(s, prop, f.PropID); 712 if (techMode) 713 g_StdOut << s; 714 else 715 { 716 PrintStringToString(temp + tempPos, f.TextAdjustment, width, s); 717 tempPos += strlen(temp + tempPos); 718 } 719 } 720 } 721 if (techMode) 722 g_StdOut << MY_ENDL; 723 } 724 g_StdOut << MY_ENDL; 725 return S_OK; 726} 727 728static void PrintNumber(EAdjustment adj, unsigned width, const CListUInt64Def &value) 729{ 730 char s[32]; 731 s[0] = 0; 732 if (value.Def) 733 ConvertUInt64ToString(value.Val, s); 734 PrintString(adj, width, s); 735} 736 737void Print_UInt64_and_String(AString &s, UInt64 val, const char *name); 738 739void CFieldPrinter::PrintSum(const CListStat &st, UInt64 numDirs, const char *str) 740{ 741 FOR_VECTOR (i, _fields) 742 { 743 const CFieldInfo &f = _fields[i]; 744 PrintSpaces(f.PrefixSpacesWidth); 745 if (f.PropID == kpidSize) 746 PrintNumber(f.TextAdjustment, f.Width, st.Size); 747 else if (f.PropID == kpidPackSize) 748 PrintNumber(f.TextAdjustment, f.Width, st.PackSize); 749 else if (f.PropID == kpidMTime) 750 { 751 char s[64]; 752 s[0] = 0; 753 if (st.MTime.Def) 754 PrintTime(s, st.MTime, false); // showNS 755 PrintString(f.TextAdjustment, f.Width, s); 756 } 757 else if (f.PropID == kpidPath) 758 { 759 AString s; 760 Print_UInt64_and_String(s, st.NumFiles, str); 761 if (numDirs != 0) 762 { 763 s += ", "; 764 Print_UInt64_and_String(s, numDirs, kString_Dirs); 765 } 766 PrintString(f.TextAdjustment, 0, s); 767 } 768 else 769 PrintString(f.TextAdjustment, f.Width, ""); 770 } 771 g_StdOut << endl; 772} 773 774void CFieldPrinter::PrintSum(const CListStat2 &stat2) 775{ 776 PrintSum(stat2.MainFiles, stat2.NumDirs, kString_Files); 777 if (stat2.AltStreams.NumFiles != 0) 778 { 779 PrintSum(stat2.AltStreams, 0, kString_AltStreams); 780 CListStat st = stat2.MainFiles; 781 st.Update(stat2.AltStreams); 782 PrintSum(st, 0, kString_Streams); 783 } 784} 785 786static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, CListUInt64Def &value) 787{ 788 value.Val = 0; 789 value.Def = false; 790 CPropVariant prop; 791 RINOK(archive->GetProperty(index, propID, &prop)) 792 value.Def = ConvertPropVariantToUInt64(prop, value.Val); 793 return S_OK; 794} 795 796static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t) 797{ 798 /* maybe we could call CArc::GetItemMTime(UInt32 index, CArcTime &ft, bool &defined) here 799 that can set default timestamp, if not defined */ 800 t.Clear(); 801 // t.Def = false; 802 CPropVariant prop; 803 RINOK(archive->GetProperty(index, kpidMTime, &prop)) 804 if (prop.vt == VT_FILETIME) 805 t.Set_From_Prop(prop); 806 else if (prop.vt != VT_EMPTY) 807 return E_FAIL; 808 return S_OK; 809} 810 811static void PrintPropNameAndNumber(CStdOutStream &so, const char *name, UInt64 val) 812{ 813 so << name << ": " << val << endl; 814} 815 816static void PrintPropName_and_Eq(CStdOutStream &so, PROPID propID) 817{ 818 const char *s; 819 char temp[16]; 820 if (propID < Z7_ARRAY_SIZE(kPropIdToName)) 821 s = kPropIdToName[propID]; 822 else 823 { 824 ConvertUInt32ToString(propID, temp); 825 s = temp; 826 } 827 so << s << " = "; 828} 829 830static void PrintPropNameAndNumber(CStdOutStream &so, PROPID propID, UInt64 val) 831{ 832 PrintPropName_and_Eq(so, propID); 833 so << val << endl; 834} 835 836static void PrintPropNameAndNumber_Signed(CStdOutStream &so, PROPID propID, Int64 val) 837{ 838 PrintPropName_and_Eq(so, propID); 839 so << val << endl; 840} 841 842 843static void UString_Replace_CRLF_to_LF(UString &s) 844{ 845 // s.Replace(L"\r\n", L"\n"); 846 wchar_t *src = s.GetBuf(); 847 wchar_t *dest = src; 848 for (;;) 849 { 850 wchar_t c = *src++; 851 if (c == 0) 852 break; 853 if (c == '\r' && *src == '\n') 854 { 855 src++; 856 c = '\n'; 857 } 858 *dest++ = c; 859 } 860 s.ReleaseBuf_SetEnd((unsigned)(dest - s.GetBuf())); 861} 862 863 864static void PrintPropVal_MultiLine(CStdOutStream &so, const wchar_t *val) 865{ 866 UString s (val); 867 if (s.Find(L'\n') >= 0) 868 { 869 so << endl; 870 so << "{"; 871 so << endl; 872 UString_Replace_CRLF_to_LF(s); 873 so.Normalize_UString_LF_Allowed(s); 874 so << s; 875 so << endl; 876 so << "}"; 877 } 878 else 879 { 880 so.Normalize_UString(s); 881 so << s; 882 } 883 so << endl; 884} 885 886 887static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val, bool multiLine) 888{ 889 so << name << " = "; 890 if (multiLine) 891 { 892 PrintPropVal_MultiLine(so, val); 893 return; 894 } 895 UString s (val); 896 so.Normalize_UString(s); 897 so << s; 898 so << endl; 899} 900 901 902static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop) 903{ 904 UString s; 905 const int levelTopLimit = 9; // 1ns level 906 ConvertPropertyToString2(s, prop, propID, levelTopLimit); 907 if (!s.IsEmpty()) 908 { 909 AString nameA; 910 UString nameU; 911 GetPropName(propID, name, nameA, nameU); 912 if (!nameA.IsEmpty()) 913 so << nameA; 914 else 915 so << nameU; 916 so << " = "; 917 PrintPropVal_MultiLine(so, s); 918 } 919} 920 921static HRESULT PrintArcProp(CStdOutStream &so, IInArchive *archive, PROPID propID, const wchar_t *name) 922{ 923 CPropVariant prop; 924 RINOK(archive->GetArchiveProperty(propID, &prop)) 925 PrintPropertyPair2(so, propID, name, prop); 926 return S_OK; 927} 928 929static void PrintArcTypeError(CStdOutStream &so, const UString &type, bool isWarning) 930{ 931 so << "Open " << (isWarning ? "WARNING" : "ERROR") 932 << ": Cannot open the file as [" 933 << type 934 << "] archive" 935 << endl; 936} 937 938int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name); 939 940void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); 941 942static void ErrorInfo_Print(CStdOutStream &so, const CArcErrorInfo &er) 943{ 944 PrintErrorFlags(so, "ERRORS:", er.GetErrorFlags()); 945 if (!er.ErrorMessage.IsEmpty()) 946 PrintPropPair(so, "ERROR", er.ErrorMessage, true); 947 948 PrintErrorFlags(so, "WARNINGS:", er.GetWarningFlags()); 949 if (!er.WarningMessage.IsEmpty()) 950 PrintPropPair(so, "WARNING", er.WarningMessage, true); 951} 952 953HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); 954HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink) 955{ 956 FOR_VECTOR (r, arcLink.Arcs) 957 { 958 const CArc &arc = arcLink.Arcs[r]; 959 const CArcErrorInfo &er = arc.ErrorInfo; 960 961 so << "--\n"; 962 PrintPropPair(so, "Path", arc.Path, false); 963 if (er.ErrorFormatIndex >= 0) 964 { 965 if (er.ErrorFormatIndex == arc.FormatIndex) 966 so << "Warning: The archive is open with offset" << endl; 967 else 968 PrintArcTypeError(so, codecs->GetFormatNamePtr(er.ErrorFormatIndex), true); 969 } 970 PrintPropPair(so, "Type", codecs->GetFormatNamePtr(arc.FormatIndex), false); 971 972 ErrorInfo_Print(so, er); 973 974 Int64 offset = arc.GetGlobalOffset(); 975 if (offset != 0) 976 PrintPropNameAndNumber_Signed(so, kpidOffset, offset); 977 IInArchive *archive = arc.Archive; 978 RINOK(PrintArcProp(so, archive, kpidPhySize, NULL)) 979 if (er.TailSize != 0) 980 PrintPropNameAndNumber(so, kpidTailSize, er.TailSize); 981 { 982 UInt32 numProps; 983 RINOK(archive->GetNumberOfArchiveProperties(&numProps)) 984 985 for (UInt32 j = 0; j < numProps; j++) 986 { 987 CMyComBSTR name; 988 PROPID propID; 989 VARTYPE vt; 990 RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt)) 991 RINOK(PrintArcProp(so, archive, propID, name)) 992 } 993 } 994 995 if (r != arcLink.Arcs.Size() - 1) 996 { 997 UInt32 numProps; 998 so << "----\n"; 999 if (archive->GetNumberOfProperties(&numProps) == S_OK) 1000 { 1001 UInt32 mainIndex = arcLink.Arcs[r + 1].SubfileIndex; 1002 for (UInt32 j = 0; j < numProps; j++) 1003 { 1004 CMyComBSTR name; 1005 PROPID propID; 1006 VARTYPE vt; 1007 RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt)) 1008 CPropVariant prop; 1009 RINOK(archive->GetProperty(mainIndex, propID, &prop)) 1010 PrintPropertyPair2(so, propID, name, prop); 1011 } 1012 } 1013 } 1014 } 1015 return S_OK; 1016} 1017 1018HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); 1019HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink) 1020{ 1021 #ifndef Z7_NO_CRYPTO 1022 if (arcLink.PasswordWasAsked) 1023 so << "Cannot open encrypted archive. Wrong password?"; 1024 else 1025 #endif 1026 { 1027 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) 1028 { 1029 so.NormalizePrint_UString(arcLink.NonOpen_ArcPath); 1030 so << endl; 1031 PrintArcTypeError(so, codecs->Formats[(unsigned)arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false); 1032 } 1033 else 1034 so << "Cannot open the file as archive"; 1035 } 1036 1037 so << endl; 1038 so << endl; 1039 ErrorInfo_Print(so, arcLink.NonOpen_ErrorInfo); 1040 1041 return S_OK; 1042} 1043 1044bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); 1045 1046HRESULT ListArchives( 1047 const CListOptions &listOptions, 1048 CCodecs *codecs, 1049 const CObjectVector<COpenType> &types, 1050 const CIntVector &excludedFormats, 1051 bool stdInMode, 1052 UStringVector &arcPaths, UStringVector &arcPathsFull, 1053 bool processAltStreams, bool showAltStreams, 1054 const NWildcard::CCensorNode &wildcardCensor, 1055 bool enableHeaders, bool techMode, 1056 #ifndef Z7_NO_CRYPTO 1057 bool &passwordEnabled, UString &password, 1058 #endif 1059 #ifndef Z7_SFX 1060 const CObjectVector<CProperty> *props, 1061 #endif 1062 UInt64 &numErrors, 1063 UInt64 &numWarnings) 1064{ 1065 bool allFilesAreAllowed = wildcardCensor.AreAllAllowed(); 1066 1067 numErrors = 0; 1068 numWarnings = 0; 1069 1070 CFieldPrinter fp; 1071 if (!techMode) 1072 fp.Init(kStandardFieldTable, Z7_ARRAY_SIZE(kStandardFieldTable)); 1073 1074 CListStat2 stat2total; 1075 1076 CBoolArr skipArcs(arcPaths.Size()); 1077 unsigned arcIndex; 1078 for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++) 1079 skipArcs[arcIndex] = false; 1080 UInt64 numVolumes = 0; 1081 UInt64 numArcs = 0; 1082 UInt64 totalArcSizes = 0; 1083 1084 HRESULT lastError = 0; 1085 1086 for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++) 1087 { 1088 if (skipArcs[arcIndex]) 1089 continue; 1090 const UString &arcPath = arcPaths[arcIndex]; 1091 UInt64 arcPackSize = 0; 1092 1093 if (!stdInMode) 1094 { 1095 NFile::NFind::CFileInfo fi; 1096 if (!fi.Find_FollowLink(us2fs(arcPath))) 1097 { 1098 DWORD errorCode = GetLastError(); 1099 if (errorCode == 0) 1100 errorCode = ERROR_FILE_NOT_FOUND; 1101 lastError = HRESULT_FROM_WIN32(errorCode); 1102 g_StdOut.Flush(); 1103 if (g_ErrStream) 1104 { 1105 *g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) << endl; 1106 g_ErrStream->NormalizePrint_UString(arcPath); 1107 *g_ErrStream << endl << endl; 1108 } 1109 numErrors++; 1110 continue; 1111 } 1112 if (fi.IsDir()) 1113 { 1114 g_StdOut.Flush(); 1115 if (g_ErrStream) 1116 { 1117 *g_ErrStream << endl << kError; 1118 g_ErrStream->NormalizePrint_UString(arcPath); 1119 *g_ErrStream << " is not a file" << endl << endl; 1120 } 1121 numErrors++; 1122 continue; 1123 } 1124 arcPackSize = fi.Size; 1125 totalArcSizes += arcPackSize; 1126 } 1127 1128 CArchiveLink arcLink; 1129 1130 COpenCallbackConsole openCallback; 1131 openCallback.Init(&g_StdOut, g_ErrStream, NULL); 1132 1133 #ifndef Z7_NO_CRYPTO 1134 1135 openCallback.PasswordIsDefined = passwordEnabled; 1136 openCallback.Password = password; 1137 1138 #endif 1139 1140 /* 1141 CObjectVector<COptionalOpenProperties> optPropsVector; 1142 COptionalOpenProperties &optProps = optPropsVector.AddNew(); 1143 optProps.Props = *props; 1144 */ 1145 1146 COpenOptions options; 1147 #ifndef Z7_SFX 1148 options.props = props; 1149 #endif 1150 options.codecs = codecs; 1151 options.types = &types; 1152 options.excludedFormats = &excludedFormats; 1153 options.stdInMode = stdInMode; 1154 options.stream = NULL; 1155 options.filePath = arcPath; 1156 1157 if (enableHeaders) 1158 { 1159 g_StdOut << endl << kListing; 1160 g_StdOut.NormalizePrint_UString(arcPath); 1161 g_StdOut << endl << endl; 1162 } 1163 1164 HRESULT result = arcLink.Open_Strict(options, &openCallback); 1165 1166 if (result != S_OK) 1167 { 1168 if (result == E_ABORT) 1169 return result; 1170 if (result != S_FALSE) 1171 lastError = result; 1172 g_StdOut.Flush(); 1173 if (g_ErrStream) 1174 { 1175 *g_ErrStream << endl << kError; 1176 g_ErrStream->NormalizePrint_UString(arcPath); 1177 *g_ErrStream << " : "; 1178 if (result == S_FALSE) 1179 { 1180 Print_OpenArchive_Error(*g_ErrStream, codecs, arcLink); 1181 } 1182 else 1183 { 1184 *g_ErrStream << "opening : "; 1185 if (result == E_OUTOFMEMORY) 1186 *g_ErrStream << "Can't allocate required memory"; 1187 else 1188 *g_ErrStream << NError::MyFormatMessage(result); 1189 } 1190 *g_ErrStream << endl; 1191 } 1192 numErrors++; 1193 continue; 1194 } 1195 1196 { 1197 FOR_VECTOR (r, arcLink.Arcs) 1198 { 1199 const CArcErrorInfo &arc = arcLink.Arcs[r].ErrorInfo; 1200 if (!arc.WarningMessage.IsEmpty()) 1201 numWarnings++; 1202 if (arc.AreThereWarnings()) 1203 numWarnings++; 1204 if (arc.ErrorFormatIndex >= 0) 1205 numWarnings++; 1206 if (arc.AreThereErrors()) 1207 { 1208 numErrors++; 1209 // break; 1210 } 1211 if (!arc.ErrorMessage.IsEmpty()) 1212 numErrors++; 1213 } 1214 } 1215 1216 numArcs++; 1217 numVolumes++; 1218 1219 if (!stdInMode) 1220 { 1221 numVolumes += arcLink.VolumePaths.Size(); 1222 totalArcSizes += arcLink.VolumesSize; 1223 FOR_VECTOR (v, arcLink.VolumePaths) 1224 { 1225 int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); 1226 if (index >= 0 && (unsigned)index > arcIndex) 1227 skipArcs[(unsigned)index] = true; 1228 } 1229 } 1230 1231 1232 if (enableHeaders) 1233 { 1234 RINOK(Print_OpenArchive_Props(g_StdOut, codecs, arcLink)) 1235 1236 g_StdOut << endl; 1237 if (techMode) 1238 g_StdOut << "----------\n"; 1239 } 1240 1241 if (enableHeaders && !techMode) 1242 { 1243 fp.PrintTitle(); 1244 g_StdOut << endl; 1245 fp.PrintTitleLines(); 1246 g_StdOut << endl; 1247 } 1248 1249 const CArc &arc = arcLink.Arcs.Back(); 1250 fp.Arc = &arc; 1251 fp.TechMode = techMode; 1252 IInArchive *archive = arc.Archive; 1253 if (techMode) 1254 { 1255 fp.Clear(); 1256 RINOK(fp.AddMainProps(archive)) 1257 if (arc.GetRawProps) 1258 { 1259 RINOK(fp.AddRawProps(arc.GetRawProps)) 1260 } 1261 } 1262 1263 CListStat2 stat2; 1264 1265 UInt32 numItems; 1266 RINOK(archive->GetNumberOfItems(&numItems)) 1267 1268 CReadArcItem item; 1269 UStringVector pathParts; 1270 1271 for (UInt32 i = 0; i < numItems; i++) 1272 { 1273 if (NConsoleClose::TestBreakSignal()) 1274 return E_ABORT; 1275 1276 HRESULT res = arc.GetItem_Path2(i, fp.FilePath); 1277 1278 if (stdInMode && res == E_INVALIDARG) 1279 break; 1280 RINOK(res) 1281 1282 if (arc.Ask_Aux) 1283 { 1284 bool isAux; 1285 RINOK(Archive_IsItem_Aux(archive, i, isAux)) 1286 if (isAux) 1287 continue; 1288 } 1289 1290 bool isAltStream = false; 1291 if (arc.Ask_AltStream) 1292 { 1293 RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)) 1294 if (isAltStream && !processAltStreams) 1295 continue; 1296 } 1297 1298 RINOK(Archive_IsItem_Dir(archive, i, fp.IsDir)) 1299 1300 if (fp.IsDir ? listOptions.ExcludeDirItems : listOptions.ExcludeFileItems) 1301 continue; 1302 1303 if (!allFilesAreAllowed) 1304 { 1305 if (isAltStream) 1306 { 1307 RINOK(arc.GetItem(i, item)) 1308 if (!CensorNode_CheckPath(wildcardCensor, item)) 1309 continue; 1310 } 1311 else 1312 { 1313 SplitPathToParts(fp.FilePath, pathParts); 1314 bool include; 1315 if (!wildcardCensor.CheckPathVect(pathParts, !fp.IsDir, include)) 1316 continue; 1317 if (!include) 1318 continue; 1319 } 1320 } 1321 1322 CListStat st; 1323 1324 RINOK(GetUInt64Value(archive, i, kpidSize, st.Size)) 1325 RINOK(GetUInt64Value(archive, i, kpidPackSize, st.PackSize)) 1326 RINOK(GetItemMTime(archive, i, st.MTime)) 1327 1328 if (fp.IsDir) 1329 stat2.NumDirs++; 1330 else 1331 st.NumFiles = 1; 1332 stat2.GetStat(isAltStream).Update(st); 1333 1334 if (isAltStream && !showAltStreams) 1335 continue; 1336 RINOK(fp.PrintItemInfo(i, st)) 1337 } 1338 1339 UInt64 numStreams = stat2.GetNumStreams(); 1340 if (!stdInMode 1341 && !stat2.MainFiles.PackSize.Def 1342 && !stat2.AltStreams.PackSize.Def) 1343 { 1344 if (arcLink.VolumePaths.Size() != 0) 1345 arcPackSize += arcLink.VolumesSize; 1346 stat2.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize); 1347 } 1348 1349 stat2.MainFiles.SetSizeDefIfNoFiles(); 1350 stat2.AltStreams.SetSizeDefIfNoFiles(); 1351 1352 if (enableHeaders && !techMode) 1353 { 1354 fp.PrintTitleLines(); 1355 g_StdOut << endl; 1356 fp.PrintSum(stat2); 1357 } 1358 1359 if (enableHeaders) 1360 { 1361 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) 1362 { 1363 g_StdOut << "----------\n"; 1364 PrintPropPair(g_StdOut, "Path", arcLink.NonOpen_ArcPath, false); 1365 PrintArcTypeError(g_StdOut, codecs->Formats[(unsigned)arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false); 1366 } 1367 } 1368 1369 stat2total.Update(stat2); 1370 1371 g_StdOut.Flush(); 1372 } 1373 1374 if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1)) 1375 { 1376 g_StdOut << endl; 1377 fp.PrintTitleLines(); 1378 g_StdOut << endl; 1379 fp.PrintSum(stat2total); 1380 g_StdOut << endl; 1381 PrintPropNameAndNumber(g_StdOut, "Archives", numArcs); 1382 PrintPropNameAndNumber(g_StdOut, "Volumes", numVolumes); 1383 PrintPropNameAndNumber(g_StdOut, "Total archives size", totalArcSizes); 1384 } 1385 1386 if (numErrors == 1 && lastError != 0) 1387 return lastError; 1388 1389 return S_OK; 1390} 1391