123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- #include "rar.hpp"
- #ifdef RARDLL
- static bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize);
- static bool DllVolNotify(RAROptions *Cmd,wchar *NextName);
- #endif
- bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command)
- {
- RAROptions *Cmd=Arc.GetRAROptions();
- 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)
- {
- 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);
- }
- bool PrevVolEncrypted=Arc.Encrypted;
- int64 PosBeforeClose=Arc.Tell();
- if (DataIO!=NULL)
- DataIO->ProcessedArcSize+=DataIO->LastArcSize;
- Arc.Close();
- 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 OldSchemeTested=false;
- 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))
- {
- // 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)
- {
- // 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 (!DllVolChange(Cmd,NextName,ASIZE(NextName)))
- {
- FailedOpen=true;
- break;
- }
- #else // !RARDLL
- #ifndef SFX_MODULE
- if (!RecoveryDone)
- {
- RecVolumesRestore(Cmd,Arc.FileName,true);
- RecoveryDone=true;
- continue;
- }
- #endif
- if (!Cmd->VolumePause && !IsRemovable(NextName))
- {
- FailedOpen=true;
- break;
- }
- #ifndef SILENT
- if (Cmd->AllYes || !uiAskNextVolume(NextName,ASIZE(NextName)))
- #endif
- {
- FailedOpen=true;
- break;
- }
- #endif // RARDLL
- }
-
- if (FailedOpen)
- {
- uiMsg(UIERROR_MISSINGVOL,NextName);
- Arc.Open(Arc.FileName,OpenMode);
- Arc.Seek(PosBeforeClose,SEEK_SET);
- return false;
- }
- if (Command=='T' || Command=='X' || Command=='E')
- mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName);
- Arc.CheckArc(true);
- #ifdef RARDLL
- if (!DllVolNotify(Cmd,NextName))
- return false;
- #endif
- 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);
- }
- if (SplitHeader)
- Arc.SearchBlock(HeaderType);
- else
- Arc.ReadHeader();
- if (Arc.GetHeaderType()==HEAD_FILE)
- {
- Arc.ConvertAttributes();
- Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);
- }
- if (ShowFileName && !Cmd->DisableNames)
- {
- mprintf(St(MExtrPoints),Arc.FileHead.FileName);
- if (!Cmd->DisablePercentage)
- mprintf(L" ");
- }
- if (DataIO!=NULL)
- {
- if (HeaderType==HEAD_ENDARC)
- DataIO->UnpVolume=false;
- else
- {
- DataIO->UnpVolume=hd->SplitAfter;
- DataIO->SetPackedSizeToRead(hd->PackSize);
- }
- 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->PackedDataHash.Init(hd->FileHash.Type,Cmd->Threads);
- }
- return true;
- }
- #ifdef RARDLL
- bool DllVolChange(RAROptions *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(RAROptions *Cmd,wchar *NextName)
- {
- 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
|