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