1
0

FileOperationProgress.cpp 27 KB

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