1 #include "rar.hpp"
2 
3 static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames);
4 static void ListSymLink(Archive &Arc);
5 static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize);
6 static void ListOldSubHeader(Archive &Arc);
7 static void ListNewSubHeader(CommandData *Cmd,Archive &Arc);
8 
ListArchive(CommandData * Cmd)9 void ListArchive(CommandData *Cmd)
10 {
11   int64 SumPackSize=0,SumUnpSize=0;
12   uint ArcCount=0,SumFileCount=0;
13   bool Technical=(Cmd->Command[1]=='T');
14   bool ShowService=Technical && Cmd->Command[2]=='A';
15   bool Bare=(Cmd->Command[1]=='B');
16   bool Verbose=(Cmd->Command[0]=='V');
17 
18   wchar ArcName[NM];
19   while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
20   {
21     if (Cmd->ManualPassword)
22       Cmd->Password.Clean(); // Clean user entered password before processing next archive.
23 
24     Archive Arc(Cmd);
25 #ifdef _WIN_ALL
26     Arc.RemoveSequentialFlag();
27 #endif
28     if (!Arc.WOpen(ArcName))
29       continue;
30     bool FileMatched=true;
31     while (true)
32     {
33       int64 TotalPackSize=0,TotalUnpSize=0;
34       uint FileCount=0;
35       if (Arc.IsArchive(true))
36       {
37         bool TitleShown=false;
38         if (!Bare)
39         {
40           Arc.ViewComment();
41           mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName);
42           mprintf(L"\n%s: ",St(MListDetails));
43           uint SetCount=0;
44           const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5");
45           mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", Fmt);
46           if (Arc.Solid)
47             mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSolid));
48           if (Arc.SFXSize>0)
49             mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSFX));
50           if (Arc.Volume)
51             if (Arc.Format==RARFMT50)
52             {
53               // RAR 5.0 archives store the volume number in main header,
54               // so it is already available now.
55               if (SetCount++ > 0)
56                 mprintf(L", ");
57               mprintf(St(MVolumeNumber),Arc.VolNumber+1);
58             }
59             else
60               mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListVolume));
61           if (Arc.Protected)
62             mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListRR));
63           if (Arc.Locked)
64             mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock));
65           if (Arc.Encrypted)
66             mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead));
67           mprintf(L"\n");
68         }
69 
70         wchar VolNumText[50];
71         *VolNumText=0;
72         while (Arc.ReadHeader()>0)
73         {
74           Wait(); // Allow quit listing with Ctrl+C.
75           HEADER_TYPE HeaderType=Arc.GetHeaderType();
76           if (HeaderType==HEAD_ENDARC)
77           {
78 #ifndef SFX_MODULE
79             // Only RAR 1.5 archives store the volume number in end record.
80             if (Arc.EndArcHead.StoreVolNumber && Arc.Format==RARFMT15)
81               swprintf(VolNumText,ASIZE(VolNumText),L"%.10ls %u",St(MListVolume),Arc.VolNumber+1);
82 #endif
83             if (Technical && ShowService)
84             {
85               mprintf(L"\n%12ls: %ls",St(MListService),L"EOF");
86               if (*VolNumText!=0)
87                 mprintf(L"\n%12ls: %ls",St(MListFlags),VolNumText);
88               mprintf(L"\n");
89             }
90             break;
91           }
92           switch(HeaderType)
93           {
94             case HEAD_FILE:
95               FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0;
96               if (FileMatched)
97               {
98                 ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare,Cmd->DisableNames);
99                 if (!Arc.FileHead.SplitBefore)
100                 {
101                   TotalUnpSize+=Arc.FileHead.UnpSize;
102                   FileCount++;
103                 }
104                 TotalPackSize+=Arc.FileHead.PackSize;
105               }
106               break;
107             case HEAD_SERVICE:
108               if (FileMatched && !Bare)
109               {
110                 if (Technical && ShowService)
111                   ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false,Cmd->DisableNames);
112               }
113               break;
114           }
115           Arc.SeekToNext();
116         }
117         if (!Bare && !Technical)
118           if (TitleShown)
119           {
120             wchar UnpSizeText[20];
121             itoa(TotalUnpSize,UnpSizeText,ASIZE(UnpSizeText));
122 
123             wchar PackSizeText[20];
124             itoa(TotalPackSize,PackSizeText,ASIZE(PackSizeText));
125 
126             if (Verbose)
127             {
128               mprintf(L"\n----------- ---------  -------- ----- ---------- -----  --------  ----");
129               mprintf(L"\n%21ls %9ls %3d%%  %-27ls %u",UnpSizeText,
130                       PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize),
131                       VolNumText,FileCount);
132             }
133             else
134             {
135               mprintf(L"\n----------- ---------  ---------- -----  ----");
136               mprintf(L"\n%21ls  %-16ls  %u",UnpSizeText,VolNumText,FileCount);
137             }
138 
139             SumFileCount+=FileCount;
140             SumUnpSize+=TotalUnpSize;
141             SumPackSize+=TotalPackSize;
142             mprintf(L"\n");
143           }
144           else
145             mprintf(St(MListNoFiles));
146 
147         ArcCount++;
148 
149 #ifndef NOVOLUME
150         if (Cmd->VolSize!=0 && (Arc.FileHead.SplitAfter ||
151             Arc.GetHeaderType()==HEAD_ENDARC && Arc.EndArcHead.NextVolume) &&
152             MergeArchive(Arc,NULL,false,Cmd->Command[0]))
153           Arc.Seek(0,SEEK_SET);
154         else
155 #endif
156           break;
157       }
158       else
159       {
160         if (Cmd->ArcNames.ItemsCount()<2 && !Bare)
161           mprintf(St(MNotRAR),Arc.FileName);
162         break;
163       }
164     }
165   }
166 
167   // Clean user entered password. Not really required, just for extra safety.
168   if (Cmd->ManualPassword)
169     Cmd->Password.Clean();
170 
171   if (ArcCount>1 && !Bare && !Technical)
172   {
173     wchar UnpSizeText[20],PackSizeText[20];
174     itoa(SumUnpSize,UnpSizeText,ASIZE(UnpSizeText));
175     itoa(SumPackSize,PackSizeText,ASIZE(PackSizeText));
176 
177     if (Verbose)
178       mprintf(L"%21ls %9ls %3d%% %28ls %u",UnpSizeText,PackSizeText,
179               ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount);
180     else
181       mprintf(L"%21ls %18s %lu",UnpSizeText,L"",SumFileCount);
182   }
183 }
184 
185 
186 enum LISTCOL_TYPE {
187   LCOL_NAME,LCOL_ATTR,LCOL_SIZE,LCOL_PACKED,LCOL_RATIO,LCOL_CSUM,LCOL_ENCR
188 };
189 
190 
ListFileHeader(Archive & Arc,FileHeader & hd,bool & TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames)191 void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames)
192 {
193   if (!TitleShown && !Technical && !Bare)
194   {
195     if (Verbose)
196     {
197       mprintf(L"\n%ls",St(MListTitleV));
198       if (!DisableNames)
199         mprintf(L"\n----------- ---------  -------- ----- ---------- -----  --------  ----");
200     }
201     else
202     {
203       mprintf(L"\n%ls",St(MListTitleL));
204       if (!DisableNames)
205         mprintf(L"\n----------- ---------  ---------- -----  ----");
206     }
207     // Must be set even in DisableNames mode to suppress "0 files" output
208     // unless no files are matched.
209     TitleShown=true;
210   }
211   if (DisableNames)
212     return;
213 
214   wchar *Name=hd.FileName;
215   RARFORMAT Format=Arc.Format;
216 
217   if (Bare)
218   {
219     mprintf(L"%s\n",Name);
220     return;
221   }
222 
223   wchar UnpSizeText[30],PackSizeText[30];
224   if (hd.UnpSize==INT64NDF)
225     wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText));
226   else
227     itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText));
228   itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText));
229 
230   wchar AttrStr[30];
231   if (hd.HeaderType==HEAD_SERVICE)
232     swprintf(AttrStr,ASIZE(AttrStr),L"%cB",hd.Inherited ? 'I' : '.');
233   else
234     ListFileAttr(hd.FileAttr,hd.HSType,AttrStr,ASIZE(AttrStr));
235 
236   wchar RatioStr[10];
237 
238   if (hd.SplitBefore && hd.SplitAfter)
239     wcsncpyz(RatioStr,L"<->",ASIZE(RatioStr));
240   else
241     if (hd.SplitBefore)
242       wcsncpyz(RatioStr,L"<--",ASIZE(RatioStr));
243     else
244       if (hd.SplitAfter)
245         wcsncpyz(RatioStr,L"-->",ASIZE(RatioStr));
246       else
247         swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));
248 
249   wchar DateStr[50];
250   hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical);
251 
252   if (Technical)
253   {
254     mprintf(L"\n%12s: %s",St(MListName),Name);
255 
256     bool FileBlock=hd.HeaderType==HEAD_FILE;
257 
258     if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
259     {
260       mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream));
261       wchar StreamName[NM];
262       GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName));
263       mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName);
264     }
265     else
266     {
267       const wchar *Type=St(FileBlock ? (hd.Dir ? MListDir:MListFile):MListService);
268 
269       if (hd.RedirType!=FSREDIR_NONE)
270         switch(hd.RedirType)
271         {
272           case FSREDIR_UNIXSYMLINK:
273             Type=St(MListUSymlink); break;
274           case FSREDIR_WINSYMLINK:
275             Type=St(MListWSymlink); break;
276           case FSREDIR_JUNCTION:
277             Type=St(MListJunction); break;
278           case FSREDIR_HARDLINK:
279             Type=St(MListHardlink); break;
280           case FSREDIR_FILECOPY:
281             Type=St(MListCopy);     break;
282         }
283       mprintf(L"\n%12ls: %ls",St(MListType),Type);
284       if (hd.RedirType!=FSREDIR_NONE)
285         if (Format==RARFMT15)
286         {
287           char LinkTargetA[NM];
288           if (Arc.FileHead.Encrypted)
289           {
290             // Link data are encrypted. We would need to ask for password
291             // and initialize decryption routine to display the link target.
292             strncpyz(LinkTargetA,"*<-?->",ASIZE(LinkTargetA));
293           }
294           else
295           {
296             int DataSize=(int)Min(hd.PackSize,ASIZE(LinkTargetA)-1);
297             Arc.Read(LinkTargetA,DataSize);
298             LinkTargetA[DataSize > 0 ? DataSize : 0] = 0;
299           }
300           wchar LinkTarget[NM];
301           CharToWide(LinkTargetA,LinkTarget,ASIZE(LinkTarget));
302           mprintf(L"\n%12ls: %ls",St(MListTarget),LinkTarget);
303         }
304         else
305           mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName);
306     }
307     if (!hd.Dir)
308     {
309       mprintf(L"\n%12ls: %ls",St(MListSize),UnpSizeText);
310       mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText);
311       mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr);
312     }
313     if (hd.mtime.IsSet())
314       mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr);
315     if (hd.ctime.IsSet())
316     {
317       hd.ctime.GetText(DateStr,ASIZE(DateStr),true);
318       mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr);
319     }
320     if (hd.atime.IsSet())
321     {
322       hd.atime.GetText(DateStr,ASIZE(DateStr),true);
323       mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr);
324     }
325     mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr);
326     if (hd.FileHash.Type==HASH_CRC32)
327       mprintf(L"\n%12ls: %8.8X",
328         hd.UseHashKey ? L"CRC32 MAC":hd.SplitAfter ? L"Pack-CRC32":L"CRC32",
329         hd.FileHash.CRC32);
330     if (hd.FileHash.Type==HASH_BLAKE2)
331     {
332       wchar BlakeStr[BLAKE2_DIGEST_SIZE*2+1];
333       BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,NULL,BlakeStr,ASIZE(BlakeStr));
334       mprintf(L"\n%12ls: %ls",
335         hd.UseHashKey ? L"BLAKE2 MAC":hd.SplitAfter ? L"Pack-BLAKE2":L"BLAKE2",
336         BlakeStr);
337     }
338 
339     const wchar *HostOS=L"";
340     if (Format==RARFMT50 && hd.HSType!=HSYS_UNKNOWN)
341       HostOS=hd.HSType==HSYS_WINDOWS ? L"Windows":L"Unix";
342     if (Format==RARFMT15)
343     {
344       static const wchar *RarOS[]={
345         L"DOS",L"OS/2",L"Windows",L"Unix",L"Mac OS",L"BeOS",L"WinCE",L"",L"",L""
346       };
347       if (hd.HostOS<ASIZE(RarOS))
348         HostOS=RarOS[hd.HostOS];
349     }
350     if (*HostOS!=0)
351       mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS);
352 
353     mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo),
354             Format==RARFMT15 ? L"1.5":L"5.0",
355             hd.UnpVer==VER_UNKNOWN ? 0 : hd.UnpVer,hd.Method,
356             hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400,
357             hd.WinSize>=0x100000 ? L"M":L"K");
358 
359     if (hd.Solid || hd.Encrypted)
360     {
361       mprintf(L"\n%12ls: ",St(MListFlags));
362       if (hd.Solid)
363         mprintf(L"%ls ",St(MListSolid));
364       if (hd.Encrypted)
365         mprintf(L"%ls ",St(MListEnc));
366     }
367 
368     if (hd.Version)
369     {
370       uint Version=ParseVersionFileName(Name,false);
371       if (Version!=0)
372         mprintf(L"\n%12ls: %u",St(MListFileVer),Version);
373     }
374 
375     if (hd.UnixOwnerSet)
376     {
377       mprintf(L"\n%12ls: ",L"Unix owner");
378       if (*hd.UnixOwnerName!=0)
379         mprintf(L"%ls:",GetWide(hd.UnixOwnerName));
380       if (*hd.UnixGroupName!=0)
381         mprintf(L"%ls",GetWide(hd.UnixGroupName));
382       if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric))
383         mprintf(L"  ");
384       if (hd.UnixOwnerNumeric)
385         mprintf(L"#%d:",hd.UnixOwnerID);
386       if (hd.UnixGroupNumeric)
387         mprintf(L"#%d:",hd.UnixGroupID);
388     }
389 
390     mprintf(L"\n");
391     return;
392   }
393 
394   mprintf(L"\n%c%10ls %9ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText);
395 
396   if (Verbose)
397     mprintf(L"%9ls %4ls ",PackSizeText,RatioStr);
398 
399   mprintf(L" %ls  ",DateStr);
400 
401   if (Verbose)
402   {
403     if (hd.FileHash.Type==HASH_CRC32)
404       mprintf(L"%8.8X  ",hd.FileHash.CRC32);
405     else
406       if (hd.FileHash.Type==HASH_BLAKE2)
407       {
408         byte *S=hd.FileHash.Digest;
409         mprintf(L"%02x%02x..%02x  ",S[0],S[1],S[31]);
410       }
411       else
412         mprintf(L"????????  ");
413   }
414   mprintf(L"%ls",Name);
415 }
416 
417 /*
418 void ListSymLink(Archive &Arc)
419 {
420   if (Arc.FileHead.HSType==HSYS_UNIX && (Arc.FileHead.FileAttr & 0xF000)==0xA000)
421     if (Arc.FileHead.Encrypted)
422     {
423       // Link data are encrypted. We would need to ask for password
424       // and initialize decryption routine to display the link target.
425       mprintf(L"\n%22ls %ls",L"-->",L"*<-?->");
426     }
427     else
428     {
429       char FileName[NM];
430       uint DataSize=(uint)Min(Arc.FileHead.PackSize,sizeof(FileName)-1);
431       Arc.Read(FileName,DataSize);
432       FileName[DataSize]=0;
433       mprintf(L"\n%22ls %ls",L"-->",GetWide(FileName));
434     }
435 }
436 */
437 
ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar * AttrStr,size_t AttrSize)438 void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize)
439 {
440   switch(HostType)
441   {
442     case HSYS_WINDOWS:
443       swprintf(AttrStr,AttrSize,L"%c%c%c%c%c%c%c",
444               (A & 0x2000)!=0 ? 'I' : '.',  // Not content indexed.
445               (A & 0x0800)!=0 ? 'C' : '.',  // Compressed.
446               (A & 0x0020)!=0 ? 'A' : '.',  // Archive.
447               (A & 0x0010)!=0 ? 'D' : '.',  // Directory.
448               (A & 0x0004)!=0 ? 'S' : '.',  // System.
449               (A & 0x0002)!=0 ? 'H' : '.',  // Hidden.
450               (A & 0x0001)!=0 ? 'R' : '.'); // Read-only.
451       break;
452     case HSYS_UNIX:
453       switch (A & 0xF000)
454       {
455         case 0x4000:
456           AttrStr[0]='d';
457           break;
458         case 0xA000:
459           AttrStr[0]='l';
460           break;
461         default:
462           AttrStr[0]='-';
463           break;
464       }
465       swprintf(AttrStr+1,AttrSize-1,L"%c%c%c%c%c%c%c%c%c",
466               (A & 0x0100) ? 'r' : '-',
467               (A & 0x0080) ? 'w' : '-',
468               (A & 0x0040) ? ((A & 0x0800)!=0 ? 's':'x'):((A & 0x0800)!=0 ? 'S':'-'),
469               (A & 0x0020) ? 'r' : '-',
470               (A & 0x0010) ? 'w' : '-',
471               (A & 0x0008) ? ((A & 0x0400)!=0 ? 's':'x'):((A & 0x0400)!=0 ? 'S':'-'),
472               (A & 0x0004) ? 'r' : '-',
473               (A & 0x0002) ? 'w' : '-',
474               (A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-');
475       break;
476     case HSYS_UNKNOWN:
477       wcsncpyz(AttrStr,L"?",AttrSize);
478       break;
479   }
480 }
481