FileOperationProgress.cpp 28 KB

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