| #include "rar.hpp" |
| |
| static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare); |
| static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize); |
| |
| void ListArchive(CommandData *Cmd) |
| { |
| int64 SumPackSize=0,SumUnpSize=0; |
| uint ArcCount=0,SumFileCount=0; |
| bool Technical=(Cmd->Command[1]=='T'); |
| bool ShowService=Technical && Cmd->Command[2]=='A'; |
| bool Bare=(Cmd->Command[1]=='B'); |
| bool Verbose=(Cmd->Command[0]=='V'); |
| |
| wchar ArcName[NM]; |
| while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) |
| { |
| if (Cmd->ManualPassword) |
| Cmd->Password.Clean(); // Clean user entered password before processing next archive. |
| |
| Archive Arc(Cmd); |
| #ifdef _WIN_ALL |
| Arc.RemoveSequentialFlag(); |
| #endif |
| if (!Arc.WOpen(ArcName)) |
| continue; |
| bool FileMatched=true; |
| while (1) |
| { |
| int64 TotalPackSize=0,TotalUnpSize=0; |
| uint FileCount=0; |
| if (Arc.IsArchive(true)) |
| { |
| bool TitleShown=false; |
| if (!Bare) |
| { |
| Arc.ViewComment(); |
| mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName); |
| mprintf(L"\n%s: ",St(MListDetails)); |
| uint SetCount=0; |
| const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5"); |
| mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", Fmt); |
| if (Arc.Solid) |
| mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSolid)); |
| if (Arc.SFXSize>0) |
| mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSFX)); |
| if (Arc.Volume) |
| { |
| if (Arc.Format==RARFMT50) |
| { |
| // RAR 5.0 archives store the volume number in main header, |
| // so it is already available now. |
| if (SetCount++ > 0) |
| mprintf(L", "); |
| mprintf(St(MVolumeNumber),Arc.VolNumber+1); |
| } |
| else |
| mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListVolume)); |
| } |
| if (Arc.Protected) |
| mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListRR)); |
| if (Arc.Locked) |
| mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock)); |
| if (Arc.Encrypted) |
| mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead)); |
| mprintf(L"\n"); |
| } |
| |
| wchar VolNumText[50]; |
| *VolNumText=0; |
| while(Arc.ReadHeader()>0) |
| { |
| HEADER_TYPE HeaderType=Arc.GetHeaderType(); |
| if (HeaderType==HEAD_ENDARC) |
| { |
| #ifndef SFX_MODULE |
| // Only RAR 1.5 archives store the volume number in end record. |
| if (Arc.EndArcHead.StoreVolNumber && Arc.Format==RARFMT15) |
| swprintf(VolNumText,ASIZE(VolNumText),L"%.10ls %u",St(MListVolume),Arc.VolNumber+1); |
| #endif |
| if (Technical && ShowService) |
| { |
| mprintf(L"\n%12ls: %ls",St(MListService),L"EOF"); |
| if (*VolNumText!=0) |
| mprintf(L"\n%12ls: %ls",St(MListFlags),VolNumText); |
| mprintf(L"\n"); |
| } |
| break; |
| } |
| switch(HeaderType) |
| { |
| case HEAD_FILE: |
| FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0; |
| if (FileMatched) |
| { |
| ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare); |
| if (!Arc.FileHead.SplitBefore) |
| { |
| TotalUnpSize+=Arc.FileHead.UnpSize; |
| FileCount++; |
| } |
| TotalPackSize+=Arc.FileHead.PackSize; |
| } |
| break; |
| case HEAD_SERVICE: |
| if (FileMatched && !Bare) |
| { |
| if (Technical && ShowService) |
| ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false); |
| } |
| break; |
| default: |
| break; |
| } |
| Arc.SeekToNext(); |
| } |
| if (!Bare && !Technical) |
| { |
| if (TitleShown) |
| { |
| wchar UnpSizeText[20]; |
| itoa(TotalUnpSize,UnpSizeText,ASIZE(UnpSizeText)); |
| |
| wchar PackSizeText[20]; |
| itoa(TotalPackSize,PackSizeText,ASIZE(PackSizeText)); |
| |
| if (Verbose) |
| { |
| mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); |
| mprintf(L"\n%21ls %9ls %3d%% %-27ls %u",UnpSizeText, |
| PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize), |
| VolNumText,FileCount); |
| } |
| else |
| { |
| mprintf(L"\n----------- --------- ---------- ----- ----"); |
| mprintf(L"\n%21ls %-16ls %u",UnpSizeText,VolNumText,FileCount); |
| } |
| |
| SumFileCount+=FileCount; |
| SumUnpSize+=TotalUnpSize; |
| SumPackSize+=TotalPackSize; |
| mprintf(L"\n"); |
| } |
| else |
| mprintf(St(MListNoFiles)); |
| } |
| |
| ArcCount++; |
| |
| #ifndef NOVOLUME |
| if (Cmd->VolSize!=0 && (Arc.FileHead.SplitAfter || |
| (Arc.GetHeaderType()==HEAD_ENDARC && Arc.EndArcHead.NextVolume)) && |
| MergeArchive(Arc,NULL,false,Cmd->Command[0])) |
| Arc.Seek(0,SEEK_SET); |
| else |
| #endif |
| break; |
| } |
| else |
| { |
| if (Cmd->ArcNames.ItemsCount()<2 && !Bare) |
| mprintf(St(MNotRAR),Arc.FileName); |
| break; |
| } |
| } |
| } |
| |
| // Clean user entered password. Not really required, just for extra safety. |
| if (Cmd->ManualPassword) |
| Cmd->Password.Clean(); |
| |
| if (ArcCount>1 && !Bare && !Technical) |
| { |
| wchar UnpSizeText[20],PackSizeText[20]; |
| itoa(SumUnpSize,UnpSizeText,ASIZE(UnpSizeText)); |
| itoa(SumPackSize,PackSizeText,ASIZE(PackSizeText)); |
| |
| if (Verbose) |
| mprintf(L"%21ls %9ls %3d%% %28ls %u",UnpSizeText,PackSizeText, |
| ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount); |
| else |
| mprintf(L"%21ls %18s %lu",UnpSizeText,L"",SumFileCount); |
| } |
| } |
| |
| |
| enum LISTCOL_TYPE { |
| LCOL_NAME,LCOL_ATTR,LCOL_SIZE,LCOL_PACKED,LCOL_RATIO,LCOL_CSUM,LCOL_ENCR |
| }; |
| |
| |
| void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare) |
| { |
| wchar *Name=hd.FileName; |
| RARFORMAT Format=Arc.Format; |
| |
| if (Bare) |
| { |
| mprintf(L"%s\n",Name); |
| return; |
| } |
| |
| if (!TitleShown && !Technical) |
| { |
| if (Verbose) |
| { |
| mprintf(L"\n%ls",St(MListTitleV)); |
| mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); |
| } |
| else |
| { |
| mprintf(L"\n%ls",St(MListTitleL)); |
| mprintf(L"\n----------- --------- ---------- ----- ----"); |
| } |
| TitleShown=true; |
| } |
| |
| wchar UnpSizeText[30],PackSizeText[30]; |
| if (hd.UnpSize==INT64NDF) |
| wcscpy(UnpSizeText,L"?"); |
| else |
| itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText)); |
| itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText)); |
| |
| wchar AttrStr[30]; |
| if (hd.HeaderType==HEAD_SERVICE) |
| swprintf(AttrStr,ASIZE(AttrStr),L"%cB",hd.Inherited ? 'I' : '.'); |
| else |
| ListFileAttr(hd.FileAttr,hd.HSType,AttrStr,ASIZE(AttrStr)); |
| |
| wchar RatioStr[10]; |
| |
| if (hd.SplitBefore && hd.SplitAfter) |
| wcscpy(RatioStr,L"<->"); |
| else |
| if (hd.SplitBefore) |
| wcscpy(RatioStr,L"<--"); |
| else |
| if (hd.SplitAfter) |
| wcscpy(RatioStr,L"-->"); |
| else |
| swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize)); |
| |
| wchar DateStr[50]; |
| hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical); |
| |
| if (Technical) |
| { |
| mprintf(L"\n%12s: %s",St(MListName),Name); |
| |
| bool FileBlock=hd.HeaderType==HEAD_FILE; |
| |
| if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM)) |
| { |
| mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream)); |
| wchar StreamName[NM]; |
| GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName)); |
| mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName); |
| } |
| else |
| { |
| const wchar *Type=St(FileBlock ? (hd.Dir ? MListDir:MListFile):MListService); |
| |
| if (hd.RedirType!=FSREDIR_NONE) |
| switch(hd.RedirType) |
| { |
| case FSREDIR_UNIXSYMLINK: |
| Type=St(MListUSymlink); break; |
| case FSREDIR_WINSYMLINK: |
| Type=St(MListWSymlink); break; |
| case FSREDIR_JUNCTION: |
| Type=St(MListJunction); break; |
| case FSREDIR_HARDLINK: |
| Type=St(MListHardlink); break; |
| case FSREDIR_FILECOPY: |
| Type=St(MListCopy); break; |
| case FSREDIR_NONE: |
| break; |
| } |
| mprintf(L"\n%12ls: %ls",St(MListType),Type); |
| if (hd.RedirType!=FSREDIR_NONE) |
| { |
| if (Format==RARFMT15) |
| { |
| char LinkTargetA[NM]; |
| if (Arc.FileHead.Encrypted) |
| { |
| // Link data are encrypted. We would need to ask for password |
| // and initialize decryption routine to display the link target. |
| strncpyz(LinkTargetA,"*<-?->",ASIZE(LinkTargetA)); |
| } |
| else |
| { |
| int DataSize=(int)Min(hd.PackSize,ASIZE(LinkTargetA)-1); |
| Arc.Read(LinkTargetA,DataSize); |
| LinkTargetA[DataSize > 0 ? DataSize : 0] = 0; |
| } |
| wchar LinkTarget[NM]; |
| CharToWide(LinkTargetA,LinkTarget,ASIZE(LinkTarget)); |
| mprintf(L"\n%12ls: %ls",St(MListTarget),LinkTarget); |
| } |
| else |
| mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName); |
| } |
| } |
| if (!hd.Dir) |
| { |
| mprintf(L"\n%12ls: %ls",St(MListSize),UnpSizeText); |
| mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText); |
| mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr); |
| } |
| if (hd.mtime.IsSet()) |
| mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr); |
| if (hd.ctime.IsSet()) |
| { |
| hd.ctime.GetText(DateStr,ASIZE(DateStr),true); |
| mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr); |
| } |
| if (hd.atime.IsSet()) |
| { |
| hd.atime.GetText(DateStr,ASIZE(DateStr),true); |
| mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr); |
| } |
| mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr); |
| if (hd.FileHash.Type==HASH_CRC32) |
| mprintf(L"\n%12ls: %8.8X", |
| hd.UseHashKey ? L"CRC32 MAC":hd.SplitAfter ? L"Pack-CRC32":L"CRC32", |
| hd.FileHash.CRC32); |
| if (hd.FileHash.Type==HASH_BLAKE2) |
| { |
| wchar BlakeStr[BLAKE2_DIGEST_SIZE*2+1]; |
| BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,NULL,BlakeStr,ASIZE(BlakeStr)); |
| mprintf(L"\n%12ls: %ls", |
| hd.UseHashKey ? L"BLAKE2 MAC":hd.SplitAfter ? L"Pack-BLAKE2":L"BLAKE2", |
| BlakeStr); |
| } |
| |
| const wchar *HostOS=L""; |
| if (Format==RARFMT50 && hd.HSType!=HSYS_UNKNOWN) |
| HostOS=hd.HSType==HSYS_WINDOWS ? L"Windows":L"Unix"; |
| if (Format==RARFMT15) |
| { |
| static const wchar *RarOS[]={ |
| L"DOS",L"OS/2",L"Windows",L"Unix",L"Mac OS",L"BeOS",L"WinCE",L"",L"",L"" |
| }; |
| if (hd.HostOS<ASIZE(RarOS)) |
| HostOS=RarOS[hd.HostOS]; |
| } |
| if (*HostOS!=0) |
| mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS); |
| |
| mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo), |
| Format==RARFMT15 ? L"3.0":L"5.0",hd.UnpVer,hd.Method, |
| hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400, |
| hd.WinSize>=0x100000 ? L"M":L"K"); |
| |
| if (hd.Solid || hd.Encrypted) |
| { |
| mprintf(L"\n%12ls: ",St(MListFlags)); |
| if (hd.Solid) |
| mprintf(L"%ls ",St(MListSolid)); |
| if (hd.Encrypted) |
| mprintf(L"%ls ",St(MListEnc)); |
| } |
| |
| if (hd.Version) |
| { |
| uint Version=ParseVersionFileName(Name,false); |
| if (Version!=0) |
| mprintf(L"\n%12ls: %u",St(MListFileVer),Version); |
| } |
| |
| if (hd.UnixOwnerSet) |
| { |
| mprintf(L"\n%12ls: ",L"Unix owner"); |
| if (*hd.UnixOwnerName!=0) |
| mprintf(L"%ls:",GetWide(hd.UnixOwnerName)); |
| if (*hd.UnixGroupName!=0) |
| mprintf(L"%ls",GetWide(hd.UnixGroupName)); |
| if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric)) |
| mprintf(L" "); |
| if (hd.UnixOwnerNumeric) |
| mprintf(L"#%d:",hd.UnixOwnerID); |
| if (hd.UnixGroupNumeric) |
| mprintf(L"#%d:",hd.UnixGroupID); |
| } |
| |
| mprintf(L"\n"); |
| return; |
| } |
| |
| mprintf(L"\n%c%10ls %9ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText); |
| |
| if (Verbose) |
| mprintf(L"%9ls %4ls ",PackSizeText,RatioStr); |
| |
| mprintf(L" %ls ",DateStr); |
| |
| if (Verbose) |
| { |
| if (hd.FileHash.Type==HASH_CRC32) |
| mprintf(L"%8.8X ",hd.FileHash.CRC32); |
| else |
| if (hd.FileHash.Type==HASH_BLAKE2) |
| { |
| byte *S=hd.FileHash.Digest; |
| mprintf(L"%02x%02x..%02x ",S[0],S[1],S[31]); |
| } |
| else |
| mprintf(L"???????? "); |
| } |
| mprintf(L"%ls",Name); |
| } |
| |
| /* |
| void ListSymLink(Archive &Arc) |
| { |
| if (Arc.FileHead.HSType==HSYS_UNIX && (Arc.FileHead.FileAttr & 0xF000)==0xA000) |
| if (Arc.FileHead.Encrypted) |
| { |
| // Link data are encrypted. We would need to ask for password |
| // and initialize decryption routine to display the link target. |
| mprintf(L"\n%22ls %ls",L"-->",L"*<-?->"); |
| } |
| else |
| { |
| char FileName[NM]; |
| uint DataSize=(uint)Min(Arc.FileHead.PackSize,sizeof(FileName)-1); |
| Arc.Read(FileName,DataSize); |
| FileName[DataSize]=0; |
| mprintf(L"\n%22ls %ls",L"-->",GetWide(FileName)); |
| } |
| } |
| */ |
| |
| void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize) |
| { |
| switch(HostType) |
| { |
| case HSYS_WINDOWS: |
| swprintf(AttrStr,AttrSize,L"%c%c%c%c%c%c%c", |
| (A & 0x2000)!=0 ? 'I' : '.', // Not content indexed. |
| (A & 0x0800)!=0 ? 'C' : '.', // Compressed. |
| (A & 0x0020)!=0 ? 'A' : '.', // Archive. |
| (A & 0x0010)!=0 ? 'D' : '.', // Directory. |
| (A & 0x0004)!=0 ? 'S' : '.', // System. |
| (A & 0x0002)!=0 ? 'H' : '.', // Hidden. |
| (A & 0x0001)!=0 ? 'R' : '.'); // Read-only. |
| break; |
| case HSYS_UNIX: |
| switch (A & 0xF000) |
| { |
| case 0x4000: |
| AttrStr[0]='d'; |
| break; |
| case 0xA000: |
| AttrStr[0]='l'; |
| break; |
| default: |
| AttrStr[0]='-'; |
| break; |
| } |
| swprintf(AttrStr+1,AttrSize-1,L"%c%c%c%c%c%c%c%c%c", |
| (A & 0x0100) ? 'r' : '-', |
| (A & 0x0080) ? 'w' : '-', |
| (A & 0x0040) ? ((A & 0x0800)!=0 ? 's':'x'):((A & 0x0800)!=0 ? 'S':'-'), |
| (A & 0x0020) ? 'r' : '-', |
| (A & 0x0010) ? 'w' : '-', |
| (A & 0x0008) ? ((A & 0x0400)!=0 ? 's':'x'):((A & 0x0400)!=0 ? 'S':'-'), |
| (A & 0x0004) ? 'r' : '-', |
| (A & 0x0002) ? 'w' : '-', |
| (A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-'); |
| break; |
| case HSYS_UNKNOWN: |
| wcscpy(AttrStr,L"?"); |
| break; |
| } |
| } |