1 #include "rar.hpp"
2 
3 static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare);
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 (1)
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);
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);
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)191 void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare)
192 {
193   wchar *Name=hd.FileName;
194   RARFORMAT Format=Arc.Format;
195 
196   if (Bare)
197   {
198     mprintf(L"%s\n",Name);
199     return;
200   }
201 
202   if (!TitleShown && !Technical)
203   {
204     if (Verbose)
205     {
206       mprintf(L"\n%ls",St(MListTitleV));
207       mprintf(L"\n----------- ---------  -------- ----- ---------- -----  --------  ----");
208     }
209     else
210     {
211       mprintf(L"\n%ls",St(MListTitleL));
212       mprintf(L"\n----------- ---------  ---------- -----  ----");
213     }
214     TitleShown=true;
215   }
216 
217   wchar UnpSizeText[30],PackSizeText[30];
218   if (hd.UnpSize==INT64NDF)
219     wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText));
220   else
221     itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText));
222   itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText));
223 
224   wchar AttrStr[30];
225   if (hd.HeaderType==HEAD_SERVICE)
226     swprintf(AttrStr,ASIZE(AttrStr),L"%cB",hd.Inherited ? 'I' : '.');
227   else
228     ListFileAttr(hd.FileAttr,hd.HSType,AttrStr,ASIZE(AttrStr));
229 
230   wchar RatioStr[10];
231 
232   if (hd.SplitBefore && hd.SplitAfter)
233     wcsncpyz(RatioStr,L"<->",ASIZE(RatioStr));
234   else
235     if (hd.SplitBefore)
236       wcsncpyz(RatioStr,L"<--",ASIZE(RatioStr));
237     else
238       if (hd.SplitAfter)
239         wcsncpyz(RatioStr,L"-->",ASIZE(RatioStr));
240       else
241         swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));
242 
243   wchar DateStr[50];
244   hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical);
245 
246   if (Technical)
247   {
248     mprintf(L"\n%12s: %s",St(MListName),Name);
249 
250     bool FileBlock=hd.HeaderType==HEAD_FILE;
251 
252     if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
253     {
254       mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream));
255       wchar StreamName[NM];
256       GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName));
257       mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName);
258     }
259     else
260     {
261       const wchar *Type=St(FileBlock ? (hd.Dir ? MListDir:MListFile):MListService);
262 
263       if (hd.RedirType!=FSREDIR_NONE)
264         switch(hd.RedirType)
265         {
266           case FSREDIR_UNIXSYMLINK:
267             Type=St(MListUSymlink); break;
268           case FSREDIR_WINSYMLINK:
269             Type=St(MListWSymlink); break;
270           case FSREDIR_JUNCTION:
271             Type=St(MListJunction); break;
272           case FSREDIR_HARDLINK:
273             Type=St(MListHardlink); break;
274           case FSREDIR_FILECOPY:
275             Type=St(MListCopy);     break;
276         }
277       mprintf(L"\n%12ls: %ls",St(MListType),Type);
278       if (hd.RedirType!=FSREDIR_NONE)
279         if (Format==RARFMT15)
280         {
281           char LinkTargetA[NM];
282           if (Arc.FileHead.Encrypted)
283           {
284             // Link data are encrypted. We would need to ask for password
285             // and initialize decryption routine to display the link target.
286             strncpyz(LinkTargetA,"*<-?->",ASIZE(LinkTargetA));
287           }
288           else
289           {
290             int DataSize=(int)Min(hd.PackSize,ASIZE(LinkTargetA)-1);
291             Arc.Read(LinkTargetA,DataSize);
292             LinkTargetA[DataSize > 0 ? DataSize : 0] = 0;
293           }
294           wchar LinkTarget[NM];
295           CharToWide(LinkTargetA,LinkTarget,ASIZE(LinkTarget));
296           mprintf(L"\n%12ls: %ls",St(MListTarget),LinkTarget);
297         }
298         else
299           mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName);
300     }
301     if (!hd.Dir)
302     {
303       mprintf(L"\n%12ls: %ls",St(MListSize),UnpSizeText);
304       mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText);
305       mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr);
306     }
307     if (hd.mtime.IsSet())
308       mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr);
309     if (hd.ctime.IsSet())
310     {
311       hd.ctime.GetText(DateStr,ASIZE(DateStr),true);
312       mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr);
313     }
314     if (hd.atime.IsSet())
315     {
316       hd.atime.GetText(DateStr,ASIZE(DateStr),true);
317       mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr);
318     }
319     mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr);
320     if (hd.FileHash.Type==HASH_CRC32)
321       mprintf(L"\n%12ls: %8.8X",
322         hd.UseHashKey ? L"CRC32 MAC":hd.SplitAfter ? L"Pack-CRC32":L"CRC32",
323         hd.FileHash.CRC32);
324     if (hd.FileHash.Type==HASH_BLAKE2)
325     {
326       wchar BlakeStr[BLAKE2_DIGEST_SIZE*2+1];
327       BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,NULL,BlakeStr,ASIZE(BlakeStr));
328       mprintf(L"\n%12ls: %ls",
329         hd.UseHashKey ? L"BLAKE2 MAC":hd.SplitAfter ? L"Pack-BLAKE2":L"BLAKE2",
330         BlakeStr);
331     }
332 
333     const wchar *HostOS=L"";
334     if (Format==RARFMT50 && hd.HSType!=HSYS_UNKNOWN)
335       HostOS=hd.HSType==HSYS_WINDOWS ? L"Windows":L"Unix";
336     if (Format==RARFMT15)
337     {
338       static const wchar *RarOS[]={
339         L"DOS",L"OS/2",L"Windows",L"Unix",L"Mac OS",L"BeOS",L"WinCE",L"",L"",L""
340       };
341       if (hd.HostOS<ASIZE(RarOS))
342         HostOS=RarOS[hd.HostOS];
343     }
344     if (*HostOS!=0)
345       mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS);
346 
347     mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo),
348             Format==RARFMT15 ? L"1.5":L"5.0",
349             hd.UnpVer==VER_UNKNOWN ? 0 : hd.UnpVer,hd.Method,
350             hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400,
351             hd.WinSize>=0x100000 ? L"M":L"K");
352 
353     if (hd.Solid || hd.Encrypted)
354     {
355       mprintf(L"\n%12ls: ",St(MListFlags));
356       if (hd.Solid)
357         mprintf(L"%ls ",St(MListSolid));
358       if (hd.Encrypted)
359         mprintf(L"%ls ",St(MListEnc));
360     }
361 
362     if (hd.Version)
363     {
364       uint Version=ParseVersionFileName(Name,false);
365       if (Version!=0)
366         mprintf(L"\n%12ls: %u",St(MListFileVer),Version);
367     }
368 
369     if (hd.UnixOwnerSet)
370     {
371       mprintf(L"\n%12ls: ",L"Unix owner");
372       if (*hd.UnixOwnerName!=0)
373         mprintf(L"%ls:",GetWide(hd.UnixOwnerName));
374       if (*hd.UnixGroupName!=0)
375         mprintf(L"%ls",GetWide(hd.UnixGroupName));
376       if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric))
377         mprintf(L"  ");
378       if (hd.UnixOwnerNumeric)
379         mprintf(L"#%d:",hd.UnixOwnerID);
380       if (hd.UnixGroupNumeric)
381         mprintf(L"#%d:",hd.UnixGroupID);
382     }
383 
384     mprintf(L"\n");
385     return;
386   }
387 
388   mprintf(L"\n%c%10ls %9ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText);
389 
390   if (Verbose)
391     mprintf(L"%9ls %4ls ",PackSizeText,RatioStr);
392 
393   mprintf(L" %ls  ",DateStr);
394 
395   if (Verbose)
396   {
397     if (hd.FileHash.Type==HASH_CRC32)
398       mprintf(L"%8.8X  ",hd.FileHash.CRC32);
399     else
400       if (hd.FileHash.Type==HASH_BLAKE2)
401       {
402         byte *S=hd.FileHash.Digest;
403         mprintf(L"%02x%02x..%02x  ",S[0],S[1],S[31]);
404       }
405       else
406         mprintf(L"????????  ");
407   }
408   mprintf(L"%ls",Name);
409 }
410 
411 /*
412 void ListSymLink(Archive &Arc)
413 {
414   if (Arc.FileHead.HSType==HSYS_UNIX && (Arc.FileHead.FileAttr & 0xF000)==0xA000)
415     if (Arc.FileHead.Encrypted)
416     {
417       // Link data are encrypted. We would need to ask for password
418       // and initialize decryption routine to display the link target.
419       mprintf(L"\n%22ls %ls",L"-->",L"*<-?->");
420     }
421     else
422     {
423       char FileName[NM];
424       uint DataSize=(uint)Min(Arc.FileHead.PackSize,sizeof(FileName)-1);
425       Arc.Read(FileName,DataSize);
426       FileName[DataSize]=0;
427       mprintf(L"\n%22ls %ls",L"-->",GetWide(FileName));
428     }
429 }
430 */
431 
ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar * AttrStr,size_t AttrSize)432 void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize)
433 {
434   switch(HostType)
435   {
436     case HSYS_WINDOWS:
437       swprintf(AttrStr,AttrSize,L"%c%c%c%c%c%c%c",
438               (A & 0x2000)!=0 ? 'I' : '.',  // Not content indexed.
439               (A & 0x0800)!=0 ? 'C' : '.',  // Compressed.
440               (A & 0x0020)!=0 ? 'A' : '.',  // Archive.
441               (A & 0x0010)!=0 ? 'D' : '.',  // Directory.
442               (A & 0x0004)!=0 ? 'S' : '.',  // System.
443               (A & 0x0002)!=0 ? 'H' : '.',  // Hidden.
444               (A & 0x0001)!=0 ? 'R' : '.'); // Read-only.
445       break;
446     case HSYS_UNIX:
447       switch (A & 0xF000)
448       {
449         case 0x4000:
450           AttrStr[0]='d';
451           break;
452         case 0xA000:
453           AttrStr[0]='l';
454           break;
455         default:
456           AttrStr[0]='-';
457           break;
458       }
459       swprintf(AttrStr+1,AttrSize-1,L"%c%c%c%c%c%c%c%c%c",
460               (A & 0x0100) ? 'r' : '-',
461               (A & 0x0080) ? 'w' : '-',
462               (A & 0x0040) ? ((A & 0x0800)!=0 ? 's':'x'):((A & 0x0800)!=0 ? 'S':'-'),
463               (A & 0x0020) ? 'r' : '-',
464               (A & 0x0010) ? 'w' : '-',
465               (A & 0x0008) ? ((A & 0x0400)!=0 ? 's':'x'):((A & 0x0400)!=0 ? 'S':'-'),
466               (A & 0x0004) ? 'r' : '-',
467               (A & 0x0002) ? 'w' : '-',
468               (A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-');
469       break;
470     case HSYS_UNKNOWN:
471       wcsncpyz(AttrStr,L"?",AttrSize);
472       break;
473   }
474 }
475