| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 | #include "rar.hpp"static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames);static void ListSymLink(Archive &Arc);static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize);static void ListOldSubHeader(Archive &Arc);static void ListNewSubHeader(CommandData *Cmd,Archive &Arc);void ListArchive(CommandData *Cmd){  int64 SumPackSize=0,SumUnpSize=0;  uint ArcCount=0,SumFileCount=0;  bool Technical=(Cmd->Command[1]=='T');  bool ShowService=Technical && Cmd->Command[2]=='A';  bool Bare=(Cmd->Command[1]=='B');  bool Verbose=(Cmd->Command[0]=='V');  wchar ArcName[NM];  while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))  {    if (Cmd->ManualPassword)      Cmd->Password.Clean(); // Clean user entered password before processing next archive.    Archive Arc(Cmd);    if (!Arc.WOpen(ArcName))      continue;    bool FileMatched=true;    while (true)    {      int64 TotalPackSize=0,TotalUnpSize=0;      uint FileCount=0;      if (Arc.IsArchive(true))      {        bool TitleShown=false;        if (!Bare)        {          Arc.ViewComment();          mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName);          mprintf(L"\n%s: ",St(MListDetails));          uint SetCount=0;          const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5");          mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", Fmt);          if (Arc.Solid)            mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSolid));          if (Arc.SFXSize>0)            mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSFX));          if (Arc.Volume)            if (Arc.Format==RARFMT50)            {              // RAR 5.0 archives store the volume number in main header,              // so it is already available now.              if (SetCount++ > 0)                mprintf(L", ");              mprintf(St(MVolumeNumber),Arc.VolNumber+1);            }            else              mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListVolume));          if (Arc.Protected)            mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListRR));          if (Arc.Locked)            mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock));          if (Arc.Encrypted)            mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead));          mprintf(L"\n");        }        wchar VolNumText[50];        *VolNumText=0;        while (Arc.ReadHeader()>0)        {          Wait(); // Allow quit listing with Ctrl+C.          HEADER_TYPE HeaderType=Arc.GetHeaderType();          if (HeaderType==HEAD_ENDARC)          {#ifndef SFX_MODULE            // Only RAR 1.5 archives store the volume number in end record.            if (Arc.EndArcHead.StoreVolNumber && Arc.Format==RARFMT15)              swprintf(VolNumText,ASIZE(VolNumText),L"%.10ls %u",St(MListVolume),Arc.VolNumber+1);#endif            if (Technical && ShowService)            {              mprintf(L"\n%12ls: %ls",St(MListService),L"EOF");              if (*VolNumText!=0)                mprintf(L"\n%12ls: %ls",St(MListFlags),VolNumText);              mprintf(L"\n");            }            break;          }          switch(HeaderType)          {            case HEAD_FILE:              FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0;              if (FileMatched)              {                ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare,Cmd->DisableNames);                if (!Arc.FileHead.SplitBefore)                {                  TotalUnpSize+=Arc.FileHead.UnpSize;                  FileCount++;                }                TotalPackSize+=Arc.FileHead.PackSize;              }              break;            case HEAD_SERVICE:              if (FileMatched && !Bare)              {                if (Technical && ShowService)                  ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false,Cmd->DisableNames);              }              break;          }          Arc.SeekToNext();        }        if (!Bare && !Technical)          if (TitleShown)          {            wchar UnpSizeText[20];            itoa(TotalUnpSize,UnpSizeText,ASIZE(UnpSizeText));                    wchar PackSizeText[20];            itoa(TotalPackSize,PackSizeText,ASIZE(PackSizeText));                    if (Verbose)            {              mprintf(L"\n----------- ---------  -------- ----- ---------- -----  --------  ----");              mprintf(L"\n%21ls %9ls %3d%%  %-27ls %u",UnpSizeText,                      PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize),                      VolNumText,FileCount);            }            else            {              mprintf(L"\n----------- ---------  ---------- -----  ----");              mprintf(L"\n%21ls  %-16ls  %u",UnpSizeText,VolNumText,FileCount);            }            SumFileCount+=FileCount;            SumUnpSize+=TotalUnpSize;            SumPackSize+=TotalPackSize;            mprintf(L"\n");          }          else            mprintf(St(MListNoFiles));        ArcCount++;#ifndef NOVOLUME        if (Cmd->VolSize!=0 && (Arc.FileHead.SplitAfter ||            Arc.GetHeaderType()==HEAD_ENDARC && Arc.EndArcHead.NextVolume) &&            MergeArchive(Arc,NULL,false,Cmd->Command[0]))          Arc.Seek(0,SEEK_SET);        else#endif          break;      }      else      {        if (Cmd->ArcNames.ItemsCount()<2 && !Bare)          mprintf(St(MNotRAR),Arc.FileName);        break;      }    }  }  // Clean user entered password. Not really required, just for extra safety.  if (Cmd->ManualPassword)    Cmd->Password.Clean();  if (ArcCount>1 && !Bare && !Technical)  {    wchar UnpSizeText[20],PackSizeText[20];    itoa(SumUnpSize,UnpSizeText,ASIZE(UnpSizeText));    itoa(SumPackSize,PackSizeText,ASIZE(PackSizeText));    if (Verbose)      mprintf(L"%21ls %9ls %3d%% %28ls %u",UnpSizeText,PackSizeText,              ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount);    else      mprintf(L"%21ls %18s %lu",UnpSizeText,L"",SumFileCount);  }}enum LISTCOL_TYPE {  LCOL_NAME,LCOL_ATTR,LCOL_SIZE,LCOL_PACKED,LCOL_RATIO,LCOL_CSUM,LCOL_ENCR};void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames){  if (!TitleShown && !Technical && !Bare)  {    if (Verbose)    {      mprintf(L"\n%ls",St(MListTitleV));      if (!DisableNames)        mprintf(L"\n----------- ---------  -------- ----- ---------- -----  --------  ----");    }    else    {      mprintf(L"\n%ls",St(MListTitleL));      if (!DisableNames)        mprintf(L"\n----------- ---------  ---------- -----  ----");    }    // Must be set even in DisableNames mode to suppress "0 files" output    // unless no files are matched.    TitleShown=true;  }  if (DisableNames)    return;  wchar *Name=hd.FileName;  RARFORMAT Format=Arc.Format;  if (Bare)  {    mprintf(L"%s\n",Name);    return;  }  wchar UnpSizeText[30],PackSizeText[30];  if (hd.UnpSize==INT64NDF)    wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText));  else    itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText));  itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText));  wchar AttrStr[30];  if (hd.HeaderType==HEAD_SERVICE)    swprintf(AttrStr,ASIZE(AttrStr),L"%cB",hd.Inherited ? 'I' : '.');  else    ListFileAttr(hd.FileAttr,hd.HSType,AttrStr,ASIZE(AttrStr));  wchar RatioStr[10];  if (hd.SplitBefore && hd.SplitAfter)    wcsncpyz(RatioStr,L"<->",ASIZE(RatioStr));  else    if (hd.SplitBefore)      wcsncpyz(RatioStr,L"<--",ASIZE(RatioStr));    else      if (hd.SplitAfter)        wcsncpyz(RatioStr,L"-->",ASIZE(RatioStr));      else        swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));  wchar DateStr[50];  hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical);  if (Technical)  {    mprintf(L"\n%12s: %s",St(MListName),Name);    bool FileBlock=hd.HeaderType==HEAD_FILE;    if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))    {      mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream));      wchar StreamName[NM];      GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName));      mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName);    }    else    {      const wchar *Type=St(FileBlock ? (hd.Dir ? MListDir:MListFile):MListService);          if (hd.RedirType!=FSREDIR_NONE)        switch(hd.RedirType)        {          case FSREDIR_UNIXSYMLINK:            Type=St(MListUSymlink); break;          case FSREDIR_WINSYMLINK:            Type=St(MListWSymlink); break;          case FSREDIR_JUNCTION:            Type=St(MListJunction); break;          case FSREDIR_HARDLINK:            Type=St(MListHardlink); break;          case FSREDIR_FILECOPY:            Type=St(MListCopy);     break;        }      mprintf(L"\n%12ls: %ls",St(MListType),Type);      if (hd.RedirType!=FSREDIR_NONE)        if (Format==RARFMT15)        {          char LinkTargetA[NM];          if (Arc.FileHead.Encrypted)          {            // Link data are encrypted. We would need to ask for password            // and initialize decryption routine to display the link target.            strncpyz(LinkTargetA,"*<-?->",ASIZE(LinkTargetA));          }          else          {            int DataSize=(int)Min(hd.PackSize,ASIZE(LinkTargetA)-1);            Arc.Read(LinkTargetA,DataSize);            LinkTargetA[DataSize > 0 ? DataSize : 0] = 0;          }          wchar LinkTarget[NM];          CharToWide(LinkTargetA,LinkTarget,ASIZE(LinkTarget));          mprintf(L"\n%12ls: %ls",St(MListTarget),LinkTarget);        }        else          mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName);    }    if (!hd.Dir)    {      mprintf(L"\n%12ls: %ls",St(MListSize),UnpSizeText);      mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText);      mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr);    }    bool WinTitles=false;#ifdef _WIN_ALL    WinTitles=true;#endif    if (hd.mtime.IsSet())      mprintf(L"\n%12ls: %ls",St(WinTitles ? MListModified:MListMtime),DateStr);    if (hd.ctime.IsSet())    {      hd.ctime.GetText(DateStr,ASIZE(DateStr),true);      mprintf(L"\n%12ls: %ls",St(WinTitles ? MListCreated:MListCtime),DateStr);    }    if (hd.atime.IsSet())    {      hd.atime.GetText(DateStr,ASIZE(DateStr),true);      mprintf(L"\n%12ls: %ls",St(WinTitles ? MListAccessed:MListAtime),DateStr);    }    mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr);    if (hd.FileHash.Type==HASH_CRC32)      mprintf(L"\n%12ls: %8.8X",        hd.UseHashKey ? L"CRC32 MAC":hd.SplitAfter ? L"Pack-CRC32":L"CRC32",        hd.FileHash.CRC32);    if (hd.FileHash.Type==HASH_BLAKE2)    {      wchar BlakeStr[BLAKE2_DIGEST_SIZE*2+1];      BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,NULL,BlakeStr,ASIZE(BlakeStr));      mprintf(L"\n%12ls: %ls",        hd.UseHashKey ? L"BLAKE2 MAC":hd.SplitAfter ? L"Pack-BLAKE2":L"BLAKE2",        BlakeStr);    }    const wchar *HostOS=L"";    if (Format==RARFMT50 && hd.HSType!=HSYS_UNKNOWN)      HostOS=hd.HSType==HSYS_WINDOWS ? L"Windows":L"Unix";    if (Format==RARFMT15)    {      static const wchar *RarOS[]={        L"DOS",L"OS/2",L"Windows",L"Unix",L"Mac OS",L"BeOS",L"WinCE",L"",L"",L""      };      if (hd.HostOS<ASIZE(RarOS))        HostOS=RarOS[hd.HostOS];    }    if (*HostOS!=0)      mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS);    mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo),            Format==RARFMT15 ? L"1.5":L"5.0",            hd.UnpVer==VER_UNKNOWN ? 0 : hd.UnpVer,hd.Method,            hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400,            hd.WinSize>=0x100000 ? L"M":L"K");    if (hd.Solid || hd.Encrypted)    {      mprintf(L"\n%12ls: ",St(MListFlags));      if (hd.Solid)        mprintf(L"%ls ",St(MListSolid));      if (hd.Encrypted)        mprintf(L"%ls ",St(MListEnc));    }    if (hd.Version)    {      uint Version=ParseVersionFileName(Name,false);      if (Version!=0)        mprintf(L"\n%12ls: %u",St(MListFileVer),Version);    }    if (hd.UnixOwnerSet)    {      mprintf(L"\n%12ls: ",L"Unix owner");      if (*hd.UnixOwnerName!=0)        mprintf(L"%ls",GetWide(hd.UnixOwnerName));      else        if (hd.UnixOwnerNumeric)          mprintf(L"#%d",hd.UnixOwnerID);      mprintf(L":");      if (*hd.UnixGroupName!=0)        mprintf(L"%ls",GetWide(hd.UnixGroupName));      else        if (hd.UnixGroupNumeric)          mprintf(L"#%d",hd.UnixGroupID);    }    mprintf(L"\n");    return;  }  mprintf(L"\n%c%10ls %9ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText);  if (Verbose)    mprintf(L"%9ls %4ls ",PackSizeText,RatioStr);  mprintf(L" %ls  ",DateStr);  if (Verbose)  {    if (hd.FileHash.Type==HASH_CRC32)      mprintf(L"%8.8X  ",hd.FileHash.CRC32);    else      if (hd.FileHash.Type==HASH_BLAKE2)      {        byte *S=hd.FileHash.Digest;        mprintf(L"%02x%02x..%02x  ",S[0],S[1],S[31]);      }      else        mprintf(L"????????  ");  }  mprintf(L"%ls",Name);}/*void ListSymLink(Archive &Arc){  if (Arc.FileHead.HSType==HSYS_UNIX && (Arc.FileHead.FileAttr & 0xF000)==0xA000)    if (Arc.FileHead.Encrypted)    {      // Link data are encrypted. We would need to ask for password      // and initialize decryption routine to display the link target.      mprintf(L"\n%22ls %ls",L"-->",L"*<-?->");    }    else    {      char FileName[NM];      uint DataSize=(uint)Min(Arc.FileHead.PackSize,sizeof(FileName)-1);      Arc.Read(FileName,DataSize);      FileName[DataSize]=0;      mprintf(L"\n%22ls %ls",L"-->",GetWide(FileName));    }}*/void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize){  switch(HostType)  {    case HSYS_WINDOWS:      swprintf(AttrStr,AttrSize,L"%c%c%c%c%c%c%c",              (A & 0x2000)!=0 ? 'I' : '.',  // Not content indexed.              (A & 0x0800)!=0 ? 'C' : '.',  // Compressed.              (A & 0x0020)!=0 ? 'A' : '.',  // Archive.              (A & 0x0010)!=0 ? 'D' : '.',  // Directory.              (A & 0x0004)!=0 ? 'S' : '.',  // System.              (A & 0x0002)!=0 ? 'H' : '.',  // Hidden.              (A & 0x0001)!=0 ? 'R' : '.'); // Read-only.      break;    case HSYS_UNIX:      switch (A & 0xF000)      {        case 0x4000:          AttrStr[0]='d';          break;        case 0xA000:          AttrStr[0]='l';          break;        default:          AttrStr[0]='-';          break;      }      swprintf(AttrStr+1,AttrSize-1,L"%c%c%c%c%c%c%c%c%c",              (A & 0x0100) ? 'r' : '-',              (A & 0x0080) ? 'w' : '-',              (A & 0x0040) ? ((A & 0x0800)!=0 ? 's':'x'):((A & 0x0800)!=0 ? 'S':'-'),              (A & 0x0020) ? 'r' : '-',              (A & 0x0010) ? 'w' : '-',              (A & 0x0008) ? ((A & 0x0400)!=0 ? 's':'x'):((A & 0x0400)!=0 ? 'S':'-'),              (A & 0x0004) ? 'r' : '-',              (A & 0x0002) ? 'w' : '-',              (A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-');      break;    case HSYS_UNKNOWN:      wcsncpyz(AttrStr,L"?",AttrSize);      break;  }}
 |