FileOperationProgress.cpp 30 KB

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