FileOperationProgress.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "Common.h"
  5. #include "FileOperationProgress.h"
  6. #include "CoreMain.h"
  7. //---------------------------------------------------------------------------
  8. #define TRANSFER_BUF_SIZE 32768
  9. //---------------------------------------------------------------------------
  10. TFileOperationStatistics::TFileOperationStatistics()
  11. {
  12. memset(this, 0, sizeof(*this));
  13. }
  14. //---------------------------------------------------------------------------
  15. //---------------------------------------------------------------------------
  16. TFileOperationProgressType::TPersistence::TPersistence()
  17. {
  18. FStatistics = NULL;
  19. Clear(true, true);
  20. }
  21. //---------------------------------------------------------------------------
  22. bool TFileOperationProgressType::IsIndeterminateOperation(TFileOperation Operation)
  23. {
  24. return (Operation == foCalculateSize);
  25. }
  26. //---------------------------------------------------------------------------
  27. bool TFileOperationProgressType::IsTransferOperation(TFileOperation Operation)
  28. {
  29. return (Operation == foCopy) || (Operation == foMove);
  30. }
  31. //---------------------------------------------------------------------------
  32. void TFileOperationProgressType::TPersistence::Clear(bool Batch, bool Speed)
  33. {
  34. if (Batch)
  35. {
  36. TotalTransferred = 0;
  37. StartTime = Now();
  38. SkipToAll = false;
  39. BatchOverwrite = boNo;
  40. CPSLimit = 0;
  41. CounterSet = false;
  42. }
  43. if (Speed)
  44. {
  45. Ticks.clear();
  46. TotalTransferredThen.clear();
  47. }
  48. }
  49. //---------------------------------------------------------------------------
  50. __fastcall TFileOperationProgressType::TFileOperationProgressType()
  51. {
  52. FOnProgress = NULL;
  53. FOnFinished = NULL;
  54. FParent = NULL;
  55. Init();
  56. Clear();
  57. }
  58. //---------------------------------------------------------------------------
  59. __fastcall TFileOperationProgressType::TFileOperationProgressType(
  60. TFileOperationProgressEvent AOnProgress, TFileOperationFinished AOnFinished,
  61. TFileOperationProgressType * Parent)
  62. {
  63. FOnProgress = AOnProgress;
  64. FOnFinished = AOnFinished;
  65. FParent = Parent;
  66. FReset = false;
  67. Init();
  68. Clear();
  69. }
  70. //---------------------------------------------------------------------------
  71. __fastcall TFileOperationProgressType::~TFileOperationProgressType()
  72. {
  73. DebugAssert(!InProgress || FReset);
  74. DebugAssert(!Suspended || FReset);
  75. SAFE_DESTROY(FSection);
  76. SAFE_DESTROY(FUserSelectionsSection);
  77. }
  78. //---------------------------------------------------------------------------
  79. void __fastcall TFileOperationProgressType::Init()
  80. {
  81. FSection = new TCriticalSection();
  82. FUserSelectionsSection = new TCriticalSection();
  83. FRestored = false;
  84. FPersistence.Side = osCurrent; // = undefined value
  85. }
  86. //---------------------------------------------------------------------------
  87. void __fastcall TFileOperationProgressType::Assign(const TFileOperationProgressType & Other)
  88. {
  89. TValueRestorer<TCriticalSection *> SectionRestorer(FSection);
  90. TValueRestorer<TCriticalSection *> UserSelectionsSectionRestorer(FUserSelectionsSection);
  91. TGuard Guard(FSection);
  92. TGuard OtherGuard(Other.FSection);
  93. *this = Other;
  94. }
  95. //---------------------------------------------------------------------------
  96. void __fastcall TFileOperationProgressType::AssignButKeepSuspendState(const TFileOperationProgressType & Other)
  97. {
  98. TGuard Guard(FSection);
  99. TValueRestorer<unsigned int> SuspendTimeRestorer(FSuspendTime);
  100. TValueRestorer<bool> SuspendedRestorer(FSuspended);
  101. Assign(Other);
  102. }
  103. //---------------------------------------------------------------------------
  104. void __fastcall TFileOperationProgressType::DoClear(bool Batch, bool Speed)
  105. {
  106. FFileName = L"";
  107. FFullFileName = L"";
  108. FDirectory = L"";
  109. FAsciiTransfer = false;
  110. FCount = -1;
  111. FFilesFinished = 0;
  112. FFilesFinishedSuccessfully = 0;
  113. FSuspended = false;
  114. FSuspendTime = 0;
  115. FInProgress = false;
  116. FDone = false;
  117. FFileInProgress = false;
  118. FTotalSkipped = 0;
  119. FTotalSize = 0;
  120. FSkippedSize = 0;
  121. FTotalSizeSet = false;
  122. FOperation = foNone;
  123. FTemp = false;
  124. FPersistence.Clear(Batch, Speed);
  125. // to bypass check in ClearTransfer()
  126. FTransferSize = 0;
  127. ClearTransfer();
  128. }
  129. //---------------------------------------------------------------------------
  130. void __fastcall TFileOperationProgressType::Clear()
  131. {
  132. DoClear(true, true);
  133. }
  134. //---------------------------------------------------------------------------
  135. void __fastcall TFileOperationProgressType::ClearTransfer()
  136. {
  137. if ((TransferSize > 0) && (TransferredSize < TransferSize))
  138. {
  139. TGuard Guard(FSection);
  140. __int64 RemainingSize = (TransferSize - TransferredSize);
  141. AddSkipped(RemainingSize);
  142. }
  143. FLocalSize = 0;
  144. FTransferSize = 0;
  145. FLocallyUsed = 0;
  146. FSkippedSize = 0;
  147. FTransferredSize = 0;
  148. FTransferringFile = false;
  149. FLastSecond = 0;
  150. }
  151. //---------------------------------------------------------------------------
  152. void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation,
  153. TOperationSide ASide, int ACount)
  154. {
  155. Start(AOperation, ASide, ACount, false, L"", 0, odoIdle);
  156. }
  157. //---------------------------------------------------------------------------
  158. void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation,
  159. TOperationSide ASide, int ACount, bool ATemp,
  160. const UnicodeString ADirectory, unsigned long ACPSLimit, TOnceDoneOperation InitialOnceDoneOperation)
  161. {
  162. {
  163. TGuard Guard(FSection); // not really needed, just for consistency
  164. DoClear(!FRestored, (FPersistence.Side != osCurrent) && (FPersistence.Side != ASide));
  165. FTotalTransferBase = FPersistence.TotalTransferred;
  166. FOperation = AOperation;
  167. FPersistence.Side = ASide;
  168. FCount = ACount;
  169. FInProgress = true;
  170. FCancel = csContinue;
  171. FDirectory = ADirectory;
  172. FTemp = ATemp;
  173. FInitialOnceDoneOperation = InitialOnceDoneOperation;
  174. FPersistence.CPSLimit = ACPSLimit;
  175. }
  176. try
  177. {
  178. DoProgress();
  179. }
  180. catch (...)
  181. {
  182. // connection can be lost during progress callbacks
  183. ClearTransfer();
  184. FInProgress = false;
  185. throw;
  186. }
  187. }
  188. //---------------------------------------------------------------------------
  189. void __fastcall TFileOperationProgressType::Reset()
  190. {
  191. FReset = true;
  192. }
  193. //---------------------------------------------------------------------------
  194. void __fastcall TFileOperationProgressType::Stop()
  195. {
  196. // added to include remaining bytes to TotalSkipped, in case
  197. // the progress happens to update before closing
  198. ClearTransfer();
  199. FInProgress = false;
  200. DoProgress();
  201. }
  202. //---------------------------------------------------------------------------
  203. void __fastcall TFileOperationProgressType::SetDone()
  204. {
  205. FDone = true;
  206. DoProgress();
  207. }
  208. //---------------------------------------------------------------------------
  209. void __fastcall TFileOperationProgressType::Suspend()
  210. {
  211. {
  212. TGuard Guard(FSection);
  213. DebugAssert(!Suspended);
  214. FSuspended = true;
  215. FSuspendTime = GetTickCount();
  216. }
  217. DoProgress();
  218. }
  219. //---------------------------------------------------------------------------
  220. void __fastcall TFileOperationProgressType::Resume()
  221. {
  222. {
  223. TGuard Guard(FSection);
  224. DebugAssert(Suspended);
  225. FSuspended = false;
  226. // shift timestamps for CPS calculation in advance
  227. // by the time the progress was suspended
  228. unsigned long Stopped = (GetTickCount() - FSuspendTime);
  229. size_t i = 0;
  230. while (i < FPersistence.Ticks.size())
  231. {
  232. FPersistence.Ticks[i] += Stopped;
  233. ++i;
  234. }
  235. }
  236. DoProgress();
  237. }
  238. //---------------------------------------------------------------------------
  239. int __fastcall TFileOperationProgressType::OperationProgress() const
  240. {
  241. int Result;
  242. if (FCount > 0)
  243. {
  244. Result = (FFilesFinished * 100)/FCount;
  245. }
  246. else
  247. {
  248. Result = 0;
  249. }
  250. return Result;
  251. }
  252. //---------------------------------------------------------------------------
  253. int __fastcall TFileOperationProgressType::TransferProgress()
  254. {
  255. int Result;
  256. if (TransferSize)
  257. {
  258. Result = (int)((TransferredSize * 100)/TransferSize);
  259. }
  260. else
  261. {
  262. Result = 0;
  263. }
  264. return Result;
  265. }
  266. //---------------------------------------------------------------------------
  267. int __fastcall TFileOperationProgressType::TotalTransferProgress() const
  268. {
  269. TGuard Guard(FSection);
  270. DebugAssert(TotalSizeSet);
  271. int Result;
  272. if (FTotalSize > 0)
  273. {
  274. Result = (int)(((FPersistence.TotalTransferred - FTotalTransferBase + FTotalSkipped) * 100)/FTotalSize);
  275. }
  276. else
  277. {
  278. Result = 0;
  279. }
  280. return Result < 100 ? Result : 100;
  281. }
  282. //---------------------------------------------------------------------------
  283. int __fastcall TFileOperationProgressType::OverallProgress() const
  284. {
  285. if (TotalSizeSet)
  286. {
  287. DebugAssert(IsTransfer());
  288. return TotalTransferProgress();
  289. }
  290. else
  291. {
  292. return OperationProgress();
  293. }
  294. }
  295. //---------------------------------------------------------------------------
  296. void __fastcall TFileOperationProgressType::Progress()
  297. {
  298. DoProgress();
  299. }
  300. //---------------------------------------------------------------------------
  301. void __fastcall TFileOperationProgressType::DoProgress()
  302. {
  303. SetThreadExecutionState(ES_SYSTEM_REQUIRED);
  304. FOnProgress(*this);
  305. }
  306. //---------------------------------------------------------------------------
  307. void __fastcall TFileOperationProgressType::Finish(UnicodeString FileName,
  308. bool Success, TOnceDoneOperation & OnceDoneOperation)
  309. {
  310. DebugAssert(InProgress);
  311. // Cancel reader is guarded
  312. FOnFinished(Operation, Side, Temp, FileName,
  313. Success && (Cancel == csContinue), OnceDoneOperation);
  314. FFilesFinished++;
  315. if (Success)
  316. {
  317. FFilesFinishedSuccessfully++;
  318. }
  319. DoProgress();
  320. }
  321. //---------------------------------------------------------------------------
  322. void __fastcall TFileOperationProgressType::Succeeded(int Count)
  323. {
  324. if (FPersistence.Statistics != NULL)
  325. {
  326. if (IsTransfer())
  327. {
  328. __int64 Transferred = FTransferredSize - FSkippedSize;
  329. if (Side == osLocal)
  330. {
  331. FPersistence.Statistics->FilesUploaded += Count;
  332. FPersistence.Statistics->TotalUploaded += Transferred;
  333. }
  334. else
  335. {
  336. FPersistence.Statistics->FilesDownloaded += Count;
  337. FPersistence.Statistics->TotalDownloaded += Transferred;
  338. }
  339. }
  340. else if (Operation == foDelete)
  341. {
  342. if (Side == osLocal)
  343. {
  344. FPersistence.Statistics->FilesDeletedLocal += Count;
  345. }
  346. else
  347. {
  348. FPersistence.Statistics->FilesDeletedRemote += Count;
  349. }
  350. }
  351. }
  352. }
  353. //---------------------------------------------------------------------------
  354. void __fastcall TFileOperationProgressType::SetFile(UnicodeString AFileName, bool AFileInProgress)
  355. {
  356. FFullFileName = AFileName;
  357. if (Side == osRemote)
  358. {
  359. // historically set were passing filename-only for remote site operations,
  360. // now we need to collect a full paths, so we pass in full path,
  361. // but still want to have filename-only in FileName
  362. AFileName = UnixExtractFileName(AFileName);
  363. }
  364. FFileName = AFileName;
  365. FFileInProgress = AFileInProgress;
  366. ClearTransfer();
  367. FFileStartTime = Now();
  368. DoProgress();
  369. }
  370. //---------------------------------------------------------------------------
  371. void __fastcall TFileOperationProgressType::SetFileInProgress()
  372. {
  373. DebugAssert(!FileInProgress);
  374. FFileInProgress = true;
  375. DoProgress();
  376. }
  377. //---------------------------------------------------------------------------
  378. void __fastcall TFileOperationProgressType::SetLocalSize(__int64 ASize)
  379. {
  380. FLocalSize = ASize;
  381. DoProgress();
  382. }
  383. //---------------------------------------------------------------------------
  384. void __fastcall TFileOperationProgressType::AddLocallyUsed(__int64 ASize)
  385. {
  386. FLocallyUsed += ASize;
  387. if (LocallyUsed > LocalSize)
  388. {
  389. FLocalSize = LocallyUsed;
  390. }
  391. DoProgress();
  392. }
  393. //---------------------------------------------------------------------------
  394. bool __fastcall TFileOperationProgressType::IsLocallyDone()
  395. {
  396. DebugAssert(LocallyUsed <= LocalSize);
  397. return (LocallyUsed == LocalSize);
  398. }
  399. //---------------------------------------------------------------------------
  400. void __fastcall TFileOperationProgressType::SetSpeedCounters()
  401. {
  402. if ((CPSLimit > 0) && !FPersistence.CounterSet)
  403. {
  404. FPersistence.CounterSet = true;
  405. Configuration->Usage->Inc(L"SpeedLimitUses");
  406. }
  407. }
  408. //---------------------------------------------------------------------------
  409. // Used in WebDAV and S3 protocols
  410. void __fastcall TFileOperationProgressType::ThrottleToCPSLimit(
  411. unsigned long Size)
  412. {
  413. unsigned long Remaining = Size;
  414. while (Remaining > 0)
  415. {
  416. Remaining -= AdjustToCPSLimit(Remaining);
  417. }
  418. }
  419. //---------------------------------------------------------------------------
  420. unsigned long __fastcall TFileOperationProgressType::AdjustToCPSLimit(
  421. unsigned long Size)
  422. {
  423. SetSpeedCounters();
  424. // CPSLimit reader is guarded, we cannot block whole method as it can last long.
  425. if (CPSLimit > 0)
  426. {
  427. // we must not return 0, hence, if we reach zero,
  428. // we wait until the next second
  429. do
  430. {
  431. unsigned int Second = (GetTickCount() / MSecsPerSec);
  432. if (Second != FLastSecond)
  433. {
  434. FRemainingCPS = CPSLimit;
  435. FLastSecond = Second;
  436. }
  437. if (FRemainingCPS == 0)
  438. {
  439. SleepEx(100, true);
  440. DoProgress();
  441. }
  442. }
  443. while ((CPSLimit > 0) && (FRemainingCPS == 0));
  444. // CPSLimit may have been dropped in DoProgress
  445. if (CPSLimit > 0)
  446. {
  447. if (FRemainingCPS < Size)
  448. {
  449. Size = FRemainingCPS;
  450. }
  451. FRemainingCPS -= Size;
  452. }
  453. }
  454. return Size;
  455. }
  456. //---------------------------------------------------------------------------
  457. // Use in SCP protocol only
  458. unsigned long __fastcall TFileOperationProgressType::LocalBlockSize()
  459. {
  460. unsigned long Result = TRANSFER_BUF_SIZE;
  461. if (LocallyUsed + Result > LocalSize)
  462. {
  463. Result = (unsigned long)(LocalSize - LocallyUsed);
  464. }
  465. Result = AdjustToCPSLimit(Result);
  466. return Result;
  467. }
  468. //---------------------------------------------------------------------------
  469. void __fastcall TFileOperationProgressType::SetTotalSize(__int64 ASize)
  470. {
  471. TGuard Guard(FSection); // not really needed, just for consistency
  472. FTotalSize = ASize;
  473. FTotalSizeSet = true;
  474. // parent has its own totals
  475. if (FParent != NULL)
  476. {
  477. DebugAssert(FParent->TotalSizeSet);
  478. }
  479. DoProgress();
  480. }
  481. //---------------------------------------------------------------------------
  482. void __fastcall TFileOperationProgressType::SetTransferSize(__int64 ASize)
  483. {
  484. FTransferSize = ASize;
  485. DoProgress();
  486. }
  487. //---------------------------------------------------------------------------
  488. void __fastcall TFileOperationProgressType::SetTransferringFile(bool ATransferringFile)
  489. {
  490. FTransferringFile = ATransferringFile;
  491. }
  492. //---------------------------------------------------------------------------
  493. bool __fastcall TFileOperationProgressType::PassCancelToParent(TCancelStatus ACancel)
  494. {
  495. bool Result;
  496. if (ACancel < csCancel)
  497. {
  498. // do not propagate csCancelFile,
  499. // though it's not supported for queue atm, so we do not expect it here
  500. DebugFail();
  501. Result = false;
  502. }
  503. else if (ACancel == csCancel)
  504. {
  505. Result = true;
  506. }
  507. else
  508. {
  509. // csCancelTransfer and csRemoteAbort are used with SCP only, which does not use parallel transfers
  510. DebugFail();
  511. Result = false;
  512. }
  513. return Result;
  514. }
  515. //---------------------------------------------------------------------------
  516. void __fastcall TFileOperationProgressType::SetCancel(TCancelStatus ACancel)
  517. {
  518. TGuard Guard(FSection);
  519. FCancel = ACancel;
  520. if ((FParent != NULL) && PassCancelToParent(ACancel))
  521. {
  522. FParent->SetCancel(ACancel);
  523. }
  524. }
  525. //---------------------------------------------------------------------------
  526. void __fastcall TFileOperationProgressType::SetCancelAtLeast(TCancelStatus ACancel)
  527. {
  528. TGuard Guard(FSection);
  529. if (FCancel < ACancel)
  530. {
  531. FCancel = ACancel;
  532. }
  533. if ((FParent != NULL) && PassCancelToParent(ACancel))
  534. {
  535. FParent->SetCancelAtLeast(ACancel);
  536. }
  537. }
  538. //---------------------------------------------------------------------------
  539. TCancelStatus __fastcall TFileOperationProgressType::GetCancel()
  540. {
  541. TCancelStatus Result = FCancel;
  542. if (FParent != NULL)
  543. {
  544. TGuard Guard(FSection);
  545. TCancelStatus ParentCancel = FParent->Cancel;
  546. if (ParentCancel > Result)
  547. {
  548. Result = ParentCancel;
  549. }
  550. }
  551. return Result;
  552. }
  553. //---------------------------------------------------------------------------
  554. bool __fastcall TFileOperationProgressType::ClearCancelFile()
  555. {
  556. TGuard Guard(FSection);
  557. // Not propagated to parent, as this is local flag, see also PassCancelToParent
  558. bool Result = (Cancel == csCancelFile);
  559. if (Result)
  560. {
  561. FCancel = csContinue;
  562. }
  563. return Result;
  564. }
  565. //---------------------------------------------------------------------------
  566. unsigned long __fastcall TFileOperationProgressType::GetCPSLimit()
  567. {
  568. unsigned int Result;
  569. if (FParent != NULL)
  570. {
  571. Result = FParent->CPSLimit;
  572. }
  573. else
  574. {
  575. TGuard Guard(FSection);
  576. Result = FPersistence.CPSLimit;
  577. }
  578. return Result;
  579. }
  580. //---------------------------------------------------------------------------
  581. void __fastcall TFileOperationProgressType::SetCPSLimit(unsigned long ACPSLimit)
  582. {
  583. if (FParent != NULL)
  584. {
  585. FParent->SetCPSLimit(ACPSLimit);
  586. }
  587. else
  588. {
  589. TGuard Guard(FSection);
  590. FPersistence.CPSLimit = ACPSLimit;
  591. }
  592. }
  593. //---------------------------------------------------------------------------
  594. TBatchOverwrite __fastcall TFileOperationProgressType::GetBatchOverwrite()
  595. {
  596. TBatchOverwrite Result;
  597. if (FParent != NULL)
  598. {
  599. Result = FParent->BatchOverwrite;
  600. }
  601. else
  602. {
  603. TGuard Guard(FSection); // not really needed
  604. Result = FPersistence.BatchOverwrite;
  605. }
  606. return Result;
  607. }
  608. //---------------------------------------------------------------------------
  609. void __fastcall TFileOperationProgressType::SetBatchOverwrite(TBatchOverwrite ABatchOverwrite)
  610. {
  611. if (FParent != NULL)
  612. {
  613. FParent->SetBatchOverwrite(ABatchOverwrite);
  614. }
  615. else
  616. {
  617. TGuard Guard(FSection); // not really needed
  618. FPersistence.BatchOverwrite = ABatchOverwrite;;
  619. }
  620. }
  621. //---------------------------------------------------------------------------
  622. bool __fastcall TFileOperationProgressType::GetSkipToAll()
  623. {
  624. bool Result;
  625. if (FParent != NULL)
  626. {
  627. Result = FParent->SkipToAll;
  628. }
  629. else
  630. {
  631. TGuard Guard(FSection); // not really needed
  632. Result = FPersistence.SkipToAll;
  633. }
  634. return Result;
  635. }
  636. //---------------------------------------------------------------------------
  637. void __fastcall TFileOperationProgressType::SetSkipToAll()
  638. {
  639. if (FParent != NULL)
  640. {
  641. FParent->SetSkipToAll();
  642. }
  643. else
  644. {
  645. TGuard Guard(FSection); // not really needed
  646. FPersistence.SkipToAll = true;
  647. }
  648. }
  649. //---------------------------------------------------------------------------
  650. void __fastcall TFileOperationProgressType::ChangeTransferSize(__int64 ASize)
  651. {
  652. // reflect change on file size (due to text transfer mode conversion particulary)
  653. // on total transfer size
  654. if (TotalSizeSet)
  655. {
  656. AddTotalSize(ASize - TransferSize);
  657. }
  658. FTransferSize = ASize;
  659. DoProgress();
  660. }
  661. //---------------------------------------------------------------------------
  662. void __fastcall TFileOperationProgressType::RollbackTransferFromTotals(__int64 ATransferredSize, __int64 ASkippedSize)
  663. {
  664. TGuard Guard(FSection);
  665. DebugAssert(ATransferredSize <= FPersistence.TotalTransferred - FTotalTransferBase);
  666. DebugAssert(ASkippedSize <= FTotalSkipped);
  667. FPersistence.TotalTransferred -= ATransferredSize;
  668. FPersistence.Ticks.clear();
  669. FPersistence.TotalTransferredThen.clear();
  670. FTotalSkipped -= ASkippedSize;
  671. if (FParent != NULL)
  672. {
  673. FParent->RollbackTransferFromTotals(ATransferredSize, ASkippedSize);
  674. }
  675. }
  676. //---------------------------------------------------------------------------
  677. void __fastcall TFileOperationProgressType::RollbackTransfer()
  678. {
  679. FTransferredSize -= FSkippedSize;
  680. RollbackTransferFromTotals(FTransferredSize, FSkippedSize);
  681. FSkippedSize = 0;
  682. FTransferredSize = 0;
  683. FTransferSize = 0;
  684. FLocallyUsed = 0;
  685. }
  686. //---------------------------------------------------------------------------
  687. void __fastcall TFileOperationProgressType::AddTransferredToTotals(__int64 ASize)
  688. {
  689. TGuard Guard(FSection);
  690. FPersistence.TotalTransferred += ASize;
  691. if (ASize >= 0)
  692. {
  693. unsigned long Ticks = GetTickCount();
  694. if (FPersistence.Ticks.empty() ||
  695. (FPersistence.Ticks.back() > Ticks) || // ticks wrap after 49.7 days
  696. ((Ticks - FPersistence.Ticks.back()) >= MSecsPerSec))
  697. {
  698. FPersistence.Ticks.push_back(Ticks);
  699. FPersistence.TotalTransferredThen.push_back(FPersistence.TotalTransferred);
  700. }
  701. if (FPersistence.Ticks.size() > 10)
  702. {
  703. FPersistence.Ticks.erase(FPersistence.Ticks.begin());
  704. FPersistence.TotalTransferredThen.erase(FPersistence.TotalTransferredThen.begin());
  705. }
  706. }
  707. else
  708. {
  709. FPersistence.Ticks.clear();
  710. }
  711. if (FParent != NULL)
  712. {
  713. FParent->AddTransferredToTotals(ASize);
  714. }
  715. }
  716. //---------------------------------------------------------------------------
  717. void __fastcall TFileOperationProgressType::AddTotalSize(__int64 ASize)
  718. {
  719. if (ASize != 0)
  720. {
  721. TGuard Guard(FSection);
  722. FTotalSize += ASize;
  723. if (FParent != NULL)
  724. {
  725. FParent->AddTotalSize(ASize);
  726. }
  727. }
  728. }
  729. //---------------------------------------------------------------------------
  730. void __fastcall TFileOperationProgressType::AddTransferred(__int64 ASize,
  731. bool AddToTotals)
  732. {
  733. FTransferredSize += ASize;
  734. if (TransferredSize > TransferSize)
  735. {
  736. // this can happen with SFTP when downloading file that
  737. // grows while being downloaded
  738. if (TotalSizeSet)
  739. {
  740. // we should probably guard this with AddToTotals
  741. AddTotalSize(TransferredSize - TransferSize);
  742. }
  743. FTransferSize = TransferredSize;
  744. }
  745. if (AddToTotals)
  746. {
  747. AddTransferredToTotals(ASize);
  748. }
  749. DoProgress();
  750. }
  751. //---------------------------------------------------------------------------
  752. void __fastcall TFileOperationProgressType::AddSkipped(__int64 ASize)
  753. {
  754. TGuard Guard(FSection);
  755. FTotalSkipped += ASize;
  756. if (FParent != NULL)
  757. {
  758. FParent->AddSkipped(ASize);
  759. }
  760. }
  761. //---------------------------------------------------------------------------
  762. void __fastcall TFileOperationProgressType::AddResumed(__int64 ASize)
  763. {
  764. AddSkipped(ASize);
  765. FSkippedSize += ASize;
  766. AddTransferred(ASize, false);
  767. AddLocallyUsed(ASize);
  768. }
  769. //---------------------------------------------------------------------------
  770. void __fastcall TFileOperationProgressType::AddSkippedFileSize(__int64 ASize)
  771. {
  772. AddSkipped(ASize);
  773. DoProgress();
  774. }
  775. //---------------------------------------------------------------------------
  776. // Use in SCP protocol only
  777. unsigned long __fastcall TFileOperationProgressType::TransferBlockSize()
  778. {
  779. unsigned long Result = TRANSFER_BUF_SIZE;
  780. if (TransferredSize + Result > TransferSize)
  781. {
  782. Result = (unsigned long)(TransferSize - TransferredSize);
  783. }
  784. Result = AdjustToCPSLimit(Result);
  785. return Result;
  786. }
  787. //---------------------------------------------------------------------------
  788. unsigned long __fastcall TFileOperationProgressType::StaticBlockSize()
  789. {
  790. return TRANSFER_BUF_SIZE;
  791. }
  792. //---------------------------------------------------------------------------
  793. bool TFileOperationProgressType::IsTransferDoneChecked()
  794. {
  795. DebugAssert(TransferredSize <= TransferSize);
  796. return IsTransferDone();
  797. }
  798. //---------------------------------------------------------------------------
  799. // Note that this does not work correctly, if the file is larger than expected (at least with the FTP protocol)
  800. bool TFileOperationProgressType::IsTransferDone()
  801. {
  802. return (TransferredSize == TransferSize);
  803. }
  804. //---------------------------------------------------------------------------
  805. void __fastcall TFileOperationProgressType::SetAsciiTransfer(bool AAsciiTransfer)
  806. {
  807. FAsciiTransfer = AAsciiTransfer;
  808. DoProgress();
  809. }
  810. //---------------------------------------------------------------------------
  811. TDateTime __fastcall TFileOperationProgressType::TimeElapsed()
  812. {
  813. return Now() - StartTime;
  814. }
  815. //---------------------------------------------------------------------------
  816. unsigned int __fastcall TFileOperationProgressType::CPS()
  817. {
  818. TGuard Guard(FSection);
  819. return GetCPS();
  820. }
  821. //---------------------------------------------------------------------------
  822. inline static unsigned int CalculateCPS(__int64 Transferred, unsigned int MSecElapsed)
  823. {
  824. unsigned int Result;
  825. if (MSecElapsed == 0)
  826. {
  827. Result = 0;
  828. }
  829. else
  830. {
  831. Result = (unsigned int)(Transferred * MSecsPerSec / MSecElapsed);
  832. }
  833. return Result;
  834. }
  835. //---------------------------------------------------------------------------
  836. // Has to be called from a guarded method
  837. unsigned int __fastcall TFileOperationProgressType::GetCPS()
  838. {
  839. unsigned int Result;
  840. if (FPersistence.Ticks.empty())
  841. {
  842. Result = 0;
  843. }
  844. else
  845. {
  846. unsigned long Ticks = (Suspended ? FSuspendTime : GetTickCount());
  847. unsigned long TimeSpan;
  848. if (Ticks < FPersistence.Ticks.front())
  849. {
  850. // clocks has wrapped, guess 10 seconds difference
  851. TimeSpan = 10000;
  852. }
  853. else
  854. {
  855. TimeSpan = (Ticks - FPersistence.Ticks.front());
  856. }
  857. __int64 Transferred = (FPersistence.TotalTransferred - FPersistence.TotalTransferredThen.front());
  858. Result = CalculateCPS(Transferred, TimeSpan);
  859. }
  860. return Result;
  861. }
  862. //---------------------------------------------------------------------------
  863. TDateTime __fastcall TFileOperationProgressType::TimeExpected()
  864. {
  865. unsigned int CurCps = CPS();
  866. if (CurCps)
  867. {
  868. return TDateTime((double)(((double)(TransferSize - TransferredSize)) / CurCps) / SecsPerDay);
  869. }
  870. else
  871. {
  872. return 0;
  873. }
  874. }
  875. //---------------------------------------------------------------------------
  876. TDateTime __fastcall TFileOperationProgressType::TotalTimeLeft()
  877. {
  878. TGuard Guard(FSection);
  879. DebugAssert(FTotalSizeSet);
  880. unsigned int CurCps = GetCPS();
  881. // sanity check
  882. __int64 Processed = FTotalSkipped + FPersistence.TotalTransferred - FTotalTransferBase;
  883. if ((CurCps > 0) && (FTotalSize > Processed))
  884. {
  885. return TDateTime((double)((double)(FTotalSize - Processed) / CurCps) / SecsPerDay);
  886. }
  887. else
  888. {
  889. return 0;
  890. }
  891. }
  892. //---------------------------------------------------------------------------
  893. __int64 __fastcall TFileOperationProgressType::GetTotalTransferred()
  894. {
  895. TGuard Guard(FSection);
  896. return FPersistence.TotalTransferred;
  897. }
  898. //---------------------------------------------------------------------------
  899. __int64 __fastcall TFileOperationProgressType::GetOperationTransferred() const
  900. {
  901. TGuard Guard(FSection);
  902. return FPersistence.TotalTransferred - FTotalTransferBase + FTotalSkipped;
  903. }
  904. //---------------------------------------------------------------------------
  905. __int64 __fastcall TFileOperationProgressType::GetTotalSize()
  906. {
  907. TGuard Guard(FSection);
  908. return FTotalSize;
  909. }
  910. //---------------------------------------------------------------------------
  911. void __fastcall TFileOperationProgressType::LockUserSelections()
  912. {
  913. if (FParent != NULL)
  914. {
  915. FParent->LockUserSelections();
  916. }
  917. else
  918. {
  919. FUserSelectionsSection->Enter();
  920. }
  921. }
  922. //---------------------------------------------------------------------------
  923. void __fastcall TFileOperationProgressType::UnlockUserSelections()
  924. {
  925. if (FParent != NULL)
  926. {
  927. FParent->UnlockUserSelections();
  928. }
  929. else
  930. {
  931. FUserSelectionsSection->Leave();
  932. }
  933. }
  934. //---------------------------------------------------------------------------
  935. UnicodeString __fastcall TFileOperationProgressType::GetLogStr(bool Done)
  936. {
  937. UnicodeString Transferred = FormatSize(TotalTransferred);
  938. TDateTime Time;
  939. UnicodeString TimeLabel;
  940. if (!Done && TotalSizeSet)
  941. {
  942. Time = TotalTimeLeft();
  943. TimeLabel = L"Left";
  944. }
  945. else
  946. {
  947. Time = TimeElapsed();
  948. TimeLabel = L"Elapsed";
  949. }
  950. UnicodeString TimeStr = FormatDateTimeSpan(Configuration->TimeFormat, Time);
  951. unsigned int ACPS;
  952. if (!Done)
  953. {
  954. ACPS = CPS();
  955. }
  956. else
  957. {
  958. unsigned int Elapsed = TimeToMSec(TimeElapsed());
  959. ACPS = CalculateCPS(TotalTransferred, Elapsed);
  960. }
  961. UnicodeString CPSStr = FormatSize(ACPS);
  962. return FORMAT(L"Transferred: %s, %s: %s, CPS: %s/s", (Transferred, TimeLabel, TimeStr, CPSStr));
  963. }
  964. //---------------------------------------------------------------------------
  965. void __fastcall TFileOperationProgressType::Store(TPersistence & Persistence)
  966. {
  967. // in this current use, we do not need this to be guarded actually, as it's used only for a single-threaded synchronization
  968. TGuard Guard(FSection);
  969. Persistence = FPersistence;
  970. }
  971. //---------------------------------------------------------------------------
  972. void __fastcall TFileOperationProgressType::Restore(TPersistence & Persistence)
  973. {
  974. TGuard Guard(FSection);
  975. FPersistence = Persistence;
  976. FRestored = true;
  977. }
  978. //---------------------------------------------------------------------------
  979. bool TFileOperationProgressType::IsIndeterminate() const
  980. {
  981. return
  982. IsIndeterminateOperation(FOperation) ||
  983. (!TotalSizeSet && (FCount == 1));
  984. }
  985. //---------------------------------------------------------------------------
  986. bool TFileOperationProgressType::IsTransfer() const
  987. {
  988. return IsTransferOperation(Operation);
  989. }