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