diff options
Diffstat (limited to 'unrar/unrar/volume.cpp')
| -rw-r--r-- | unrar/unrar/volume.cpp | 330 |
1 files changed, 191 insertions, 139 deletions
diff --git a/unrar/unrar/volume.cpp b/unrar/unrar/volume.cpp index 4c138db..4924d8d 100644 --- a/unrar/unrar/volume.cpp +++ b/unrar/unrar/volume.cpp @@ -1,203 +1,187 @@ #include "rar.hpp" +#ifdef RARDLL +static bool DllVolChange(CommandData *Cmd,wchar *NextName,size_t NameSize); +static bool DllVolNotify(CommandData *Cmd,wchar *NextName); +#endif -bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Command) +bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command) { - RAROptions *Cmd=Arc.GetRAROptions(); + CommandData *Cmd=Arc.GetCommandData(); - int HeaderType=Arc.GetHeaderType(); - FileHeader *hd=HeaderType==NEWSUB_HEAD ? &Arc.SubHead:&Arc.NewLhd; - bool SplitHeader=(HeaderType==FILE_HEAD || HeaderType==NEWSUB_HEAD) && - (hd->Flags & LHD_SPLIT_AFTER)!=0; + HEADER_TYPE HeaderType=Arc.GetHeaderType(); + FileHeader *hd=HeaderType==HEAD_SERVICE ? &Arc.SubHead:&Arc.FileHead; + bool SplitHeader=(HeaderType==HEAD_FILE || HeaderType==HEAD_SERVICE) && + hd->SplitAfter; - if (DataIO!=NULL && SplitHeader && hd->UnpVer>=20 && - hd->FileCRC!=0xffffffff && DataIO->PackedCRC!=~hd->FileCRC) + if (DataIO!=NULL && SplitHeader) { - Log(Arc.FileName,St(MDataBadCRC),hd->FileName,Arc.FileName); + bool PackedHashPresent=Arc.Format==RARFMT50 || + hd->UnpVer>=20 && hd->FileHash.CRC32!=0xffffffff; + if (PackedHashPresent && + !DataIO->PackedDataHash.Cmp(&hd->FileHash,hd->UseHashKey ? hd->HashKey:NULL)) + uiMsg(UIERROR_CHECKSUMPACKED, Arc.FileName, hd->FileName); } - Int64 PosBeforeClose=Arc.Tell(); + bool PrevVolEncrypted=Arc.Encrypted; + + int64 PosBeforeClose=Arc.Tell(); if (DataIO!=NULL) - DataIO->ProcessedArcSize+=Arc.FileLength(); + DataIO->ProcessedArcSize+=DataIO->LastArcSize; + Arc.Close(); - char NextName[NM]; - wchar NextNameW[NM]; - strcpy(NextName,Arc.FileName); - strcpyw(NextNameW,Arc.FileNameW); - NextVolumeName(NextName,NextNameW,ASIZE(NextName),(Arc.NewMhd.Flags & MHD_NEWNUMBERING)==0 || Arc.OldFormat); + wchar NextName[NM]; + wcsncpyz(NextName,Arc.FileName,ASIZE(NextName)); + NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); #if !defined(SFX_MODULE) && !defined(RARDLL) bool RecoveryDone=false; #endif - bool FailedOpen=false,OldSchemeTested=false; + bool OldSchemeTested=false; - while (!Arc.Open(NextName,NextNameW)) - { - // We need to open a new volume which size was not calculated - // in total size before, so we cannot calculate the total progress - // anymore. Let's reset the total size to zero and stop - // the total progress. - if (DataIO!=NULL) - DataIO->TotalArcSize=0; - - if (!OldSchemeTested) + bool FailedOpen=false; // No more next volume open attempts if true. +#if !defined(SILENT) + // In -vp mode we force the pause before next volume even if it is present + // and even if we are on the hard disk. It is important when user does not + // want to process partially downloaded volumes preliminary. + // 2022.01.11: In WinRAR 6.10 beta versions we tried to ignore VolumePause + // if we could open the next volume with FMF_OPENEXCLUSIVE. But another + // developer asked us to return the previous behavior and always prompt + // for confirmation. They want to control when unrar continues, because + // the next file might not be fully decoded yet. They write chunks of data + // and then close the file again until the next chunk comes in. + + if (Cmd->VolumePause && !uiAskNextVolume(NextName,ASIZE(NextName))) + FailedOpen=true; +#endif + + uint OpenMode = Cmd->OpenShared ? FMF_OPENSHARED : 0; + + if (!FailedOpen) + while (!Arc.Open(NextName,OpenMode)) { - // Checking for new style volumes renamed by user to old style - // name format. Some users did it for unknown reason. - char AltNextName[NM]; - wchar AltNextNameW[NM]; - strcpy(AltNextName,Arc.FileName); - strcpyw(AltNextNameW,Arc.FileNameW); - NextVolumeName(AltNextName,AltNextNameW,ASIZE(AltNextName),true); - OldSchemeTested=true; - if (Arc.Open(AltNextName,AltNextNameW)) + // We need to open a new volume which size was not calculated + // in total size before, so we cannot calculate the total progress + // anymore. Let's reset the total size to zero and stop + // the total progress. + if (DataIO!=NULL) + DataIO->TotalArcSize=0; + + if (!OldSchemeTested) { - strcpy(NextName,AltNextName); - strcpyw(NextNameW,AltNextNameW); - break; + // Checking for new style volumes renamed by user to old style + // name format. Some users did it for unknown reason. + wchar AltNextName[NM]; + wcsncpyz(AltNextName,Arc.FileName,ASIZE(AltNextName)); + NextVolumeName(AltNextName,ASIZE(AltNextName),true); + OldSchemeTested=true; + if (Arc.Open(AltNextName,OpenMode)) + { + wcsncpyz(NextName,AltNextName,ASIZE(NextName)); + break; + } } - } #ifdef RARDLL - if (Cmd->Callback==NULL && Cmd->ChangeVolProc==NULL || - Cmd->Callback!=NULL && Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1) - { - Cmd->DllError=ERAR_EOPEN; - FailedOpen=true; - break; - } - if (Cmd->ChangeVolProc!=NULL) - { -#if defined(_WIN_32) && !defined(_MSC_VER) && !defined(__MINGW32__) - _EBX=_ESP; -#endif - int RetCode=Cmd->ChangeVolProc(NextName,RAR_VOL_ASK); -#if defined(_WIN_32) && !defined(_MSC_VER) && !defined(__MINGW32__) - _ESP=_EBX; -#endif - if (RetCode==0) + if (!DllVolChange(Cmd,NextName,ASIZE(NextName))) { - Cmd->DllError=ERAR_EOPEN; FailedOpen=true; break; } - } -#else // RARDLL +#else // !RARDLL -#if !defined(SFX_MODULE) && !defined(_WIN_CE) - if (!RecoveryDone) - { - RecVolumes RecVol; - RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true); - RecoveryDone=true; - continue; - } +#ifndef SFX_MODULE + if (!RecoveryDone) + { + RecVolumesRestore(Cmd,Arc.FileName,true); + RecoveryDone=true; + continue; + } #endif -#ifndef GUI - if (!Cmd->VolumePause && !IsRemovable(NextName)) - { - FailedOpen=true; - break; - } -#endif + if (!Cmd->VolumePause && !IsRemovable(NextName)) + { + FailedOpen=true; + break; + } #ifndef SILENT - if (Cmd->AllYes || !AskNextVol(NextName)) + if (Cmd->AllYes || !uiAskNextVolume(NextName,ASIZE(NextName))) #endif - { - FailedOpen=true; - break; - } + { + FailedOpen=true; + break; + } #endif // RARDLL - *NextNameW=0; - } + } + if (FailedOpen) { -#if !defined(SILENT) && !defined(_WIN_CE) - Log(Arc.FileName,St(MAbsNextVol),NextName); -#endif - Arc.Open(Arc.FileName,Arc.FileNameW); + uiMsg(UIERROR_MISSINGVOL,NextName); + Arc.Open(Arc.FileName,OpenMode); Arc.Seek(PosBeforeClose,SEEK_SET); - return(false); + return false; } + + if (Command=='T' || Command=='X' || Command=='E') + mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName); + + Arc.CheckArc(true); #ifdef RARDLL - if (Cmd->Callback!=NULL && - Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1) - return(false); - if (Cmd->ChangeVolProc!=NULL) - { -#if defined(_WIN_32) && !defined(_MSC_VER) && !defined(__MINGW32__) - _EBX=_ESP; -#endif - int RetCode=Cmd->ChangeVolProc(NextName,RAR_VOL_NOTIFY); -#if defined(_WIN_32) && !defined(_MSC_VER) && !defined(__MINGW32__) - _ESP=_EBX; + if (!DllVolNotify(Cmd,NextName)) + return false; #endif - if (RetCode==0) - return(false); + + if (Arc.Encrypted!=PrevVolEncrypted) + { + // There is no legitimate reason for encrypted header state to be + // changed in the middle of volume sequence. So we abort here to prevent + // replacing an encrypted header volume to unencrypted and adding + // unexpected files by third party to encrypted extraction. + uiMsg(UIERROR_BADARCHIVE,Arc.FileName); + ErrHandler.Exit(RARX_FATAL); } -#endif - if (Command=='T' || Command=='X' || Command=='E') - mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName); if (SplitHeader) Arc.SearchBlock(HeaderType); else Arc.ReadHeader(); - if (Arc.GetHeaderType()==FILE_HEAD) + if (Arc.GetHeaderType()==HEAD_FILE) { Arc.ConvertAttributes(); - Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET); + Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); } -#ifndef GUI - if (ShowFileName) + if (ShowFileName && !Cmd->DisableNames) { - char OutName[NM]; - IntToExt(Arc.NewLhd.FileName,OutName); -#ifdef UNICODE_SUPPORTED - bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled(); - if (WideName) - { - wchar NameW[NM]; - ConvertPath(Arc.NewLhd.FileNameW,NameW); - char Name[NM]; - if (WideToChar(NameW,Name) && IsNameUsable(Name)) - strcpy(OutName,Name); - } -#endif - mprintf(St(MExtrPoints),OutName); + mprintf(St(MExtrPoints),Arc.FileHead.FileName); if (!Cmd->DisablePercentage) - mprintf(" "); + mprintf(L" "); } -#endif if (DataIO!=NULL) { - if (HeaderType==ENDARC_HEAD) + if (HeaderType==HEAD_ENDARC) DataIO->UnpVolume=false; else { - DataIO->UnpVolume=(hd->Flags & LHD_SPLIT_AFTER); - DataIO->SetPackedSizeToRead(hd->FullPackSize); + DataIO->UnpVolume=hd->SplitAfter; + DataIO->SetPackedSizeToRead(hd->PackSize); } -#ifdef SFX_MODULE - DataIO->UnpArcSize=Arc.FileLength(); -#endif - + + DataIO->AdjustTotalArcSize(&Arc); + // Reset the size of packed data read from current volume. It is used // to display the total progress and preceding volumes are already // compensated with ProcessedArcSize, so we need to reset this variable. DataIO->CurUnpRead=0; - DataIO->PackedCRC=0xffffffff; -// DataIO->SetFiles(&Arc,NULL); + DataIO->PackedDataHash.Init(hd->FileHash.Type,Cmd->Threads); } - return(true); + return true; } @@ -205,12 +189,80 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Comman -#ifndef SILENT -bool AskNextVol(char *ArcName) +#ifdef RARDLL +bool DllVolChange(CommandData *Cmd,wchar *NextName,size_t NameSize) +{ + bool DllVolChanged=false,DllVolAborted=false; + + if (Cmd->Callback!=NULL) + { + wchar OrgNextName[NM]; + wcsncpyz(OrgNextName,NextName,ASIZE(OrgNextName)); + if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1) + DllVolAborted=true; + else + if (wcscmp(OrgNextName,NextName)!=0) + DllVolChanged=true; + else + { + char NextNameA[NM],OrgNextNameA[NM]; + WideToChar(NextName,NextNameA,ASIZE(NextNameA)); + strncpyz(OrgNextNameA,NextNameA,ASIZE(OrgNextNameA)); + if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_ASK)==-1) + DllVolAborted=true; + else + if (strcmp(OrgNextNameA,NextNameA)!=0) + { + // We can damage some Unicode characters by U->A->U conversion, + // so set Unicode name only if we see that ANSI name is changed. + CharToWide(NextNameA,NextName,NameSize); + DllVolChanged=true; + } + } + } + if (!DllVolChanged && Cmd->ChangeVolProc!=NULL) + { + char NextNameA[NM]; + WideToChar(NextName,NextNameA,ASIZE(NextNameA)); + int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK); + if (RetCode==0) + DllVolAborted=true; + else + CharToWide(NextNameA,NextName,NameSize); + } + + // We quit only on 'abort' condition, but not on 'name not changed'. + // It is legitimate for program to return the same name when waiting + // for currently non-existent volume. + // Also we quit to prevent an infinite loop if no callback is defined. + if (DllVolAborted || Cmd->Callback==NULL && Cmd->ChangeVolProc==NULL) + { + Cmd->DllError=ERAR_EOPEN; + return false; + } + return true; +} +#endif + + +#ifdef RARDLL +bool DllVolNotify(CommandData *Cmd,wchar *NextName) { - eprintf(St(MAskNextVol),ArcName); - if (Ask(St(MContinueQuit))==2) - return(false); - return(true); + char NextNameA[NM]; + WideToChar(NextName,NextNameA,ASIZE(NextNameA)); + if (Cmd->Callback!=NULL) + { + if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1) + return false; + if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_NOTIFY)==-1) + return false; + } + if (Cmd->ChangeVolProc!=NULL) + { + int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_NOTIFY); + if (RetCode==0) + return false; + } + return true; } #endif |
