extract.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. #include "rar.hpp"
  2. CmdExtract::CmdExtract()
  3. {
  4. TotalFileCount=0;
  5. *Password=0;
  6. Unp=new Unpack(&DataIO);
  7. Unp->Init(NULL);
  8. }
  9. CmdExtract::~CmdExtract()
  10. {
  11. delete Unp;
  12. memset(Password,0,sizeof(Password));
  13. }
  14. void CmdExtract::DoExtract(CommandData *Cmd)
  15. {
  16. PasswordCancelled=false;
  17. DataIO.SetCurrentCommand(*Cmd->Command);
  18. FindData FD;
  19. while (Cmd->GetArcName(ArcName,ArcNameW,ASIZE(ArcName)))
  20. if (FindFile::FastFind(ArcName,ArcNameW,&FD))
  21. DataIO.TotalArcSize+=FD.Size;
  22. Cmd->ArcNames->Rewind();
  23. while (Cmd->GetArcName(ArcName,ArcNameW,ASIZE(ArcName)))
  24. {
  25. while (true)
  26. {
  27. wchar PrevCmdPassword[MAXPASSWORD];
  28. wcscpy(PrevCmdPassword,Cmd->Password);
  29. EXTRACT_ARC_CODE Code=ExtractArchive(Cmd);
  30. // Restore Cmd->Password, which could be changed in IsArchive() call
  31. // for next header encrypted archive.
  32. wcscpy(Cmd->Password,PrevCmdPassword);
  33. if (Code!=EXTRACT_ARC_REPEAT)
  34. break;
  35. }
  36. if (FindFile::FastFind(ArcName,ArcNameW,&FD))
  37. DataIO.ProcessedArcSize+=FD.Size;
  38. }
  39. if (TotalFileCount==0 && *Cmd->Command!='I')
  40. {
  41. if (!PasswordCancelled)
  42. {
  43. mprintf(St(MExtrNoFiles));
  44. }
  45. ErrHandler.SetErrorCode(NO_FILES_ERROR);
  46. }
  47. #ifndef GUI
  48. else
  49. if (!Cmd->DisableDone)
  50. if (*Cmd->Command=='I')
  51. mprintf(St(MDone));
  52. else
  53. if (ErrHandler.GetErrorCount()==0)
  54. mprintf(St(MExtrAllOk));
  55. else
  56. mprintf(St(MExtrTotalErr),ErrHandler.GetErrorCount());
  57. #endif
  58. }
  59. void CmdExtract::ExtractArchiveInit(CommandData *Cmd,Archive &Arc)
  60. {
  61. DataIO.UnpArcSize=Arc.FileLength();
  62. FileCount=0;
  63. MatchedArgs=0;
  64. #ifndef SFX_MODULE
  65. FirstFile=true;
  66. #endif
  67. if (*Cmd->Password!=0)
  68. wcscpy(Password,Cmd->Password);
  69. PasswordAll=(*Cmd->Password!=0);
  70. DataIO.UnpVolume=false;
  71. PrevExtracted=false;
  72. SignatureFound=false;
  73. AllMatchesExact=true;
  74. ReconstructDone=false;
  75. AnySolidDataUnpackedWell=false;
  76. StartTime.SetCurrentTime();
  77. }
  78. EXTRACT_ARC_CODE CmdExtract::ExtractArchive(CommandData *Cmd)
  79. {
  80. Archive Arc(Cmd);
  81. if (!Arc.WOpen(ArcName,ArcNameW))
  82. {
  83. ErrHandler.SetErrorCode(OPEN_ERROR);
  84. return(EXTRACT_ARC_NEXT);
  85. }
  86. if (!Arc.IsArchive(true))
  87. {
  88. #ifndef GUI
  89. mprintf(St(MNotRAR),ArcName);
  90. #endif
  91. if (CmpExt(ArcName,"rar"))
  92. ErrHandler.SetErrorCode(WARNING);
  93. return(EXTRACT_ARC_NEXT);
  94. }
  95. // Archive with corrupt encrypted header can be closed in IsArchive() call.
  96. // if (!Arc.IsOpened())
  97. // return(EXTRACT_ARC_NEXT);
  98. #ifndef SFX_MODULE
  99. if (Arc.Volume && Arc.NotFirstVolume)
  100. {
  101. char FirstVolName[NM];
  102. VolNameToFirstName(ArcName,FirstVolName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0);
  103. // If several volume names from same volume set are specified
  104. // and current volume is not first in set and first volume is present
  105. // and specified too, let's skip the current volume.
  106. if (stricomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) &&
  107. Cmd->ArcNames->Search(FirstVolName,NULL,false))
  108. return(EXTRACT_ARC_NEXT);
  109. }
  110. #endif
  111. int64 VolumeSetSize=0; // Total size of volumes after the current volume.
  112. if (Arc.Volume)
  113. {
  114. // Calculate the total size of all accessible volumes.
  115. // This size is necessary to display the correct total progress indicator.
  116. char NextName[NM];
  117. wchar NextNameW[NM];
  118. strcpy(NextName,Arc.FileName);
  119. wcscpy(NextNameW,Arc.FileNameW);
  120. while (true)
  121. {
  122. // First volume is already added to DataIO.TotalArcSize
  123. // in initial TotalArcSize calculation in DoExtract.
  124. // So we skip it and start from second volume.
  125. NextVolumeName(NextName,NextNameW,ASIZE(NextName),(Arc.NewMhd.Flags & MHD_NEWNUMBERING)==0 || Arc.OldFormat);
  126. struct FindData FD;
  127. if (FindFile::FastFind(NextName,NextNameW,&FD))
  128. VolumeSetSize+=FD.Size;
  129. else
  130. break;
  131. }
  132. DataIO.TotalArcSize+=VolumeSetSize;
  133. }
  134. ExtractArchiveInit(Cmd,Arc);
  135. if (*Cmd->Command=='T' || *Cmd->Command=='I')
  136. Cmd->Test=true;
  137. #ifndef GUI
  138. if (*Cmd->Command=='I')
  139. Cmd->DisablePercentage=true;
  140. else
  141. if (Cmd->Test)
  142. mprintf(St(MExtrTest),ArcName);
  143. else
  144. mprintf(St(MExtracting),ArcName);
  145. #endif
  146. Arc.ViewComment();
  147. // RAR can close a corrupt encrypted archive
  148. // if (!Arc.IsOpened())
  149. // return(EXTRACT_ARC_NEXT);
  150. while (1)
  151. {
  152. size_t Size=Arc.ReadHeader();
  153. bool Repeat=false;
  154. if (!ExtractCurrentFile(Cmd,Arc,Size,Repeat))
  155. if (Repeat)
  156. {
  157. // If we started extraction from not first volume and need to
  158. // restart it from first, we must correct DataIO.TotalArcSize
  159. // for correct total progress display. We subtract the size
  160. // of current volume and all volumes after it and add the size
  161. // of new (first) volume.
  162. FindData OldArc,NewArc;
  163. if (FindFile::FastFind(Arc.FileName,Arc.FileNameW,&OldArc) &&
  164. FindFile::FastFind(ArcName,ArcNameW,&NewArc))
  165. DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size;
  166. return(EXTRACT_ARC_REPEAT);
  167. }
  168. else
  169. break;
  170. }
  171. return(EXTRACT_ARC_NEXT);
  172. }
  173. bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize,bool &Repeat)
  174. {
  175. char Command=*Cmd->Command;
  176. if (HeaderSize==0)
  177. if (DataIO.UnpVolume)
  178. {
  179. #ifdef NOVOLUME
  180. return(false);
  181. #else
  182. if (!MergeArchive(Arc,&DataIO,false,Command))
  183. {
  184. ErrHandler.SetErrorCode(WARNING);
  185. return(false);
  186. }
  187. SignatureFound=false;
  188. #endif
  189. }
  190. else
  191. return(false);
  192. int HeadType=Arc.GetHeaderType();
  193. if (HeadType!=FILE_HEAD)
  194. {
  195. if (HeadType==AV_HEAD || HeadType==SIGN_HEAD)
  196. SignatureFound=true;
  197. #if !defined(SFX_MODULE) && !defined(_WIN_CE)
  198. if (HeadType==SUB_HEAD && PrevExtracted)
  199. SetExtraInfo(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
  200. #endif
  201. if (HeadType==NEWSUB_HEAD)
  202. {
  203. if (Arc.SubHead.CmpName(SUBHEAD_TYPE_AV))
  204. SignatureFound=true;
  205. #if !defined(NOSUBBLOCKS) && !defined(_WIN_CE)
  206. if (PrevExtracted)
  207. SetExtraInfoNew(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
  208. #endif
  209. }
  210. if (HeadType==ENDARC_HEAD)
  211. if (Arc.EndArcHead.Flags & EARC_NEXT_VOLUME)
  212. {
  213. #ifndef NOVOLUME
  214. if (!MergeArchive(Arc,&DataIO,false,Command))
  215. {
  216. ErrHandler.SetErrorCode(WARNING);
  217. return(false);
  218. }
  219. SignatureFound=false;
  220. #endif
  221. Arc.Seek(Arc.CurBlockPos,SEEK_SET);
  222. return(true);
  223. }
  224. else
  225. return(false);
  226. Arc.SeekToNext();
  227. return(true);
  228. }
  229. PrevExtracted=false;
  230. if (SignatureFound ||
  231. !Cmd->Recurse && MatchedArgs>=Cmd->FileArgs->ItemsCount() &&
  232. AllMatchesExact)
  233. return(false);
  234. char ArcFileName[NM];
  235. IntToExt(Arc.NewLhd.FileName,Arc.NewLhd.FileName);
  236. strcpy(ArcFileName,Arc.NewLhd.FileName);
  237. wchar ArcFileNameW[NM];
  238. *ArcFileNameW=0;
  239. int MatchType=MATCH_WILDSUBPATH;
  240. bool EqualNames=false;
  241. int MatchNumber=Cmd->IsProcessFile(Arc.NewLhd,&EqualNames,MatchType);
  242. bool ExactMatch=MatchNumber!=0;
  243. #if !defined(SFX_MODULE) && !defined(_WIN_CE)
  244. if (Cmd->ExclPath==EXCL_BASEPATH)
  245. {
  246. *Cmd->ArcPath=0;
  247. if (ExactMatch)
  248. {
  249. Cmd->FileArgs->Rewind();
  250. if (Cmd->FileArgs->GetString(Cmd->ArcPath,NULL,sizeof(Cmd->ArcPath),MatchNumber-1))
  251. *PointToName(Cmd->ArcPath)=0;
  252. }
  253. }
  254. #endif
  255. if (ExactMatch && !EqualNames)
  256. AllMatchesExact=false;
  257. #ifdef UNICODE_SUPPORTED
  258. bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled();
  259. #else
  260. bool WideName=false;
  261. #endif
  262. #ifdef _APPLE
  263. if (WideName)
  264. {
  265. // Prepare UTF-8 name for OS X. Since we are sure that destination
  266. // is UTF-8, we can avoid calling the less reliable WideToChar function.
  267. WideToUtf(Arc.NewLhd.FileNameW,ArcFileName,ASIZE(ArcFileName));
  268. WideName=false;
  269. }
  270. #endif
  271. wchar *DestNameW=WideName ? DestFileNameW:NULL;
  272. #ifdef UNICODE_SUPPORTED
  273. if (WideName)
  274. {
  275. // Prepare the name in single byte native encoding (typically UTF-8
  276. // for Unix-based systems). Windows does not really need it,
  277. // but Unix system will use this name instead of Unicode.
  278. ConvertPath(Arc.NewLhd.FileNameW,ArcFileNameW);
  279. char Name[NM];
  280. if (WideToChar(ArcFileNameW,Name) && IsNameUsable(Name))
  281. strcpy(ArcFileName,Name);
  282. }
  283. #endif
  284. ConvertPath(ArcFileName,ArcFileName);
  285. if (Arc.IsArcLabel())
  286. return(true);
  287. if (Arc.NewLhd.Flags & LHD_VERSION)
  288. {
  289. if (Cmd->VersionControl!=1 && !EqualNames)
  290. {
  291. if (Cmd->VersionControl==0)
  292. ExactMatch=false;
  293. int Version=ParseVersionFileName(ArcFileName,ArcFileNameW,false);
  294. if (Cmd->VersionControl-1==Version)
  295. ParseVersionFileName(ArcFileName,ArcFileNameW,true);
  296. else
  297. ExactMatch=false;
  298. }
  299. }
  300. else
  301. if (!Arc.IsArcDir() && Cmd->VersionControl>1)
  302. ExactMatch=false;
  303. Arc.ConvertAttributes();
  304. #ifndef SFX_MODULE
  305. if ((Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)!=0 && FirstFile)
  306. {
  307. char CurVolName[NM];
  308. strcpy(CurVolName,ArcName);
  309. bool NewNumbering=(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0;
  310. VolNameToFirstName(ArcName,ArcName,NewNumbering);
  311. if (*ArcNameW!=0)
  312. VolNameToFirstName(ArcNameW,ArcNameW,NewNumbering);
  313. if (stricomp(ArcName,CurVolName)!=0 && FileExist(ArcName,ArcNameW))
  314. {
  315. // If first volume name does not match the current name and if
  316. // such volume name really exists, let's unpack from this first volume.
  317. Repeat=true;
  318. return(false);
  319. }
  320. #if !defined(RARDLL) && !defined(_WIN_CE)
  321. if (!ReconstructDone)
  322. {
  323. ReconstructDone=true;
  324. RecVolumes RecVol;
  325. if (RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true))
  326. {
  327. Repeat=true;
  328. return(false);
  329. }
  330. }
  331. #endif
  332. strcpy(ArcName,CurVolName);
  333. }
  334. #endif
  335. DataIO.UnpVolume=(Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0;
  336. DataIO.NextVolumeMissing=false;
  337. Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET);
  338. bool TestMode=false;
  339. bool ExtrFile=false;
  340. bool SkipSolid=false;
  341. #ifndef SFX_MODULE
  342. if (FirstFile && (ExactMatch || Arc.Solid) && (Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/))!=0)
  343. {
  344. if (ExactMatch)
  345. {
  346. Log(Arc.FileName,St(MUnpCannotMerge),ArcFileName);
  347. #ifdef RARDLL
  348. Cmd->DllError=ERAR_BAD_DATA;
  349. #endif
  350. ErrHandler.SetErrorCode(OPEN_ERROR);
  351. }
  352. ExactMatch=false;
  353. }
  354. FirstFile=false;
  355. #endif
  356. if (ExactMatch || (SkipSolid=Arc.Solid)!=0)
  357. {
  358. if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0)
  359. #ifndef RARDLL
  360. if (*Password==0)
  361. #endif
  362. {
  363. #ifdef RARDLL
  364. if (*Cmd->Password==0)
  365. {
  366. char PasswordA[MAXPASSWORD];
  367. if (Cmd->Callback==NULL ||
  368. Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
  369. return(false);
  370. GetWideName(PasswordA,NULL,Cmd->Password,ASIZE(Cmd->Password));
  371. }
  372. wcscpy(Password,Cmd->Password);
  373. #else
  374. if (!GetPassword(PASSWORD_FILE,ArcFileName,ArcFileNameW,Password,ASIZE(Password)))
  375. {
  376. PasswordCancelled=true;
  377. return(false);
  378. }
  379. #endif
  380. }
  381. #if !defined(GUI) && !defined(SILENT)
  382. else
  383. if (!PasswordAll && (!Arc.Solid || Arc.NewLhd.UnpVer>=20 && (Arc.NewLhd.Flags & LHD_SOLID)==0))
  384. {
  385. eprintf(St(MUseCurPsw),ArcFileName);
  386. switch(Cmd->AllYes ? 1:Ask(St(MYesNoAll)))
  387. {
  388. case -1:
  389. ErrHandler.Exit(USER_BREAK);
  390. case 2:
  391. if (!GetPassword(PASSWORD_FILE,ArcFileName,ArcFileNameW,Password,ASIZE(Password)))
  392. {
  393. return(false);
  394. }
  395. break;
  396. case 3:
  397. PasswordAll=true;
  398. break;
  399. }
  400. }
  401. #endif
  402. #ifndef SFX_MODULE
  403. if (*Cmd->ExtrPath==0 && *Cmd->ExtrPathW!=0)
  404. WideToChar(Cmd->ExtrPathW,DestFileName);
  405. else
  406. #endif
  407. strcpy(DestFileName,Cmd->ExtrPath);
  408. #ifndef SFX_MODULE
  409. if (Cmd->AppendArcNameToPath)
  410. {
  411. strcat(DestFileName,PointToName(Arc.FirstVolumeName));
  412. SetExt(DestFileName,NULL);
  413. AddEndSlash(DestFileName);
  414. }
  415. #endif
  416. char *ExtrName=ArcFileName;
  417. bool EmptyName=false;
  418. #ifndef SFX_MODULE
  419. size_t Length=strlen(Cmd->ArcPath);
  420. if (Length>1 && IsPathDiv(Cmd->ArcPath[Length-1]) &&
  421. strlen(ArcFileName)==Length-1)
  422. Length--;
  423. if (Length>0 && strnicomp(Cmd->ArcPath,ArcFileName,Length)==0)
  424. {
  425. ExtrName+=Length;
  426. while (*ExtrName==CPATHDIVIDER)
  427. ExtrName++;
  428. if (*ExtrName==0)
  429. EmptyName=true;
  430. }
  431. #endif
  432. // Use -ep3 only in systems, where disk letters are exist, not in Unix.
  433. bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':');
  434. // We do not use any user specified destination paths when extracting
  435. // absolute paths in -ep3 mode.
  436. if (AbsPaths)
  437. *DestFileName=0;
  438. if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
  439. strcat(DestFileName,PointToName(ExtrName));
  440. else
  441. strcat(DestFileName,ExtrName);
  442. char DiskLetter=etoupper(DestFileName[0]);
  443. if (AbsPaths)
  444. {
  445. if (DestFileName[1]=='_' && IsPathDiv(DestFileName[2]) &&
  446. DiskLetter>='A' && DiskLetter<='Z')
  447. DestFileName[1]=':';
  448. else
  449. if (DestFileName[0]=='_' && DestFileName[1]=='_')
  450. {
  451. // Convert __server\share to \\server\share.
  452. DestFileName[0]=CPATHDIVIDER;
  453. DestFileName[1]=CPATHDIVIDER;
  454. }
  455. }
  456. #ifndef SFX_MODULE
  457. if (!WideName && *Cmd->ExtrPathW!=0)
  458. {
  459. DestNameW=DestFileNameW;
  460. WideName=true;
  461. CharToWide(ArcFileName,ArcFileNameW);
  462. }
  463. #endif
  464. if (WideName)
  465. {
  466. if (*Cmd->ExtrPathW!=0)
  467. wcscpy(DestFileNameW,Cmd->ExtrPathW);
  468. else
  469. CharToWide(Cmd->ExtrPath,DestFileNameW);
  470. #ifndef SFX_MODULE
  471. if (Cmd->AppendArcNameToPath)
  472. {
  473. wchar FileNameW[NM];
  474. if (*Arc.FirstVolumeNameW!=0)
  475. wcscpy(FileNameW,Arc.FirstVolumeNameW);
  476. else
  477. CharToWide(Arc.FirstVolumeName,FileNameW);
  478. wcscat(DestFileNameW,PointToName(FileNameW));
  479. SetExt(DestFileNameW,NULL);
  480. AddEndSlash(DestFileNameW);
  481. }
  482. #endif
  483. wchar *ExtrNameW=ArcFileNameW;
  484. #ifndef SFX_MODULE
  485. if (Length>0)
  486. {
  487. wchar ArcPathW[NM];
  488. GetWideName(Cmd->ArcPath,Cmd->ArcPathW,ArcPathW,ASIZE(ArcPathW));
  489. Length=wcslen(ArcPathW);
  490. }
  491. ExtrNameW+=Length;
  492. while (*ExtrNameW==CPATHDIVIDER)
  493. ExtrNameW++;
  494. #endif
  495. if (AbsPaths)
  496. *DestFileNameW=0;
  497. if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
  498. wcscat(DestFileNameW,PointToName(ExtrNameW));
  499. else
  500. wcscat(DestFileNameW,ExtrNameW);
  501. if (AbsPaths && DestFileNameW[1]=='_' && IsPathDiv(DestFileNameW[2]))
  502. DestFileNameW[1]=':';
  503. }
  504. else
  505. *DestFileNameW=0;
  506. ExtrFile=!SkipSolid && !EmptyName && (Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0;
  507. if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X'))
  508. {
  509. struct FindData FD;
  510. if (FindFile::FastFind(DestFileName,DestNameW,&FD))
  511. {
  512. if (FD.mtime >= Arc.NewLhd.mtime)
  513. {
  514. // If directory already exists and its modification time is newer
  515. // than start of extraction, it is likely it was created
  516. // when creating a path to one of already extracted items.
  517. // In such case we'll better update its time even if archived
  518. // directory is older.
  519. if (!FD.IsDir || FD.mtime<StartTime)
  520. ExtrFile=false;
  521. }
  522. }
  523. else
  524. if (Cmd->FreshFiles)
  525. ExtrFile=false;
  526. }
  527. // Skip encrypted file if no password is specified.
  528. if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0 && *Password==0)
  529. {
  530. ErrHandler.SetErrorCode(WARNING);
  531. #ifdef RARDLL
  532. Cmd->DllError=ERAR_MISSING_PASSWORD;
  533. #endif
  534. ExtrFile=false;
  535. }
  536. #ifdef RARDLL
  537. if (*Cmd->DllDestName)
  538. {
  539. strncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
  540. *DestFileNameW=0;
  541. if (Cmd->DllOpMode!=RAR_EXTRACT)
  542. ExtrFile=false;
  543. }
  544. if (*Cmd->DllDestNameW)
  545. {
  546. wcsncpyz(DestFileNameW,Cmd->DllDestNameW,ASIZE(DestFileNameW));
  547. DestNameW=DestFileNameW;
  548. if (Cmd->DllOpMode!=RAR_EXTRACT)
  549. ExtrFile=false;
  550. }
  551. #endif
  552. #ifdef SFX_MODULE
  553. if ((Arc.NewLhd.UnpVer!=UNP_VER && Arc.NewLhd.UnpVer!=29) &&
  554. Arc.NewLhd.Method!=0x30)
  555. #else
  556. if (Arc.NewLhd.UnpVer<13 || Arc.NewLhd.UnpVer>UNP_VER)
  557. #endif
  558. {
  559. #ifndef SILENT
  560. Log(Arc.FileName,St(MUnknownMeth),ArcFileName);
  561. #ifndef SFX_MODULE
  562. Log(Arc.FileName,St(MVerRequired),Arc.NewLhd.UnpVer/10,Arc.NewLhd.UnpVer%10);
  563. #endif
  564. #endif
  565. ExtrFile=false;
  566. ErrHandler.SetErrorCode(WARNING);
  567. #ifdef RARDLL
  568. Cmd->DllError=ERAR_UNKNOWN_FORMAT;
  569. #endif
  570. }
  571. File CurFile;
  572. if (!IsLink(Arc.NewLhd.FileAttr))
  573. if (Arc.IsArcDir())
  574. {
  575. if (!ExtrFile || Command=='P' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
  576. return(true);
  577. if (SkipSolid)
  578. {
  579. #ifndef GUI
  580. mprintf(St(MExtrSkipFile),ArcFileName);
  581. #endif
  582. return(true);
  583. }
  584. TotalFileCount++;
  585. if (Cmd->Test)
  586. {
  587. #ifndef GUI
  588. mprintf(St(MExtrTestFile),ArcFileName);
  589. mprintf(" %s",St(MOk));
  590. #endif
  591. return(true);
  592. }
  593. MKDIR_CODE MDCode=MakeDir(DestFileName,DestNameW,!Cmd->IgnoreGeneralAttr,Arc.NewLhd.FileAttr);
  594. bool DirExist=false;
  595. if (MDCode!=MKDIR_SUCCESS)
  596. {
  597. DirExist=FileExist(DestFileName,DestNameW);
  598. if (DirExist && !IsDir(GetFileAttr(DestFileName,DestNameW)))
  599. {
  600. bool UserReject;
  601. FileCreate(Cmd,NULL,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime);
  602. DirExist=false;
  603. }
  604. CreatePath(DestFileName,DestNameW,true);
  605. MDCode=MakeDir(DestFileName,DestNameW,!Cmd->IgnoreGeneralAttr,Arc.NewLhd.FileAttr);
  606. }
  607. if (MDCode==MKDIR_SUCCESS)
  608. {
  609. #ifndef GUI
  610. mprintf(St(MCreatDir),DestFileName);
  611. mprintf(" %s",St(MOk));
  612. #endif
  613. PrevExtracted=true;
  614. }
  615. else
  616. if (DirExist)
  617. {
  618. if (!Cmd->IgnoreGeneralAttr)
  619. SetFileAttr(DestFileName,DestNameW,Arc.NewLhd.FileAttr);
  620. PrevExtracted=true;
  621. }
  622. else
  623. {
  624. Log(Arc.FileName,St(MExtrErrMkDir),DestFileName);
  625. ErrHandler.CheckLongPathErrMsg(DestFileName,DestNameW);
  626. ErrHandler.SysErrMsg();
  627. #ifdef RARDLL
  628. Cmd->DllError=ERAR_ECREATE;
  629. #endif
  630. ErrHandler.SetErrorCode(CREATE_ERROR);
  631. }
  632. if (PrevExtracted)
  633. {
  634. #if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
  635. if (Cmd->SetCompressedAttr &&
  636. (Arc.NewLhd.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
  637. SetFileCompression(DestFileName,DestNameW,true);
  638. #endif
  639. SetDirTime(DestFileName,DestNameW,
  640. Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
  641. Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
  642. Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
  643. }
  644. return(true);
  645. }
  646. else
  647. {
  648. if (Cmd->Test && ExtrFile)
  649. TestMode=true;
  650. #if !defined(GUI) && !defined(SFX_MODULE)
  651. if (Command=='P' && ExtrFile)
  652. CurFile.SetHandleType(FILE_HANDLESTD);
  653. #endif
  654. if ((Command=='E' || Command=='X') && ExtrFile && !Cmd->Test)
  655. {
  656. bool UserReject;
  657. if (!FileCreate(Cmd,&CurFile,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime))
  658. {
  659. ExtrFile=false;
  660. if (!UserReject)
  661. {
  662. ErrHandler.CreateErrorMsg(Arc.FileName,Arc.FileNameW,DestFileName,DestFileNameW);
  663. ErrHandler.SetErrorCode(CREATE_ERROR);
  664. #ifdef RARDLL
  665. Cmd->DllError=ERAR_ECREATE;
  666. #endif
  667. if (!IsNameUsable(DestFileName))
  668. {
  669. Log(Arc.FileName,St(MCorrectingName));
  670. char OrigName[sizeof(DestFileName)];
  671. strncpyz(OrigName,DestFileName,ASIZE(OrigName));
  672. MakeNameUsable(DestFileName,true);
  673. CreatePath(DestFileName,NULL,true);
  674. if (FileCreate(Cmd,&CurFile,DestFileName,NULL,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime))
  675. {
  676. #ifndef SFX_MODULE
  677. Log(Arc.FileName,St(MRenaming),OrigName,DestFileName);
  678. #endif
  679. ExtrFile=true;
  680. }
  681. else
  682. ErrHandler.CreateErrorMsg(Arc.FileName,Arc.FileNameW,DestFileName,DestFileNameW);
  683. }
  684. }
  685. }
  686. }
  687. }
  688. if (!ExtrFile && Arc.Solid)
  689. {
  690. SkipSolid=true;
  691. TestMode=true;
  692. ExtrFile=true;
  693. }
  694. if (ExtrFile)
  695. {
  696. if (!SkipSolid)
  697. {
  698. if (!TestMode && Command!='P' && CurFile.IsDevice())
  699. {
  700. Log(Arc.FileName,St(MInvalidName),DestFileName);
  701. ErrHandler.WriteError(Arc.FileName,Arc.FileNameW,DestFileName,DestFileNameW);
  702. }
  703. TotalFileCount++;
  704. }
  705. FileCount++;
  706. #ifndef GUI
  707. if (Command!='I')
  708. if (SkipSolid)
  709. mprintf(St(MExtrSkipFile),ArcFileName);
  710. else
  711. switch(Cmd->Test ? 'T':Command)
  712. {
  713. case 'T':
  714. mprintf(St(MExtrTestFile),ArcFileName);
  715. break;
  716. #ifndef SFX_MODULE
  717. case 'P':
  718. mprintf(St(MExtrPrinting),ArcFileName);
  719. break;
  720. #endif
  721. case 'X':
  722. case 'E':
  723. mprintf(St(MExtrFile),DestFileName);
  724. break;
  725. }
  726. if (!Cmd->DisablePercentage)
  727. mprintf(" ");
  728. #endif
  729. DataIO.CurUnpRead=0;
  730. DataIO.CurUnpWrite=0;
  731. DataIO.UnpFileCRC=Arc.OldFormat ? 0 : 0xffffffff;
  732. DataIO.PackedCRC=0xffffffff;
  733. wchar FilePassword[MAXPASSWORD];
  734. #ifdef _WIN_ALL
  735. if (Arc.NewLhd.HostOS==HOST_MSDOS/* && Arc.NewLhd.UnpVer<=25*/)
  736. {
  737. // We need the password in OEM encoding if file was encrypted by
  738. // native RAR/DOS (not extender based). Let's make the conversion.
  739. char PswA[MAXPASSWORD];
  740. CharToOemBuffW(Password,PswA,ASIZE(PswA));
  741. CharToWide(PswA,FilePassword,ASIZE(FilePassword));
  742. FilePassword[ASIZE(FilePassword)-1]=0;
  743. }
  744. else
  745. #endif
  746. wcscpy(FilePassword,Password);
  747. DataIO.SetEncryption(
  748. (Arc.NewLhd.Flags & LHD_PASSWORD)!=0 ? Arc.NewLhd.UnpVer:0,FilePassword,
  749. (Arc.NewLhd.Flags & LHD_SALT)!=0 ? Arc.NewLhd.Salt:NULL,false,
  750. Arc.NewLhd.UnpVer>=36);
  751. DataIO.SetPackedSizeToRead(Arc.NewLhd.FullPackSize);
  752. DataIO.SetFiles(&Arc,&CurFile);
  753. DataIO.SetTestMode(TestMode);
  754. DataIO.SetSkipUnpCRC(SkipSolid);
  755. #ifndef _WIN_CE
  756. if (!TestMode && !Arc.BrokenFileHeader &&
  757. (Arc.NewLhd.FullPackSize<<11)>Arc.NewLhd.FullUnpSize &&
  758. (Arc.NewLhd.FullUnpSize<100000000 || Arc.FileLength()>Arc.NewLhd.FullPackSize))
  759. CurFile.Prealloc(Arc.NewLhd.FullUnpSize);
  760. #endif
  761. CurFile.SetAllowDelete(!Cmd->KeepBroken);
  762. bool LinkCreateMode=!Cmd->Test && !SkipSolid;
  763. if (ExtractLink(DataIO,Arc,DestFileName,DataIO.UnpFileCRC,LinkCreateMode))
  764. PrevExtracted=LinkCreateMode;
  765. else
  766. if ((Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0)
  767. if (Arc.NewLhd.Method==0x30)
  768. UnstoreFile(DataIO,Arc.NewLhd.FullUnpSize);
  769. else
  770. {
  771. Unp->SetDestSize(Arc.NewLhd.FullUnpSize);
  772. #ifndef SFX_MODULE
  773. if (Arc.NewLhd.UnpVer<=15)
  774. Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
  775. else
  776. #endif
  777. Unp->DoUnpack(Arc.NewLhd.UnpVer,(Arc.NewLhd.Flags & LHD_SOLID)!=0);
  778. }
  779. // if (Arc.IsOpened())
  780. Arc.SeekToNext();
  781. bool ValidCRC=Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC) ||
  782. !Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC^0xffffffff);
  783. // We set AnySolidDataUnpackedWell to true if we found at least one
  784. // valid non-zero solid file in preceding solid stream. If it is true
  785. // and if current encrypted file is broken, we do not need to hint
  786. // about a wrong password and can report CRC error only.
  787. if ((Arc.NewLhd.Flags & LHD_SOLID)==0)
  788. AnySolidDataUnpackedWell=false; // Reset the flag, because non-solid file is found.
  789. else
  790. if (Arc.NewLhd.Method!=0x30 && Arc.NewLhd.FullUnpSize>0 && ValidCRC)
  791. AnySolidDataUnpackedWell=true;
  792. bool BrokenFile=false;
  793. if (!SkipSolid)
  794. {
  795. if (ValidCRC)
  796. {
  797. #ifndef GUI
  798. if (Command!='P' && Command!='I')
  799. mprintf("%s%s ",Cmd->DisablePercentage ? " ":"\b\b\b\b\b ",St(MOk));
  800. #endif
  801. }
  802. else
  803. {
  804. if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0 && !AnySolidDataUnpackedWell)
  805. {
  806. Log(Arc.FileName,St(MEncrBadCRC),ArcFileName);
  807. }
  808. else
  809. {
  810. Log(Arc.FileName,St(MCRCFailed),ArcFileName);
  811. }
  812. BrokenFile=true;
  813. ErrHandler.SetErrorCode(CRC_ERROR);
  814. #ifdef RARDLL
  815. Cmd->DllError=ERAR_BAD_DATA;
  816. #endif
  817. Alarm();
  818. }
  819. }
  820. #ifndef GUI
  821. else
  822. mprintf("\b\b\b\b\b ");
  823. #endif
  824. if (!TestMode && (Command=='X' || Command=='E') &&
  825. !IsLink(Arc.NewLhd.FileAttr))
  826. {
  827. #if defined(_WIN_ALL) || defined(_EMX)
  828. if (Cmd->ClearArc)
  829. Arc.NewLhd.FileAttr&=~FA_ARCH;
  830. #endif
  831. if (!BrokenFile || Cmd->KeepBroken)
  832. {
  833. if (BrokenFile)
  834. CurFile.Truncate();
  835. CurFile.SetOpenFileTime(
  836. Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
  837. Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
  838. Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
  839. CurFile.Close();
  840. #if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
  841. if (Cmd->SetCompressedAttr &&
  842. (Arc.NewLhd.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
  843. SetFileCompression(CurFile.FileName,CurFile.FileNameW,true);
  844. #endif
  845. CurFile.SetCloseFileTime(
  846. Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
  847. Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
  848. if (!Cmd->IgnoreGeneralAttr)
  849. SetFileAttr(CurFile.FileName,CurFile.FileNameW,Arc.NewLhd.FileAttr);
  850. PrevExtracted=true;
  851. }
  852. }
  853. }
  854. }
  855. if (ExactMatch)
  856. MatchedArgs++;
  857. if (DataIO.NextVolumeMissing/* || !Arc.IsOpened()*/)
  858. return(false);
  859. if (!ExtrFile)
  860. if (!Arc.Solid)
  861. Arc.SeekToNext();
  862. else
  863. if (!SkipSolid)
  864. return(false);
  865. return(true);
  866. }
  867. void CmdExtract::UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize)
  868. {
  869. Array<byte> Buffer(0x10000);
  870. while (1)
  871. {
  872. uint Code=DataIO.UnpRead(&Buffer[0],Buffer.Size());
  873. if (Code==0 || (int)Code==-1)
  874. break;
  875. Code=Code<DestUnpSize ? Code:(uint)DestUnpSize;
  876. DataIO.UnpWrite(&Buffer[0],Code);
  877. if (DestUnpSize>=0)
  878. DestUnpSize-=Code;
  879. }
  880. }