list.cpp 15 KB

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