4 #include "XSyncUtils.h"
5 #include "XEventUtils.h"
8 // a cautious wrapper around strncpy
9 char *strncpy_null_terminated(char *dest, const char *src, size_t n)
11 char *result = strncpy(dest, src, n);
18 CmdExtract::CmdExtract()
26 CmdExtract::~CmdExtract()
29 memset(Password,0,sizeof(Password));
33 void CmdExtract::DoExtract(CommandData *Cmd)
37 Unp=new Unpack(&DataIO);
40 DataIO.SetCurrentCommand(*Cmd->Command);
43 while (Cmd->GetArcName(ArcName,ArcNameW,sizeof(ArcName)))
44 if (FindFile::FastFind(ArcName,ArcNameW,&FD))
45 DataIO.TotalArcSize+=FD.Size;
46 Cmd->ArcNames->Rewind();
47 while (Cmd->GetArcName(ArcName,ArcNameW,sizeof(ArcName)))
49 while (ExtractArchive(Cmd)==EXTRACT_ARC_REPEAT)
51 if (FindFile::FastFind(ArcName,ArcNameW,&FD))
52 DataIO.ProcessedArcSize+=FD.Size;
55 if (TotalFileCount==0 && *Cmd->Command!='I')
57 if (!PasswordCancelled)
59 mprintf(St(MExtrNoFiles));
61 ErrHandler.SetErrorCode(WARNING);
64 else if (!Cmd->DisableDone)
66 if (*Cmd->Command=='I')
72 if (ErrHandler.GetErrorCount()==0)
74 mprintf(St(MExtrAllOk));
78 mprintf(St(MExtrTotalErr),ErrHandler.GetErrorCount());
86 void CmdExtract::ExtractArchiveInit(CommandData *Cmd,Archive &Arc)
90 Unp=new Unpack(&DataIO);
94 DataIO.UnpArcSize=Arc.FileLength();
102 if (*Cmd->Password!=0)
103 strncpy_null_terminated(Password,Cmd->Password, MAXPASSWORD);
104 PasswordAll=(*Cmd->Password!=0);
106 DataIO.UnpVolume=false;
109 SignatureFound=false;
110 AllMatchesExact=true;
111 ReconstructDone=false;
115 EXTRACT_ARC_CODE CmdExtract::ExtractArchive(CommandData *Cmd)
118 if (!Arc.WOpen(ArcName,ArcNameW))
120 ErrHandler.SetErrorCode(OPEN_ERROR);
121 return(EXTRACT_ARC_NEXT);
124 if (!Arc.IsArchive(true))
127 mprintf(St(MNotRAR),ArcName);
129 if (CmpExt(ArcName,"rar"))
130 ErrHandler.SetErrorCode(WARNING);
131 return(EXTRACT_ARC_NEXT);
135 return(EXTRACT_ARC_NEXT);
138 if (Arc.Volume && Arc.NotFirstVolume)
140 char FirstVolName[NM];
142 VolNameToFirstName(ArcName,FirstVolName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING));
143 if (stricomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) &&
144 Cmd->ArcNames->Search(FirstVolName,NULL,false))
145 return(EXTRACT_ARC_NEXT);
148 ExtractArchiveInit(Cmd,Arc);
150 if (*Cmd->Command=='T' || *Cmd->Command=='I')
154 if (*Cmd->Command=='I')
155 Cmd->DisablePercentage=true;
159 mprintf(St(MExtrTest),ArcName);
163 mprintf(St(MExtracting),ArcName);
171 int Size=Arc.ReadHeader();
173 if (!ExtractCurrentFile(Cmd,Arc,Size,Repeat))
177 return(EXTRACT_ARC_REPEAT);
183 return(EXTRACT_ARC_NEXT);
187 bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize,bool &Repeat)
191 Unp=new Unpack(&DataIO);
194 char Command=*Cmd->Command;
198 if (DataIO.UnpVolume)
203 if (!MergeArchive(Arc,NULL,false,Command))
205 ErrHandler.SetErrorCode(WARNING);
208 SignatureFound=false;
214 int HeadType=Arc.GetHeaderType();
215 if (HeadType!=FILE_HEAD)
217 if (HeadType==AV_HEAD || HeadType==SIGN_HEAD)
219 #if !defined(SFX_MODULE) && !defined(_WIN_CE)
220 if (HeadType==SUB_HEAD && PrevExtracted)
221 SetExtraInfo(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
223 if (HeadType==NEWSUB_HEAD)
225 if (Arc.SubHead.CmpName(SUBHEAD_TYPE_AV))
227 #if !defined(NOSUBBLOCKS) && !defined(_WIN_CE)
229 SetExtraInfoNew(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
232 if (HeadType==ENDARC_HEAD)
234 if (Arc.EndArcHead.Flags & EARC_NEXT_VOLUME)
237 if (!MergeArchive(Arc,NULL,false,Command))
239 ErrHandler.SetErrorCode(WARNING);
242 SignatureFound=false;
244 Arc.Seek(Arc.CurBlockPos,SEEK_SET);
255 if (SignatureFound ||
256 (!Cmd->Recurse && MatchedArgs>=(int)Cmd->FileArgs->ItemsCount() && AllMatchesExact))
259 char ArcFileName[NM];
261 IntToExt(Arc.NewLhd.FileName,Arc.NewLhd.FileName);
262 strncpy_null_terminated(ArcFileName,Arc.NewLhd.FileName, NM);
264 wchar ArcFileNameW[NM];
267 int MatchType=MATCH_WILDSUBPATH;
269 bool EqualNames=false;
270 int MatchNumber=Cmd->IsProcessFile(Arc.NewLhd,&EqualNames,MatchType);
271 bool ExactMatch=MatchNumber!=0;
272 #if !defined(SFX_MODULE) && !defined(_WIN_CE)
273 if (Cmd->ExclPath==EXCL_BASEPATH)
278 Cmd->FileArgs->Rewind();
279 if (Cmd->FileArgs->GetString(Cmd->ArcPath,NULL,sizeof(Cmd->ArcPath),MatchNumber-1))
280 *PointToName(Cmd->ArcPath)=0;
284 if (ExactMatch && !EqualNames)
285 AllMatchesExact=false;
287 #ifdef UNICODE_SUPPORTED
288 bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled();
296 WideToUtf(Arc.NewLhd.FileNameW,ArcFileName,sizeof(ArcFileName));
301 wchar *DestNameW=WideName ? DestFileNameW:NULL;
303 #ifdef UNICODE_SUPPORTED
306 ConvertPath(Arc.NewLhd.FileNameW,ArcFileNameW);
308 WideToChar(ArcFileNameW,Name);
309 if (IsNameUsable(Name))
310 strncpy_null_terminated(ArcFileName,Name, NM);
314 ConvertPath(ArcFileName,ArcFileName);
316 if (Arc.IsArcLabel())
319 if (Arc.NewLhd.Flags & LHD_VERSION)
321 if (Cmd->VersionControl!=1 && !EqualNames)
323 if (Cmd->VersionControl==0)
325 int Version=ParseVersionFileName(ArcFileName,ArcFileNameW,false);
326 if (Cmd->VersionControl-1==Version)
327 ParseVersionFileName(ArcFileName,ArcFileNameW,true);
333 if (!Arc.IsArcDir() && Cmd->VersionControl>1)
336 Arc.ConvertAttributes();
339 if ((Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/)) && FirstFile)
342 strncpy_null_terminated(CurVolName,ArcName, NM);
344 VolNameToFirstName(ArcName,ArcName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING) != 0);
345 if (stricomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
351 #if !defined(RARDLL) && !defined(_WIN_CE)
352 if (!ReconstructDone)
354 ReconstructDone=true;
357 if (RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true))
364 strncpy_null_terminated(ArcName,CurVolName, NM);
368 DataIO.UnpVolume=(Arc.NewLhd.Flags & LHD_SPLIT_AFTER);
369 DataIO.NextVolumeMissing=false;
371 Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET);
375 bool SkipSolid=false;
378 if (FirstFile && (ExactMatch || Arc.Solid) && (Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/))!=0)
382 Log(Arc.FileName,St(MUnpCannotMerge),(char*) ArcFileName);
384 Cmd->DllError=ERAR_BAD_DATA;
386 ErrHandler.SetErrorCode(WARNING);
394 if (ExactMatch || (SkipSolid=Arc.Solid)!=0)
396 if (Arc.NewLhd.Flags & LHD_PASSWORD)
402 if (*Cmd->Password==0)
403 if (Cmd->Callback==NULL ||
404 Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LONG)Cmd->Password,sizeof(Cmd->Password))==-1)
406 strncpy_null_terminated(Password,Cmd->Password, MAXPASSWORD);
409 if (!GetPassword(PASSWORD_FILE,ArcFileName,Password,sizeof(Password)))
411 PasswordCancelled=true;
416 #if !defined(GUI) && !defined(SILENT)
418 if (!PasswordAll && (!Arc.Solid || Arc.NewLhd.UnpVer>=20 && (Arc.NewLhd.Flags & LHD_SOLID)==0))
420 eprintf(St(MUseCurPsw),(char*) ArcFileName);
421 switch(Cmd->AllYes ? 1:Ask(St(MYesNoAll)))
424 ErrHandler.Exit(USER_BREAK);
426 if (!GetPassword(PASSWORD_FILE,ArcFileName,Password,sizeof(Password)))
439 if (*Cmd->ExtrPath==0 && *Cmd->ExtrPathW!=0)
440 WideToChar(Cmd->ExtrPathW,DestFileName);
443 strncpy_null_terminated(DestFileName,Cmd->ExtrPath, NM);
447 if (Cmd->AppendArcNameToPath)
449 AddEndSlash(DestFileName);
450 strcat(DestFileName,PointToName(Arc.FileName));
451 SetExt(DestFileName,NULL);
452 AddEndSlash(DestFileName);
456 char *ExtrName=ArcFileName;
458 bool EmptyName=false;
460 int Length=strlen(Cmd->ArcPath);
461 if (Length>1 && IsPathDiv(Cmd->ArcPath[Length-1]) &&
462 strlen(ArcFileName)==((unsigned int)Length-1))
464 if (Length>0 && strnicomp(Cmd->ArcPath,ArcFileName,Length)==0)
467 while (*ExtrName==CPATHDIVIDER)
474 bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':');
478 if (DestFileName[strlen(DestFileName)-1] != '\\' && DestFileName[strlen(DestFileName)-1] != '/')
479 strcat(DestFileName,"\\");
481 if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
483 strcat(DestFileName,PointToName(ExtrName));
486 strcat(DestFileName,ExtrName);
488 if (AbsPaths && DestFileName[1]=='_' && IsPathDiv(DestFileName[2]))
492 if (!WideName && *Cmd->ExtrPathW!=0)
494 DestNameW=DestFileNameW;
496 CharToWide(ArcFileName,ArcFileNameW);
502 if (*Cmd->ExtrPathW!=0)
503 strcpyw(DestFileNameW,Cmd->ExtrPathW);
505 CharToWide(Cmd->ExtrPath,DestFileNameW);
508 if (Cmd->AppendArcNameToPath)
511 if (*Arc.FileNameW!=0)
512 strcpyw(FileNameW,Arc.FileNameW);
514 CharToWide(Arc.FileName,FileNameW);
515 strcatw(DestFileNameW,PointToName(FileNameW));
516 SetExt(DestFileNameW,NULL);
517 AddEndSlash(DestFileNameW);
520 wchar *ExtrNameW=ArcFileNameW;
525 CharToWide(Cmd->ArcPath,ArcPathW);
526 Length=strlenw(ArcPathW);
529 while (*ExtrNameW==CPATHDIVIDER)
536 if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
537 strcatw(DestFileNameW,PointToName(ExtrNameW));
539 strcatw(DestFileNameW,ExtrNameW);
541 if (AbsPaths && DestFileNameW[1]=='_' && IsPathDiv(DestFileNameW[2]))
542 DestFileNameW[1]=':';
547 ExtrFile=!SkipSolid && !EmptyName && (Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0/* && *ExtrName*/;
548 if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X'))
551 if (FindFile::FastFind(DestFileName,DestNameW,&FD))
553 if (FD.mtime >= Arc.NewLhd.mtime)
562 if (*Cmd->DllDestName)
564 strncpy_null_terminated(DestFileName,Cmd->DllDestName,sizeof(DestFileName));
566 if (Cmd->DllOpMode!=RAR_EXTRACT)
569 if (*Cmd->DllDestNameW)
571 strncpyw(DestFileNameW,Cmd->DllDestNameW,sizeof(DestFileNameW)/sizeof(DestFileNameW[0]));
572 DestNameW=DestFileNameW;
573 if (Cmd->DllOpMode!=RAR_EXTRACT)
579 if (Arc.NewLhd.UnpVer!=UNP_VER && Arc.NewLhd.Method!=0x30)
581 if (Arc.NewLhd.UnpVer<13 || Arc.NewLhd.UnpVer>UNP_VER)
585 Log(Arc.FileName,St(MUnknownMeth),(char*) ArcFileName);
587 Log(Arc.FileName,St(MVerRequired),Arc.NewLhd.UnpVer/10,Arc.NewLhd.UnpVer%10);
591 ErrHandler.SetErrorCode(WARNING);
593 Cmd->DllError=ERAR_UNKNOWN_FORMAT;
599 if (!IsLink(Arc.NewLhd.FileAttr))
603 if (!ExtrFile || Command=='P' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
608 mprintf(St(MExtrSkipFile),(char*) ArcFileName);
616 mprintf(St(MExtrTestFile),(char*) ArcFileName);
617 mprintf(" %s",St(MOk));
621 if (CUtil::CreateDirectoryEx(DestFileName))
624 mprintf(St(MCreatDir),DestFileName);
625 mprintf(" %s",St(MOk));
628 SetFileAttr(DestFileName,DestNameW,Arc.NewLhd.FileAttr);
633 Log(Arc.FileName,St(MExtrErrMkDir),DestFileName);
634 ErrHandler.SysErrMsg();
636 Cmd->DllError=ERAR_ECREATE;
638 ErrHandler.SetErrorCode(CREATE_ERROR);
641 SetDirTime(DestFileName,
642 Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
643 Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
644 Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
649 if (Cmd->Test && ExtrFile)
651 #if !defined(GUI) && !defined(SFX_MODULE)
652 if (Command=='P' && ExtrFile)
653 CurFile.SetHandleType(FILE_HANDLESTD);
655 if ((Command=='E' || Command=='X') && ExtrFile && !Cmd->Test)
659 if (GetDataIO().UnpackToMemorySize == -1)
661 if (!FileCreate(Cmd,&CurFile,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.UnpSize,Arc.NewLhd.FileTime))
666 ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName);
667 ErrHandler.SetErrorCode(CREATE_ERROR);
669 Cmd->DllError=ERAR_ECREATE;
677 if (!ExtrFile && Arc.Solid)
687 if (!TestMode && Command!='P' && CurFile.IsDevice())
689 Log(Arc.FileName,St(MInvalidName),DestFileName);
690 ErrHandler.WriteError(Arc.FileName,DestFileName);
699 mprintf(St(MExtrSkipFile),(char*) ArcFileName);
702 switch(Cmd->Test ? 'T':Command)
705 mprintf(St(MExtrTestFile),(char*) ArcFileName);
709 mprintf(St(MExtrPrinting),(char*) ArcFileName);
714 mprintf(St(MExtrFile),DestFileName);
719 if (!Cmd->DisablePercentage)
725 DataIO.CurUnpWrite=0;
726 DataIO.UnpFileCRC=Arc.OldFormat ? 0 : 0xffffffff;
727 DataIO.PackedCRC=0xffffffff;
728 DataIO.SetEncryption(
729 (Arc.NewLhd.Flags & LHD_PASSWORD) ? Arc.NewLhd.UnpVer:0,Password,
730 (Arc.NewLhd.Flags & LHD_SALT) ? Arc.NewLhd.Salt:NULL,false);
731 DataIO.SetPackedSizeToRead(Arc.NewLhd.FullPackSize);
732 DataIO.SetFiles(&Arc,&CurFile);
733 DataIO.SetTestMode(TestMode);
734 DataIO.SetSkipUnpCRC(SkipSolid);
737 if (!TestMode && !Arc.BrokenFileHeader &&
738 (Arc.NewLhd.FullPackSize<<11)>Arc.NewLhd.FullUnpSize &&
739 (Arc.NewLhd.FullUnpSize<100000000 || Arc.FileLength()>Arc.NewLhd.FullPackSize))
740 CurFile.Prealloc(Arc.NewLhd.FullUnpSize);
742 CurFile.SetAllowDelete(!Cmd->KeepBroken);
744 bool LinkCreateMode=!Cmd->Test && !SkipSolid;
745 if (ExtractLink(DataIO,Arc,DestFileName,DataIO.UnpFileCRC,LinkCreateMode))
746 PrevExtracted=LinkCreateMode;
747 else if ((Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0)
749 if (Arc.NewLhd.Method==0x30)
750 UnstoreFile(DataIO,Arc.NewLhd.FullUnpSize);
753 Unp->SetDestSize(Arc.NewLhd.FullUnpSize);
755 if (Arc.NewLhd.UnpVer<=15)
756 Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
759 Unp->DoUnpack(Arc.NewLhd.UnpVer,(Arc.NewLhd.Flags & LHD_SOLID));
763 if (DataIO.UnpackToMemorySize > -1)
764 if (DataIO.hQuit->WaitMSec(1))
772 bool BrokenFile=false;
775 if (Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC) ||
776 !Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC^0xffffffff))
779 if (Command!='P' && Command!='I')
780 mprintf("%s%s ",Cmd->DisablePercentage ? " ":"\b\b\b\b\b ",St(MOk));
785 char *BadArcName=(Arc.NewLhd.Flags & LHD_SPLIT_BEFORE) ? NULL:Arc.FileName;
786 if (Arc.NewLhd.Flags & LHD_PASSWORD)
788 Log(BadArcName,St(MEncrBadCRC),ArcFileName);
792 Log(BadArcName,St(MCRCFailed),ArcFileName);
795 ErrHandler.SetErrorCode(CRC_ERROR);
797 Cmd->DllError=ERAR_BAD_DATA;
804 // mprintf("\b\b\b\b\b ");
807 if (!TestMode && (Command=='X' || Command=='E') &&
808 !IsLink(Arc.NewLhd.FileAttr))
810 #if defined(_WIN_32) || defined(_EMX)
812 Arc.NewLhd.FileAttr&=~FA_ARCH;
814 if (!BrokenFile || Cmd->KeepBroken)
818 CurFile.SetOpenFileStat(
819 Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
820 Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
821 Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
823 CurFile.SetCloseFileStat(
824 Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
825 Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime,
826 Arc.NewLhd.FileAttr);
834 if (DataIO.NextVolumeMissing || !Arc.IsOpened())
847 void CmdExtract::UnstoreFile(ComprDataIO &DataIO,Int64 DestUnpSize)
849 Array<byte> Buffer(0x40000);
850 if (DataIO.UnpackToMemorySize > -1)
854 if (DataIO.hQuit->WaitMSec(1))
858 int Code=DataIO.UnpRead(&Buffer[0],Buffer.Size());
859 if (DataIO.UnpackToMemorySize > -1 && !DataIO.NextVolumeMissing)
861 if (DataIO.hSeek->WaitMSec(1))
866 Code=Code<DestUnpSize ? Code:int64to32(DestUnpSize);
867 DataIO.UnpWrite(&Buffer[0],Code);
873 if (DataIO.NextVolumeMissing)
874 DataIO.hSeekDone->Set();
876 if (DataIO.hSeek->WaitMSec(1))
878 DataIO.hBufferFilled->Reset();
879 DataIO.hBufferEmpty->Set();
880 while (! DataIO.hBufferFilled->WaitMSec(1))
881 if (DataIO.hQuit->WaitMSec(1))
890 int Code=DataIO.UnpRead(&Buffer[0],Buffer.Size());
893 Code=Code<DestUnpSize ? Code:int64to32(DestUnpSize);
894 DataIO.UnpWrite(&Buffer[0],Code);
900 DataIO.NextVolumeMissing = true;