//--------------------------------------------------------------------------- #include #pragma hdrstop #include "Common.h" #include "FileOperationProgress.h" #include "CoreMain.h" //--------------------------------------------------------------------------- #define TRANSFER_BUF_SIZE 32768 //--------------------------------------------------------------------------- TFileOperationStatistics::TFileOperationStatistics() { memset(this, 0, sizeof(*this)); } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- TFileOperationProgressType::TPersistence::TPersistence() { FStatistics = NULL; Clear(true, true); } //--------------------------------------------------------------------------- bool TFileOperationProgressType::IsIndeterminateOperation(TFileOperation Operation) { return (Operation == foCalculateSize); } //--------------------------------------------------------------------------- void TFileOperationProgressType::TPersistence::Clear(bool Batch, bool Speed) { if (Batch) { TotalTransferred = 0; StartTime = Now(); SkipToAll = false; BatchOverwrite = boNo; CPSLimit = 0; CounterSet = false; } if (Speed) { Ticks.clear(); TotalTransferredThen.clear(); } } //--------------------------------------------------------------------------- __fastcall TFileOperationProgressType::TFileOperationProgressType() { FOnProgress = NULL; FOnFinished = NULL; FParent = NULL; Init(); Clear(); } //--------------------------------------------------------------------------- __fastcall TFileOperationProgressType::TFileOperationProgressType( TFileOperationProgressEvent AOnProgress, TFileOperationFinished AOnFinished, TFileOperationProgressType * Parent) { FOnProgress = AOnProgress; FOnFinished = AOnFinished; FParent = Parent; FReset = false; Init(); Clear(); } //--------------------------------------------------------------------------- __fastcall TFileOperationProgressType::~TFileOperationProgressType() { DebugAssert(!InProgress || FReset); DebugAssert(!Suspended || FReset); SAFE_DESTROY(FSection); SAFE_DESTROY(FUserSelectionsSection); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Init() { FSection = new TCriticalSection(); FUserSelectionsSection = new TCriticalSection(); FRestored = false; FPersistence.Side = osCurrent; // = undefined value } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Assign(const TFileOperationProgressType & Other) { TValueRestorer SectionRestorer(FSection); TValueRestorer UserSelectionsSectionRestorer(FUserSelectionsSection); TGuard Guard(FSection); TGuard OtherGuard(Other.FSection); *this = Other; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::AssignButKeepSuspendState(const TFileOperationProgressType & Other) { TGuard Guard(FSection); TValueRestorer SuspendTimeRestorer(FSuspendTime); TValueRestorer SuspendedRestorer(FSuspended); Assign(Other); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::DoClear(bool Batch, bool Speed) { FFileName = L""; FFullFileName = L""; FDirectory = L""; FAsciiTransfer = false; FCount = -1; FFilesFinished = 0; FFilesFinishedSuccessfully = 0; FSuspended = false; FSuspendTime = 0; FInProgress = false; FDone = false; FFileInProgress = false; FTotalSkipped = 0; FTotalSize = 0; FSkippedSize = 0; FTotalSizeSet = false; FOperation = foNone; FTemp = false; FPersistence.Clear(Batch, Speed); // to bypass check in ClearTransfer() FTransferSize = 0; ClearTransfer(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Clear() { DoClear(true, true); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::ClearTransfer() { if ((TransferSize > 0) && (TransferredSize < TransferSize)) { TGuard Guard(FSection); __int64 RemainingSize = (TransferSize - TransferredSize); AddSkipped(RemainingSize); } FLocalSize = 0; FTransferSize = 0; FLocallyUsed = 0; FSkippedSize = 0; FTransferredSize = 0; FTransferringFile = false; FLastSecond = 0; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation, TOperationSide ASide, int ACount) { Start(AOperation, ASide, ACount, false, L"", 0, odoIdle); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation, TOperationSide ASide, int ACount, bool ATemp, const UnicodeString ADirectory, unsigned long ACPSLimit, TOnceDoneOperation InitialOnceDoneOperation) { { TGuard Guard(FSection); // not really needed, just for consistency DoClear(!FRestored, (FPersistence.Side != osCurrent) && (FPersistence.Side != ASide)); FTotalTransferBase = FPersistence.TotalTransferred; FOperation = AOperation; FPersistence.Side = ASide; FCount = ACount; FInProgress = true; FCancel = csContinue; FDirectory = ADirectory; FTemp = ATemp; FInitialOnceDoneOperation = InitialOnceDoneOperation; FPersistence.CPSLimit = ACPSLimit; } try { DoProgress(); } catch (...) { // connection can be lost during progress callbacks ClearTransfer(); FInProgress = false; throw; } } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Reset() { FReset = true; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Stop() { // added to include remaining bytes to TotalSkipped, in case // the progress happens to update before closing ClearTransfer(); FInProgress = false; DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetDone() { FDone = true; DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Suspend() { { TGuard Guard(FSection); DebugAssert(!Suspended); FSuspended = true; FSuspendTime = GetTickCount(); } DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Resume() { { TGuard Guard(FSection); DebugAssert(Suspended); FSuspended = false; // shift timestamps for CPS calculation in advance // by the time the progress was suspended unsigned long Stopped = (GetTickCount() - FSuspendTime); size_t i = 0; while (i < FPersistence.Ticks.size()) { FPersistence.Ticks[i] += Stopped; ++i; } } DoProgress(); } //--------------------------------------------------------------------------- int __fastcall TFileOperationProgressType::OperationProgress() const { int Result; if (FCount > 0) { Result = (FFilesFinished * 100)/FCount; } else { Result = 0; } return Result; } //--------------------------------------------------------------------------- int __fastcall TFileOperationProgressType::TransferProgress() { int Result; if (TransferSize) { Result = (int)((TransferredSize * 100)/TransferSize); } else { Result = 0; } return Result; } //--------------------------------------------------------------------------- int __fastcall TFileOperationProgressType::TotalTransferProgress() const { TGuard Guard(FSection); DebugAssert(TotalSizeSet); int Result; if (FTotalSize > 0) { Result = (int)(((FPersistence.TotalTransferred - FTotalTransferBase + FTotalSkipped) * 100)/FTotalSize); } else { Result = 0; } return Result < 100 ? Result : 100; } //--------------------------------------------------------------------------- int __fastcall TFileOperationProgressType::OverallProgress() const { if (TotalSizeSet) { DebugAssert((Operation == foCopy) || (Operation == foMove)); return TotalTransferProgress(); } else { return OperationProgress(); } } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Progress() { DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::DoProgress() { SetThreadExecutionState(ES_SYSTEM_REQUIRED); FOnProgress(*this); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Finish(UnicodeString FileName, bool Success, TOnceDoneOperation & OnceDoneOperation) { DebugAssert(InProgress); // Cancel reader is guarded FOnFinished(Operation, Side, Temp, FileName, Success && (Cancel == csContinue), OnceDoneOperation); FFilesFinished++; if (Success) { FFilesFinishedSuccessfully++; } DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Succeeded(int Count) { if (FPersistence.Statistics != NULL) { if ((Operation == foCopy) || (Operation == foMove)) { __int64 Transferred = FTransferredSize - FSkippedSize; if (Side == osLocal) { FPersistence.Statistics->FilesUploaded += Count; FPersistence.Statistics->TotalUploaded += Transferred; } else { FPersistence.Statistics->FilesDownloaded += Count; FPersistence.Statistics->TotalDownloaded += Transferred; } } else if (Operation == foDelete) { if (Side == osLocal) { FPersistence.Statistics->FilesDeletedLocal += Count; } else { FPersistence.Statistics->FilesDeletedRemote += Count; } } } } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetFile(UnicodeString AFileName, bool AFileInProgress) { FFullFileName = AFileName; if (Side == osRemote) { // historically set were passing filename-only for remote site operations, // now we need to collect a full paths, so we pass in full path, // but still want to have filename-only in FileName AFileName = UnixExtractFileName(AFileName); } FFileName = AFileName; FFileInProgress = AFileInProgress; ClearTransfer(); FFileStartTime = Now(); DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetFileInProgress() { DebugAssert(!FileInProgress); FFileInProgress = true; DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetLocalSize(__int64 ASize) { FLocalSize = ASize; DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::AddLocallyUsed(__int64 ASize) { FLocallyUsed += ASize; if (LocallyUsed > LocalSize) { FLocalSize = LocallyUsed; } DoProgress(); } //--------------------------------------------------------------------------- bool __fastcall TFileOperationProgressType::IsLocallyDone() { DebugAssert(LocallyUsed <= LocalSize); return (LocallyUsed == LocalSize); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetSpeedCounters() { if ((CPSLimit > 0) && !FPersistence.CounterSet) { FPersistence.CounterSet = true; Configuration->Usage->Inc(L"SpeedLimitUses"); } } //--------------------------------------------------------------------------- // Used in WebDAV and S3 protocols void __fastcall TFileOperationProgressType::ThrottleToCPSLimit( unsigned long Size) { unsigned long Remaining = Size; while (Remaining > 0) { Remaining -= AdjustToCPSLimit(Remaining); } } //--------------------------------------------------------------------------- unsigned long __fastcall TFileOperationProgressType::AdjustToCPSLimit( unsigned long Size) { SetSpeedCounters(); // CPSLimit reader is guarded, we cannot block whole method as it can last long. if (CPSLimit > 0) { // we must not return 0, hence, if we reach zero, // we wait until the next second do { unsigned int Second = (GetTickCount() / MSecsPerSec); if (Second != FLastSecond) { FRemainingCPS = CPSLimit; FLastSecond = Second; } if (FRemainingCPS == 0) { SleepEx(100, true); DoProgress(); } } while ((CPSLimit > 0) && (FRemainingCPS == 0)); // CPSLimit may have been dropped in DoProgress if (CPSLimit > 0) { if (FRemainingCPS < Size) { Size = FRemainingCPS; } FRemainingCPS -= Size; } } return Size; } //--------------------------------------------------------------------------- // Use in SCP protocol only unsigned long __fastcall TFileOperationProgressType::LocalBlockSize() { unsigned long Result = TRANSFER_BUF_SIZE; if (LocallyUsed + Result > LocalSize) { Result = (unsigned long)(LocalSize - LocallyUsed); } Result = AdjustToCPSLimit(Result); return Result; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetTotalSize(__int64 ASize) { TGuard Guard(FSection); // not really needed, just for consistency FTotalSize = ASize; FTotalSizeSet = true; // parent has its own totals if (FParent != NULL) { DebugAssert(FParent->TotalSizeSet); } DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetTransferSize(__int64 ASize) { FTransferSize = ASize; DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetTransferringFile(bool ATransferringFile) { FTransferringFile = ATransferringFile; } //--------------------------------------------------------------------------- bool __fastcall TFileOperationProgressType::PassCancelToParent(TCancelStatus ACancel) { bool Result; if (ACancel < csCancel) { // do not propagate csCancelFile, // though it's not supported for queue atm, so we do not expect it here DebugFail(); Result = false; } else if (ACancel == csCancel) { Result = true; } else { // csCancelTransfer and csRemoteAbort are used with SCP only, which does not use parallel transfers DebugFail(); Result = false; } return Result; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetCancel(TCancelStatus ACancel) { TGuard Guard(FSection); FCancel = ACancel; if ((FParent != NULL) && PassCancelToParent(ACancel)) { FParent->SetCancel(ACancel); } } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetCancelAtLeast(TCancelStatus ACancel) { TGuard Guard(FSection); if (FCancel < ACancel) { FCancel = ACancel; } if ((FParent != NULL) && PassCancelToParent(ACancel)) { FParent->SetCancelAtLeast(ACancel); } } //--------------------------------------------------------------------------- TCancelStatus __fastcall TFileOperationProgressType::GetCancel() { TCancelStatus Result = FCancel; if (FParent != NULL) { TGuard Guard(FSection); TCancelStatus ParentCancel = FParent->Cancel; if (ParentCancel > Result) { Result = ParentCancel; } } return Result; } //--------------------------------------------------------------------------- bool __fastcall TFileOperationProgressType::ClearCancelFile() { TGuard Guard(FSection); // Not propagated to parent, as this is local flag, see also PassCancelToParent bool Result = (Cancel == csCancelFile); if (Result) { FCancel = csContinue; } return Result; } //--------------------------------------------------------------------------- unsigned long __fastcall TFileOperationProgressType::GetCPSLimit() { unsigned int Result; if (FParent != NULL) { Result = FParent->CPSLimit; } else { TGuard Guard(FSection); Result = FPersistence.CPSLimit; } return Result; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetCPSLimit(unsigned long ACPSLimit) { if (FParent != NULL) { FParent->SetCPSLimit(ACPSLimit); } else { TGuard Guard(FSection); FPersistence.CPSLimit = ACPSLimit; } } //--------------------------------------------------------------------------- TBatchOverwrite __fastcall TFileOperationProgressType::GetBatchOverwrite() { TBatchOverwrite Result; if (FParent != NULL) { Result = FParent->BatchOverwrite; } else { TGuard Guard(FSection); // not really needed Result = FPersistence.BatchOverwrite; } return Result; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetBatchOverwrite(TBatchOverwrite ABatchOverwrite) { if (FParent != NULL) { FParent->SetBatchOverwrite(ABatchOverwrite); } else { TGuard Guard(FSection); // not really needed FPersistence.BatchOverwrite = ABatchOverwrite;; } } //--------------------------------------------------------------------------- bool __fastcall TFileOperationProgressType::GetSkipToAll() { bool Result; if (FParent != NULL) { Result = FParent->SkipToAll; } else { TGuard Guard(FSection); // not really needed Result = FPersistence.SkipToAll; } return Result; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetSkipToAll() { if (FParent != NULL) { FParent->SetSkipToAll(); } else { TGuard Guard(FSection); // not really needed FPersistence.SkipToAll = true; } } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::ChangeTransferSize(__int64 ASize) { // reflect change on file size (due to text transfer mode conversion particulary) // on total transfer size if (TotalSizeSet) { AddTotalSize(ASize - TransferSize); } FTransferSize = ASize; DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::RollbackTransferFromTotals(__int64 ATransferredSize, __int64 ASkippedSize) { TGuard Guard(FSection); DebugAssert(ATransferredSize <= FPersistence.TotalTransferred - FTotalTransferBase); DebugAssert(ASkippedSize <= FTotalSkipped); FPersistence.TotalTransferred -= ATransferredSize; FPersistence.Ticks.clear(); FPersistence.TotalTransferredThen.clear(); FTotalSkipped -= ASkippedSize; if (FParent != NULL) { FParent->RollbackTransferFromTotals(ATransferredSize, ASkippedSize); } } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::RollbackTransfer() { FTransferredSize -= FSkippedSize; RollbackTransferFromTotals(FTransferredSize, FSkippedSize); FSkippedSize = 0; FTransferredSize = 0; FTransferSize = 0; FLocallyUsed = 0; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::AddTransferredToTotals(__int64 ASize) { TGuard Guard(FSection); FPersistence.TotalTransferred += ASize; if (ASize >= 0) { unsigned long Ticks = GetTickCount(); if (FPersistence.Ticks.empty() || (FPersistence.Ticks.back() > Ticks) || // ticks wrap after 49.7 days ((Ticks - FPersistence.Ticks.back()) >= MSecsPerSec)) { FPersistence.Ticks.push_back(Ticks); FPersistence.TotalTransferredThen.push_back(FPersistence.TotalTransferred); } if (FPersistence.Ticks.size() > 10) { FPersistence.Ticks.erase(FPersistence.Ticks.begin()); FPersistence.TotalTransferredThen.erase(FPersistence.TotalTransferredThen.begin()); } } else { FPersistence.Ticks.clear(); } if (FParent != NULL) { FParent->AddTransferredToTotals(ASize); } } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::AddTotalSize(__int64 ASize) { if (ASize != 0) { TGuard Guard(FSection); FTotalSize += ASize; if (FParent != NULL) { FParent->AddTotalSize(ASize); } } } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::AddTransferred(__int64 ASize, bool AddToTotals) { FTransferredSize += ASize; if (TransferredSize > TransferSize) { // this can happen with SFTP when downloading file that // grows while being downloaded if (TotalSizeSet) { // we should probably guard this with AddToTotals AddTotalSize(TransferredSize - TransferSize); } FTransferSize = TransferredSize; } if (AddToTotals) { AddTransferredToTotals(ASize); } DoProgress(); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::AddSkipped(__int64 ASize) { TGuard Guard(FSection); FTotalSkipped += ASize; if (FParent != NULL) { FParent->AddSkipped(ASize); } } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::AddResumed(__int64 ASize) { AddSkipped(ASize); FSkippedSize += ASize; AddTransferred(ASize, false); AddLocallyUsed(ASize); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::AddSkippedFileSize(__int64 ASize) { AddSkipped(ASize); DoProgress(); } //--------------------------------------------------------------------------- // Use in SCP protocol only unsigned long __fastcall TFileOperationProgressType::TransferBlockSize() { unsigned long Result = TRANSFER_BUF_SIZE; if (TransferredSize + Result > TransferSize) { Result = (unsigned long)(TransferSize - TransferredSize); } Result = AdjustToCPSLimit(Result); return Result; } //--------------------------------------------------------------------------- unsigned long __fastcall TFileOperationProgressType::StaticBlockSize() { return TRANSFER_BUF_SIZE; } //--------------------------------------------------------------------------- bool TFileOperationProgressType::IsTransferDoneChecked() { DebugAssert(TransferredSize <= TransferSize); return IsTransferDone(); } //--------------------------------------------------------------------------- bool TFileOperationProgressType::IsTransferDone() { return (TransferredSize == TransferSize); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::SetAsciiTransfer(bool AAsciiTransfer) { FAsciiTransfer = AAsciiTransfer; DoProgress(); } //--------------------------------------------------------------------------- TDateTime __fastcall TFileOperationProgressType::TimeElapsed() { return Now() - StartTime; } //--------------------------------------------------------------------------- unsigned int __fastcall TFileOperationProgressType::CPS() { TGuard Guard(FSection); return GetCPS(); } //--------------------------------------------------------------------------- // Has to be called from a guarded method unsigned int __fastcall TFileOperationProgressType::GetCPS() { unsigned int Result; if (FPersistence.Ticks.empty()) { Result = 0; } else { unsigned long Ticks = (Suspended ? FSuspendTime : GetTickCount()); unsigned long TimeSpan; if (Ticks < FPersistence.Ticks.front()) { // clocks has wrapped, guess 10 seconds difference TimeSpan = 10000; } else { TimeSpan = (Ticks - FPersistence.Ticks.front()); } if (TimeSpan == 0) { Result = 0; } else { __int64 Transferred = (FPersistence.TotalTransferred - FPersistence.TotalTransferredThen.front()); Result = (unsigned int)(Transferred * MSecsPerSec / TimeSpan); } } return Result; } //--------------------------------------------------------------------------- TDateTime __fastcall TFileOperationProgressType::TimeExpected() { unsigned int CurCps = CPS(); if (CurCps) { return TDateTime((double)(((double)(TransferSize - TransferredSize)) / CurCps) / SecsPerDay); } else { return 0; } } //--------------------------------------------------------------------------- TDateTime __fastcall TFileOperationProgressType::TotalTimeLeft() { TGuard Guard(FSection); DebugAssert(FTotalSizeSet); unsigned int CurCps = GetCPS(); // sanity check __int64 Processed = FTotalSkipped + FPersistence.TotalTransferred - FTotalTransferBase; if ((CurCps > 0) && (FTotalSize > Processed)) { return TDateTime((double)((double)(FTotalSize - Processed) / CurCps) / SecsPerDay); } else { return 0; } } //--------------------------------------------------------------------------- __int64 __fastcall TFileOperationProgressType::GetTotalTransferred() { TGuard Guard(FSection); return FPersistence.TotalTransferred; } //--------------------------------------------------------------------------- __int64 __fastcall TFileOperationProgressType::GetOperationTransferred() const { TGuard Guard(FSection); return FPersistence.TotalTransferred - FTotalTransferBase + FTotalSkipped; } //--------------------------------------------------------------------------- __int64 __fastcall TFileOperationProgressType::GetTotalSize() { TGuard Guard(FSection); return FTotalSize; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::LockUserSelections() { if (FParent != NULL) { FParent->LockUserSelections(); } else { FUserSelectionsSection->Enter(); } } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::UnlockUserSelections() { if (FParent != NULL) { FParent->UnlockUserSelections(); } else { FUserSelectionsSection->Leave(); } } //--------------------------------------------------------------------------- UnicodeString __fastcall TFileOperationProgressType::GetLogStr(bool Done) { UnicodeString Transferred = FormatSize(TotalTransferred); UnicodeString Left; TDateTime Time; UnicodeString TimeLabel; if (!Done && TotalSizeSet) { Time = TotalTimeLeft(); TimeLabel = L"Left"; } else { Time = TimeElapsed(); TimeLabel = L"Elapsed"; } UnicodeString TimeStr = FormatDateTimeSpan(Configuration->TimeFormat, Time); UnicodeString CPSStr = FormatSize(CPS()); return FORMAT(L"Transferred: %s, %s: %s, CPS: %s/s", (Transferred, TimeLabel, TimeStr, CPSStr)); } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Store(TPersistence & Persistence) { // in this current use, we do not need this to be guarded actually, as it's used only for a single-threaded synchronization TGuard Guard(FSection); Persistence = FPersistence; } //--------------------------------------------------------------------------- void __fastcall TFileOperationProgressType::Restore(TPersistence & Persistence) { TGuard Guard(FSection); FPersistence = Persistence; FRestored = true; }