Terminal.cpp 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "Terminal.h"
  5. #include <SysUtils.hpp>
  6. #include <FileCtrl.hpp>
  7. #include "Common.h"
  8. #include "FileBuffer.h"
  9. #include "FileSystems.h"
  10. #include "Interface.h"
  11. #include "RemoteFiles.h"
  12. #include "ScpFileSystem.h"
  13. #include "SftpFileSystem.h"
  14. #include "TextsCore.h"
  15. //---------------------------------------------------------------------------
  16. #pragma package(smart_init)
  17. //---------------------------------------------------------------------------
  18. #define COMMAND_ERROR_ARI(MESSAGE, REPEAT) \
  19. { \
  20. int Result = CommandError(&E, MESSAGE, qaRetry | qaSkip | qaAbort); \
  21. switch (Result) { \
  22. case qaRetry: { REPEAT; } break; \
  23. case qaAbort: Abort(); \
  24. } \
  25. }
  26. #define FILE_OPERATION_LOOP_EX(ALLOW_SKIP, MESSAGE, OPERATION) \
  27. FILE_OPERATION_LOOP_CUSTOM(this, ALLOW_SKIP, MESSAGE, OPERATION)
  28. //---------------------------------------------------------------------------
  29. struct TMoveFileParams
  30. {
  31. AnsiString Target;
  32. AnsiString FileMask;
  33. };
  34. //---------------------------------------------------------------------------
  35. __fastcall TTerminal::TTerminal(): TSecureShell()
  36. {
  37. FFiles = new TRemoteDirectory(this);
  38. FExceptionOnFail = 0;
  39. FInTransaction = 0;
  40. FReadCurrentDirectoryPending = false;
  41. FReadDirectoryPending = false;
  42. FUsersGroupsLookedup = False;
  43. FGroups = new TUsersGroupsList();
  44. FUsers = new TUsersGroupsList();
  45. FOnProgress = NULL;
  46. FOnFinished = NULL;
  47. FOnDeleteLocalFile = NULL;
  48. FAdditionalInfo = NULL;
  49. FUseBusyCursor = True;
  50. FLockDirectory = "";
  51. FDirectoryCache = new TRemoteDirectoryCache();
  52. FDirectoryChangesCache = NULL;
  53. FFSProtocol = cfsUnknown;
  54. }
  55. //---------------------------------------------------------------------------
  56. __fastcall TTerminal::~TTerminal()
  57. {
  58. if (SessionData->CacheDirectoryChanges && SessionData->PreserveDirectoryChanges &&
  59. (FDirectoryChangesCache != NULL))
  60. {
  61. Configuration->SaveDirectoryChangesCache(SessionData->SessionKey,
  62. FDirectoryChangesCache);
  63. }
  64. SAFE_DESTROY(FFileSystem);
  65. delete FFiles;
  66. delete FGroups;
  67. delete FUsers;
  68. delete FDirectoryCache;
  69. delete FDirectoryChangesCache;
  70. delete FAdditionalInfo;
  71. }
  72. //---------------------------------------------------------------------------
  73. void __fastcall TTerminal::KeepAlive()
  74. {
  75. if (SessionData->PingType == ptDummyCommand)
  76. {
  77. LogEvent("Executing dummy command to keep session alive.");
  78. assert(Active);
  79. assert(FFileSystem != NULL);
  80. try
  81. {
  82. FFileSystem->KeepAlive();
  83. }
  84. catch(Exception & E)
  85. {
  86. if (Active)
  87. {
  88. DoHandleExtendedException(&E);
  89. }
  90. else
  91. {
  92. throw;
  93. }
  94. }
  95. }
  96. else
  97. {
  98. TSecureShell::KeepAlive();
  99. }
  100. }
  101. //---------------------------------------------------------------------------
  102. bool __fastcall TTerminal::IsAbsolutePath(const AnsiString Path)
  103. {
  104. return !Path.IsEmpty() && Path[1] == '/';
  105. }
  106. //---------------------------------------------------------------------------
  107. AnsiString __fastcall TTerminal::ExpandFileName(AnsiString Path,
  108. const AnsiString BasePath)
  109. {
  110. Path = UnixExcludeTrailingBackslash(Path);
  111. if (!IsAbsolutePath(Path) && !BasePath.IsEmpty())
  112. {
  113. // TODO: Handle more complicated cases like "../../xxx"
  114. if (Path == "..")
  115. {
  116. Path = UnixExcludeTrailingBackslash(UnixExtractFilePath(
  117. UnixExcludeTrailingBackslash(BasePath)));
  118. }
  119. else
  120. {
  121. Path = UnixIncludeTrailingBackslash(BasePath) + Path;
  122. }
  123. }
  124. return Path;
  125. }
  126. //---------------------------------------------------------------------------
  127. AnsiString __fastcall TTerminal::GetProtocolName()
  128. {
  129. assert(FFileSystem);
  130. return FFileSystem->ProtocolName;
  131. }
  132. //---------------------------------------------------------------------------
  133. void __fastcall TTerminal::Close()
  134. {
  135. // file system cannot be destoryed here, moved to destructor
  136. TSecureShell::Close();
  137. }
  138. //---------------------------------------------------------------------------
  139. void __fastcall TTerminal::Open()
  140. {
  141. TSecureShell::Open();
  142. assert(!FFileSystem);
  143. if ((SessionData->FSProtocol == fsSCPonly) ||
  144. (SessionData->FSProtocol == fsSFTP && SshFallbackCmd()))
  145. {
  146. FFSProtocol = cfsSCP;
  147. FFileSystem = new TSCPFileSystem(this);
  148. LogEvent("Using SCP protocol.");
  149. }
  150. else
  151. {
  152. FFSProtocol = cfsSFTP;
  153. FFileSystem = new TSFTPFileSystem(this);
  154. LogEvent("Using SFTP protocol.");
  155. }
  156. if (SessionData->CacheDirectoryChanges)
  157. {
  158. FDirectoryChangesCache = new TRemoteDirectoryChangesCache();
  159. if (SessionData->PreserveDirectoryChanges)
  160. {
  161. Configuration->LoadDirectoryChangesCache(SessionData->SessionKey,
  162. FDirectoryChangesCache);
  163. }
  164. }
  165. }
  166. //---------------------------------------------------------------------------
  167. bool __fastcall TTerminal::GetIsCapable(TFSCapability Capability) const
  168. {
  169. assert(FFileSystem);
  170. return FFileSystem->IsCapable(Capability);
  171. }
  172. //---------------------------------------------------------------------------
  173. TStrings * __fastcall TTerminal::GetAdditionalInfo()
  174. {
  175. bool Initial = (FAdditionalInfo == NULL);
  176. if (Initial)
  177. {
  178. FAdditionalInfo = new TStringList();
  179. }
  180. assert(FFileSystem);
  181. FFileSystem->AdditionalInfo(FAdditionalInfo, Initial);
  182. return FAdditionalInfo;
  183. }
  184. //---------------------------------------------------------------------------
  185. AnsiString __fastcall TTerminal::AbsolutePath(AnsiString Path)
  186. {
  187. return FFileSystem->AbsolutePath(Path);
  188. }
  189. //---------------------------------------------------------------------------
  190. void __fastcall TTerminal::ReactOnCommand(int /*TFSCommand*/ Cmd)
  191. {
  192. bool ChangesDirectory = false;
  193. bool ModifiesFiles = false;
  194. switch ((TFSCommand)Cmd) {
  195. case fsChangeDirectory:
  196. case fsHomeDirectory:
  197. ChangesDirectory = true;
  198. break;
  199. case fsCopyToRemote:
  200. case fsDeleteFile:
  201. case fsRenameFile:
  202. case fsMoveFile:
  203. case fsCreateDirectory:
  204. case fsChangeMode:
  205. case fsChangeGroup:
  206. case fsChangeOwner:
  207. case fsChangeProperties:
  208. case fsAnyCommand:
  209. ModifiesFiles = true;
  210. break;
  211. }
  212. if (ChangesDirectory)
  213. {
  214. if (!FInTransaction)
  215. {
  216. ReadCurrentDirectory();
  217. ReadDirectory(false);
  218. }
  219. else
  220. {
  221. FReadCurrentDirectoryPending = true;
  222. FReadDirectoryPending = true;
  223. }
  224. }
  225. else
  226. if (ModifiesFiles)
  227. {
  228. if (!FInTransaction) ReadDirectory(true);
  229. else FReadDirectoryPending = true;
  230. }
  231. }
  232. //---------------------------------------------------------------------------
  233. void __fastcall TTerminal::TerminalError(AnsiString Msg)
  234. {
  235. TerminalError(NULL, Msg);
  236. }
  237. //---------------------------------------------------------------------------
  238. void __fastcall TTerminal::TerminalError(Exception * E, AnsiString Msg)
  239. {
  240. throw ETerminal(E, Msg);
  241. }
  242. //---------------------------------------------------------------------------
  243. int __fastcall TTerminal::FileOperationLoop(TFileOperationEvent CallBackFunc,
  244. TFileOperationProgressType * OperationProgress, bool AllowSkip,
  245. const AnsiString Message, void * Param1, void * Param2)
  246. {
  247. assert(CallBackFunc);
  248. int Result;
  249. FILE_OPERATION_LOOP_EX
  250. (
  251. AllowSkip, Message,
  252. Result = CallBackFunc(Param1, Param2);
  253. );
  254. return Result;
  255. }
  256. //---------------------------------------------------------------------------
  257. AnsiString __fastcall TTerminal::TranslateLockedPath(AnsiString Path, bool Lock)
  258. {
  259. if (!SessionData->LockInHome || Path.IsEmpty() || (Path[1] != '/'))
  260. return Path;
  261. if (Lock)
  262. {
  263. if (Path.SubString(1, FLockDirectory.Length()) == FLockDirectory)
  264. {
  265. Path.Delete(1, FLockDirectory.Length());
  266. if (Path.IsEmpty()) Path = "/";
  267. }
  268. }
  269. else
  270. {
  271. Path = UnixExcludeTrailingBackslash(FLockDirectory + Path);
  272. }
  273. return Path;
  274. }
  275. //---------------------------------------------------------------------------
  276. void __fastcall TTerminal::ClearCaches()
  277. {
  278. FDirectoryCache->Clear();
  279. if (FDirectoryChangesCache != NULL)
  280. {
  281. FDirectoryChangesCache->Clear();
  282. }
  283. }
  284. //---------------------------------------------------------------------------
  285. void __fastcall TTerminal::ClearCachedFileList(const AnsiString Path,
  286. bool SubDirs)
  287. {
  288. FDirectoryCache->ClearFileList(Path, SubDirs);
  289. }
  290. //---------------------------------------------------------------------------
  291. void __fastcall TTerminal::AddCachedFileList(TRemoteFileList * FileList)
  292. {
  293. FDirectoryCache->AddFileList(FileList);
  294. }
  295. //---------------------------------------------------------------------------
  296. bool __fastcall TTerminal::DirectoryFileList(const AnsiString Path,
  297. TRemoteFileList *& FileList, bool CanLoad)
  298. {
  299. bool Result = false;
  300. if (UnixComparePaths(FFiles->Directory, Path))
  301. {
  302. Result = (FileList == NULL) || (FileList->Timestamp < FFiles->Timestamp);
  303. if (Result)
  304. {
  305. if (FileList == NULL)
  306. {
  307. FileList = new TRemoteFileList();
  308. }
  309. FFiles->DuplicateTo(FileList);
  310. }
  311. }
  312. else
  313. {
  314. if (((FileList == NULL) && FDirectoryCache->HasFileList(Path)) ||
  315. ((FileList != NULL) && FDirectoryCache->HasNewerFileList(Path, FileList->Timestamp)))
  316. {
  317. bool Created = (FileList == NULL);
  318. if (Created)
  319. {
  320. FileList = new TRemoteFileList();
  321. }
  322. Result = FDirectoryCache->GetFileList(Path, FileList);
  323. if (!Result && Created)
  324. {
  325. SAFE_DESTROY(FileList);
  326. }
  327. }
  328. // do not attempt to load file list if there is cached version,
  329. // only absence of cached version indicates that we consider
  330. // the directory content obsolete
  331. else if (CanLoad && !FDirectoryCache->HasFileList(Path))
  332. {
  333. bool Created = (FileList == NULL);
  334. if (Created)
  335. {
  336. FileList = new TRemoteFileList();
  337. }
  338. FileList->Directory = Path;
  339. try
  340. {
  341. ReadDirectory(FileList);
  342. Result = true;
  343. }
  344. catch(...)
  345. {
  346. if (Created)
  347. {
  348. SAFE_DESTROY(FileList);
  349. }
  350. throw;
  351. }
  352. }
  353. }
  354. return Result;
  355. }
  356. //---------------------------------------------------------------------------
  357. void __fastcall TTerminal::SetCurrentDirectory(AnsiString value)
  358. {
  359. assert(FFileSystem);
  360. value = TranslateLockedPath(value, false);
  361. if (value != FFileSystem->CurrentDirectory)
  362. {
  363. ChangeDirectory(value);
  364. }
  365. }
  366. //---------------------------------------------------------------------------
  367. AnsiString __fastcall TTerminal::GetCurrentDirectory()
  368. {
  369. if (FFileSystem)
  370. {
  371. FCurrentDirectory = FFileSystem->CurrentDirectory;
  372. if (FCurrentDirectory.IsEmpty())
  373. {
  374. ReadCurrentDirectory();
  375. }
  376. }
  377. return TranslateLockedPath(FCurrentDirectory, true);
  378. }
  379. //---------------------------------------------------------------------------
  380. AnsiString __fastcall TTerminal::PeekCurrentDirectory()
  381. {
  382. if (FFileSystem)
  383. {
  384. FCurrentDirectory = FFileSystem->CurrentDirectory;
  385. }
  386. return TranslateLockedPath(FCurrentDirectory, true);
  387. }
  388. //---------------------------------------------------------------------------
  389. TUsersGroupsList * __fastcall TTerminal::GetGroups()
  390. {
  391. assert(FFileSystem);
  392. if (!FUsersGroupsLookedup && SessionData->LookupUserGroups &&
  393. IsCapable[fcUserGroupListing])
  394. {
  395. LookupUsersGroups();
  396. }
  397. return FGroups;
  398. }
  399. //---------------------------------------------------------------------------
  400. TUsersGroupsList * __fastcall TTerminal::GetUsers()
  401. {
  402. assert(FFileSystem);
  403. if (!FUsersGroupsLookedup && SessionData->LookupUserGroups &&
  404. IsCapable[fcUserGroupListing])
  405. {
  406. LookupUsersGroups();
  407. }
  408. return FUsers;
  409. }
  410. //---------------------------------------------------------------------------
  411. AnsiString __fastcall TTerminal::GetUserName() const
  412. {
  413. // in future might be implemented to detect username similar to GetUserGroups
  414. return SessionData->UserName;
  415. }
  416. //---------------------------------------------------------------------------
  417. bool __fastcall TTerminal::GetAreCachesEmpty() const
  418. {
  419. return FDirectoryCache->IsEmpty &&
  420. ((FDirectoryChangesCache == NULL) || FDirectoryChangesCache->IsEmpty);
  421. }
  422. //---------------------------------------------------------------------------
  423. void __fastcall TTerminal::DoChangeDirectory()
  424. {
  425. if (FOnChangeDirectory)
  426. {
  427. FOnChangeDirectory(this);
  428. }
  429. }
  430. //---------------------------------------------------------------------------
  431. void __fastcall TTerminal::DoReadDirectory(bool ReloadOnly)
  432. {
  433. if (FOnReadDirectory)
  434. {
  435. FOnReadDirectory(this, ReloadOnly);
  436. }
  437. }
  438. //---------------------------------------------------------------------------
  439. void __fastcall TTerminal::DoStartReadDirectory()
  440. {
  441. if (FOnStartReadDirectory)
  442. {
  443. FOnStartReadDirectory(this);
  444. }
  445. }
  446. //---------------------------------------------------------------------------
  447. void __fastcall TTerminal::BeginTransaction()
  448. {
  449. if (!FInTransaction)
  450. {
  451. FReadCurrentDirectoryPending = false;
  452. FReadDirectoryPending = false;
  453. }
  454. FInTransaction++;
  455. }
  456. //---------------------------------------------------------------------------
  457. void __fastcall TTerminal::EndTransaction()
  458. {
  459. // it connection was closed due to fatal error during transaction, do nothing
  460. if (Active)
  461. {
  462. if (!FInTransaction)
  463. TerminalError("Can't end transaction, not in transaction");
  464. assert(FInTransaction > 0);
  465. FInTransaction--;
  466. if (FInTransaction == 0)
  467. {
  468. try
  469. {
  470. if (FReadCurrentDirectoryPending) ReadCurrentDirectory();
  471. if (FReadDirectoryPending) ReadDirectory(!FReadCurrentDirectoryPending);
  472. }
  473. __finally
  474. {
  475. FReadCurrentDirectoryPending = false;
  476. FReadDirectoryPending = false;
  477. }
  478. }
  479. }
  480. }
  481. //---------------------------------------------------------------------------
  482. void __fastcall TTerminal::SetExceptionOnFail(bool value)
  483. {
  484. if (value) FExceptionOnFail++;
  485. else
  486. {
  487. if (FExceptionOnFail == 0)
  488. throw Exception("ExceptionOnFail is already zero.");
  489. FExceptionOnFail--;
  490. }
  491. }
  492. //---------------------------------------------------------------------------
  493. bool __fastcall TTerminal::GetExceptionOnFail() const
  494. {
  495. return (bool)(FExceptionOnFail > 0);
  496. }
  497. //---------------------------------------------------------------------------
  498. void __fastcall TTerminal::CommandError(Exception * E, const AnsiString Msg)
  499. {
  500. CommandError(E, Msg, 0);
  501. }
  502. //---------------------------------------------------------------------------
  503. int __fastcall TTerminal::CommandError(Exception * E, const AnsiString Msg,
  504. int Answers)
  505. {
  506. int Result = 0;
  507. if (E && E->InheritsFrom(__classid(EFatal)))
  508. {
  509. FatalError(E, Msg);
  510. }
  511. else if (E && E->InheritsFrom(__classid(EAbort)))
  512. {
  513. // resent EAbort exception
  514. Abort();
  515. }
  516. else if (ExceptionOnFail)
  517. {
  518. throw ECommand(E, Msg);
  519. }
  520. else if (!Answers)
  521. {
  522. ECommand * ECmd = new ECommand(E, Msg);
  523. try
  524. {
  525. DoShowExtendedException(ECmd);
  526. }
  527. __finally
  528. {
  529. delete ECmd;
  530. }
  531. }
  532. else
  533. {
  534. TQueryParams Params(qpAllowContinueOnError);
  535. Result = DoQueryUser(Msg, E, Answers, &Params);
  536. }
  537. return Result;
  538. }
  539. //---------------------------------------------------------------------------
  540. bool __fastcall TTerminal::HandleException(Exception * E)
  541. {
  542. if (ExceptionOnFail)
  543. {
  544. return false;
  545. }
  546. else
  547. {
  548. DoHandleExtendedException(E);
  549. return true;
  550. }
  551. }
  552. //---------------------------------------------------------------------------
  553. void __fastcall TTerminal::CloseOnCompletion(const AnsiString Message)
  554. {
  555. LogEvent("Closing session after completed operation (as requested by user)");
  556. Close();
  557. throw ESshTerminate(NULL,
  558. Message.IsEmpty() ? LoadStr(CLOSED_ON_COMPLETION) : Message);
  559. }
  560. //---------------------------------------------------------------------------
  561. int __fastcall TTerminal::ConfirmFileOverwrite(const AnsiString FileName,
  562. const TOverwriteFileParams * FileParams, int Answers, const TQueryParams * Params,
  563. TOperationSide Side, TFileOperationProgressType * OperationProgress)
  564. {
  565. int Answer;
  566. int AnswerForNewer =
  567. (FileParams->SourceTimestamp > FileParams->DestTimestamp ? qaYes : qaNo);
  568. if (OperationProgress->YesToNewer)
  569. {
  570. Answer = AnswerForNewer;
  571. }
  572. else
  573. {
  574. AnsiString Message = FMTLOAD((Side == osLocal ? LOCAL_FILE_OVERWRITE :
  575. REMOTE_FILE_OVERWRITE), (FileName));
  576. if (FileParams)
  577. {
  578. Message = FMTLOAD(FILE_OVERWRITE_DETAILS, (Message,
  579. IntToStr(FileParams->SourceSize),
  580. FormatDateTime("ddddd tt", FileParams->SourceTimestamp),
  581. IntToStr(FileParams->DestSize),
  582. FormatDateTime("ddddd tt", FileParams->DestTimestamp)));
  583. }
  584. Answer = DoQueryUser(Message, Answers, Params);
  585. switch (Answer)
  586. {
  587. case qaNeverAskAgain:
  588. Configuration->ConfirmOverwriting = false;
  589. Answer = qaYes;
  590. break;
  591. case qaYesToAll:
  592. OperationProgress->YesToAll = true;
  593. Answer = qaYes;
  594. break;
  595. case qaAll:
  596. OperationProgress->YesToNewer = true;
  597. Answer = AnswerForNewer;
  598. break;
  599. case qaNoToAll:
  600. OperationProgress->NoToAll = true;
  601. Answer = qaNo;
  602. }
  603. }
  604. return Answer;
  605. }
  606. //---------------------------------------------------------------------------
  607. void __fastcall TTerminal::FileModified(const TRemoteFile * File,
  608. const AnsiString FileName)
  609. {
  610. if (SessionData->CacheDirectories)
  611. {
  612. if ((File != NULL) && (File->Directory != NULL))
  613. {
  614. if (File->IsDirectory)
  615. {
  616. // do not use UnixIncludeTrailingBackslash(CurrentDirectory)
  617. DirectoryModified(
  618. File->Directory->FullDirectory + File->FileName, true);
  619. }
  620. DirectoryModified(File->Directory->Directory, false);
  621. }
  622. else if (!FileName.IsEmpty())
  623. {
  624. AnsiString Directory = UnixExtractFilePath(FileName);
  625. DirectoryModified(
  626. !Directory.IsEmpty() ? Directory : CurrentDirectory, false);
  627. }
  628. }
  629. }
  630. //---------------------------------------------------------------------------
  631. void __fastcall TTerminal::DoDirectoryModified(const AnsiString Path, bool SubDirs)
  632. {
  633. if (OnDirectoryModified != NULL)
  634. {
  635. OnDirectoryModified(this, Path, SubDirs);
  636. }
  637. }
  638. //---------------------------------------------------------------------------
  639. void __fastcall TTerminal::DirectoryModified(const AnsiString Path, bool SubDirs)
  640. {
  641. ClearCachedFileList(Path, SubDirs);
  642. DoDirectoryModified(Path, SubDirs);
  643. }
  644. //---------------------------------------------------------------------------
  645. void __fastcall TTerminal::DirectoryLoaded(TRemoteFileList * FileList)
  646. {
  647. AddCachedFileList(FileList);
  648. }
  649. //---------------------------------------------------------------------------
  650. void __fastcall TTerminal::ReloadDirectory()
  651. {
  652. if (SessionData->CacheDirectories)
  653. {
  654. DirectoryModified(CurrentDirectory, false);
  655. }
  656. if (SessionData->CacheDirectoryChanges)
  657. {
  658. assert(FDirectoryChangesCache != NULL);
  659. FDirectoryChangesCache->ClearDirectoryChange(CurrentDirectory);
  660. }
  661. ReadCurrentDirectory();
  662. FReadCurrentDirectoryPending = false;
  663. ReadDirectory(true);
  664. FReadDirectoryPending = false;
  665. }
  666. //---------------------------------------------------------------------------
  667. void __fastcall TTerminal::RefreshDirectory()
  668. {
  669. if (SessionData->CacheDirectories &&
  670. FDirectoryCache->HasNewerFileList(CurrentDirectory, FFiles->Timestamp))
  671. {
  672. // Second parameter was added to allow (rather force) using the cache.
  673. // Before, the directory was reloaded always, it seems useless,
  674. // has it any reason?
  675. ReadDirectory(true, true);
  676. FReadDirectoryPending = false;
  677. }
  678. }
  679. //---------------------------------------------------------------------------
  680. void __fastcall TTerminal::EnsureNonExistence(const AnsiString FileName)
  681. {
  682. // if filename doesn't contain path, we check for existence of file
  683. if ((UnixExtractFileDir(FileName).IsEmpty()) &&
  684. UnixComparePaths(CurrentDirectory, FFiles->Directory))
  685. {
  686. TRemoteFile *File = FFiles->FindFile(FileName);
  687. if (File)
  688. {
  689. if (File->IsDirectory) throw ECommand(NULL, FMTLOAD(RENAME_CREATE_DIR_EXISTS, (FileName)));
  690. else throw ECommand(NULL, FMTLOAD(RENAME_CREATE_FILE_EXISTS, (FileName)));
  691. }
  692. }
  693. }
  694. //---------------------------------------------------------------------------
  695. void __fastcall TTerminal::DoStartup()
  696. {
  697. LogEvent("Doing startup conversation with host.");
  698. BeginTransaction();
  699. try
  700. {
  701. UpdateStatus(sshStartup);
  702. // Make sure that directory would be loaded at last
  703. FReadCurrentDirectoryPending = true;
  704. FReadDirectoryPending = true;
  705. FFileSystem->DoStartup();
  706. if (SessionData->LookupUserGroups && IsCapable[fcUserGroupListing])
  707. {
  708. LookupUsersGroups();
  709. }
  710. UpdateStatus(sshOpenDirectory);
  711. if (!SessionData->RemoteDirectory.IsEmpty())
  712. {
  713. ChangeDirectory(SessionData->RemoteDirectory);
  714. }
  715. }
  716. __finally
  717. {
  718. EndTransaction();
  719. }
  720. LogEvent("Startup conversation with host finished.");
  721. UpdateStatus(sshReady);
  722. }
  723. //---------------------------------------------------------------------------
  724. void __fastcall TTerminal::ReadCurrentDirectory()
  725. {
  726. assert(FFileSystem);
  727. try
  728. {
  729. LogEvent("Getting current directory name.");
  730. AnsiString OldDirectory = FFileSystem->CurrentDirectory;
  731. FFileSystem->ReadCurrentDirectory();
  732. ReactOnCommand(fsCurrentDirectory);
  733. if (SessionData->CacheDirectoryChanges)
  734. {
  735. assert(FDirectoryChangesCache != NULL);
  736. FDirectoryChangesCache->AddDirectoryChange(OldDirectory,
  737. FLastDirectoryChange, CurrentDirectory);
  738. // not to broke the cache, if the next directory change would not
  739. // be initialited by ChangeDirectory(), which sets it
  740. // (HomeDirectory() particularly)
  741. FLastDirectoryChange = "";
  742. }
  743. if (OldDirectory.IsEmpty())
  744. {
  745. FLockDirectory = (SessionData->LockInHome ?
  746. FFileSystem->CurrentDirectory : AnsiString(""));
  747. }
  748. if (OldDirectory != FFileSystem->CurrentDirectory) DoChangeDirectory();
  749. }
  750. catch (Exception &E)
  751. {
  752. CommandError(&E, LoadStr(READ_CURRENT_DIR_ERROR));
  753. }
  754. }
  755. //---------------------------------------------------------------------------
  756. void __fastcall TTerminal::ReadDirectory(bool ReloadOnly, bool ForceCache)
  757. {
  758. bool LoadedFromCache = false;
  759. if (SessionData->CacheDirectories && FDirectoryCache->HasFileList(CurrentDirectory))
  760. {
  761. if (ReloadOnly && !ForceCache)
  762. {
  763. LogEvent("Cached directory not reloaded.");
  764. }
  765. else
  766. {
  767. DoStartReadDirectory();
  768. try
  769. {
  770. LoadedFromCache = FDirectoryCache->GetFileList(CurrentDirectory, FFiles);
  771. }
  772. __finally
  773. {
  774. DoReadDirectory(ReloadOnly);
  775. }
  776. if (LoadedFromCache)
  777. {
  778. LogEvent("Directory content loaded from cache.");
  779. }
  780. else
  781. {
  782. LogEvent("Cached Directory content has been removed.");
  783. }
  784. }
  785. }
  786. if (!LoadedFromCache)
  787. {
  788. DoStartReadDirectory();
  789. FFiles->Directory = CurrentDirectory;
  790. try
  791. {
  792. try
  793. {
  794. CustomReadDirectory(FFiles);
  795. }
  796. __finally
  797. {
  798. // this must be called before error is displayed, otherwise
  799. // TUnixDirView would be drawn with invalid data (it keeps reference
  800. // to already destoroyed old listing)
  801. DoReadDirectory(ReloadOnly);
  802. if (Active)
  803. {
  804. if (SessionData->CacheDirectories)
  805. {
  806. DirectoryLoaded(FFiles);
  807. }
  808. }
  809. }
  810. }
  811. catch (Exception &E)
  812. {
  813. CommandError(&E, FmtLoadStr(LIST_DIR_ERROR, ARRAYOFCONST((FFiles->Directory))));
  814. }
  815. }
  816. }
  817. //---------------------------------------------------------------------------
  818. void __fastcall TTerminal::CustomReadDirectory(TRemoteFileList * FileList)
  819. {
  820. assert(FileList);
  821. assert(FFileSystem);
  822. FFileSystem->ReadDirectory(FileList);
  823. ReactOnCommand(fsListDirectory);
  824. }
  825. //---------------------------------------------------------------------------
  826. TRemoteFileList * TTerminal::ReadDirectoryListing(AnsiString Directory, bool UseCache)
  827. {
  828. TRemoteFileList * FileList;
  829. try
  830. {
  831. FileList = new TRemoteFileList();
  832. try
  833. {
  834. bool LoadedFromCache = UseCache && SessionData->CacheDirectories &&
  835. FDirectoryCache->HasFileList(Directory);
  836. if (LoadedFromCache)
  837. {
  838. LoadedFromCache = FDirectoryCache->GetFileList(Directory, FileList);
  839. }
  840. if (!LoadedFromCache)
  841. {
  842. FileList->Directory = Directory;
  843. ExceptionOnFail = true;
  844. try
  845. {
  846. ReadDirectory(FileList);
  847. }
  848. __finally
  849. {
  850. ExceptionOnFail = false;
  851. }
  852. }
  853. }
  854. catch(...)
  855. {
  856. delete FileList;
  857. FileList = NULL;
  858. throw;
  859. }
  860. }
  861. catch(Exception & E)
  862. {
  863. COMMAND_ERROR_ARI
  864. (
  865. "",
  866. FileList = ReadDirectoryListing(Directory, UseCache);
  867. );
  868. }
  869. return FileList;
  870. }
  871. //---------------------------------------------------------------------------
  872. void __fastcall TTerminal::ProcessDirectory(const AnsiString DirName,
  873. TProcessFileEvent CallBackFunc, void * Param, bool UseCache)
  874. {
  875. TRemoteFileList * FileList = ReadDirectoryListing(DirName, UseCache);
  876. // skip if directory listing fails and user selects "skip"
  877. if (FileList)
  878. {
  879. try
  880. {
  881. AnsiString Directory = UnixIncludeTrailingBackslash(DirName);
  882. TRemoteFile * File;
  883. for (int Index = 0; Index < FileList->Count; Index++)
  884. {
  885. File = FileList->Files[Index];
  886. if (!File->IsParentDirectory && !File->IsThisDirectory)
  887. {
  888. CallBackFunc(Directory + File->FileName, File, Param);
  889. }
  890. }
  891. }
  892. __finally
  893. {
  894. delete FileList;
  895. }
  896. }
  897. }
  898. //---------------------------------------------------------------------------
  899. void __fastcall TTerminal::ReadDirectory(TRemoteFileList * FileList)
  900. {
  901. try
  902. {
  903. CustomReadDirectory(FileList);
  904. }
  905. catch (Exception &E)
  906. {
  907. CommandError(&E, FmtLoadStr(LIST_DIR_ERROR, ARRAYOFCONST((FileList->Directory))));
  908. }
  909. }
  910. //---------------------------------------------------------------------------
  911. void __fastcall TTerminal::ReadSymlink(TRemoteFile * SymlinkFile,
  912. TRemoteFile *& File)
  913. {
  914. assert(FFileSystem);
  915. try
  916. {
  917. LogEvent(FORMAT("Reading symlink \"%s\".", (SymlinkFile->FileName)));
  918. FFileSystem->ReadSymlink(SymlinkFile, File);
  919. ReactOnCommand(fsReadSymlink);
  920. }
  921. catch (Exception &E)
  922. {
  923. CommandError(&E, FMTLOAD(READ_SYMLINK_ERROR, (SymlinkFile->FileName)));
  924. }
  925. }
  926. //---------------------------------------------------------------------------
  927. void __fastcall TTerminal::ReadFile(const AnsiString FileName,
  928. TRemoteFile *& File)
  929. {
  930. assert(FFileSystem);
  931. File = NULL;
  932. try
  933. {
  934. LogEvent(FORMAT("Listing file \"%s\".", (FileName)));
  935. FFileSystem->ReadFile(FileName, File);
  936. ReactOnCommand(fsListFile);
  937. }
  938. catch (Exception &E)
  939. {
  940. if (File) delete File;
  941. File = NULL;
  942. CommandError(&E, FMTLOAD(LIST_DIR_ERROR, (FileName)));
  943. }
  944. }
  945. //---------------------------------------------------------------------------
  946. bool __fastcall TTerminal::ProcessFiles(TStrings * FileList,
  947. TFileOperation Operation, TProcessFileEvent ProcessFile, void * Param,
  948. TOperationSide Side)
  949. {
  950. assert(FFileSystem);
  951. assert(FileList);
  952. bool Result = false;
  953. bool DisconnectWhenComplete = false;
  954. try
  955. {
  956. TFileOperationProgressType Progress(FOnProgress, FOnFinished);
  957. Progress.Start(Operation, Side, FileList->Count);
  958. FOperationProgress = &Progress;
  959. try
  960. {
  961. BeginTransaction();
  962. try
  963. {
  964. int Index = 0;
  965. AnsiString FileName;
  966. bool Success;
  967. while ((Index < FileList->Count) && (Progress.Cancel == csContinue))
  968. {
  969. FileName = FileList->Strings[Index];
  970. try
  971. {
  972. Success = false;
  973. ProcessFile(FileName, (TRemoteFile *)FileList->Objects[Index], Param);
  974. Success = true;
  975. }
  976. __finally
  977. {
  978. Progress.Finish(FileName, Success, DisconnectWhenComplete);
  979. }
  980. Index++;
  981. }
  982. }
  983. __finally
  984. {
  985. EndTransaction();
  986. }
  987. if (Progress.Cancel == csContinue)
  988. {
  989. Result = true;
  990. }
  991. }
  992. __finally
  993. {
  994. FOperationProgress = NULL;
  995. Progress.Stop();
  996. }
  997. }
  998. catch (...)
  999. {
  1000. DisconnectWhenComplete = false;
  1001. // this was missing here. was it by purpose?
  1002. // without it any error message is lost
  1003. throw;
  1004. }
  1005. if (DisconnectWhenComplete)
  1006. {
  1007. CloseOnCompletion();
  1008. }
  1009. return Result;
  1010. }
  1011. //---------------------------------------------------------------------------
  1012. void __fastcall TTerminal::DeleteFile(AnsiString FileName,
  1013. const TRemoteFile * File, void * Recursive)
  1014. {
  1015. if (FileName.IsEmpty() && File)
  1016. {
  1017. FileName = File->FileName;
  1018. }
  1019. if (OperationProgress && OperationProgress->Operation == foDelete)
  1020. {
  1021. if (OperationProgress->Cancel != csContinue) Abort();
  1022. OperationProgress->SetFile(FileName);
  1023. }
  1024. LogEvent(FORMAT("Deleting file \"%s\".", (FileName)));
  1025. if (File) FileModified(File, FileName);
  1026. DoDeleteFile(FileName, File, Recursive);
  1027. ReactOnCommand(fsDeleteFile);
  1028. }
  1029. //---------------------------------------------------------------------------
  1030. void __fastcall TTerminal::DoDeleteFile(const AnsiString FileName,
  1031. const TRemoteFile * File, void * Recursive)
  1032. {
  1033. try
  1034. {
  1035. assert(FFileSystem);
  1036. // 'File' parameter: SFTPFileSystem needs to know if file is file or directory
  1037. FFileSystem->DeleteFile(FileName, File,
  1038. Recursive ? *((bool*)Recursive) : true);
  1039. }
  1040. catch(Exception & E)
  1041. {
  1042. COMMAND_ERROR_ARI
  1043. (
  1044. FMTLOAD(DELETE_FILE_ERROR, (FileName)),
  1045. DoDeleteFile(FileName, File, Recursive)
  1046. );
  1047. }
  1048. }
  1049. //---------------------------------------------------------------------------
  1050. bool __fastcall TTerminal::DeleteFiles(TStrings * FilesToDelete, bool * Recursive)
  1051. {
  1052. return ProcessFiles(FilesToDelete, foDelete, DeleteFile, Recursive);
  1053. }
  1054. //---------------------------------------------------------------------------
  1055. void __fastcall TTerminal::DeleteLocalFile(AnsiString FileName,
  1056. const TRemoteFile * /*File*/, void * /*Param*/)
  1057. {
  1058. if (OnDeleteLocalFile == NULL)
  1059. {
  1060. if (!RecursiveDeleteFile(FileName, false))
  1061. {
  1062. throw Exception(FMTLOAD(DELETE_FILE_ERROR, (FileName)));
  1063. }
  1064. }
  1065. else
  1066. {
  1067. OnDeleteLocalFile(FileName);
  1068. }
  1069. }
  1070. //---------------------------------------------------------------------------
  1071. bool __fastcall TTerminal::DeleteLocalFiles(TStrings * FileList)
  1072. {
  1073. return ProcessFiles(FileList, foDelete, DeleteLocalFile, NULL, osLocal);
  1074. }
  1075. //---------------------------------------------------------------------------
  1076. void __fastcall TTerminal::CustomCommandOnFile(AnsiString FileName,
  1077. const TRemoteFile * File, void * AParams)
  1078. {
  1079. TCustomCommandParams * Params = ((TCustomCommandParams *)AParams);
  1080. if (FileName.IsEmpty() && File)
  1081. {
  1082. FileName = File->FileName;
  1083. }
  1084. if (OperationProgress && OperationProgress->Operation == foCustomCommand)
  1085. {
  1086. if (OperationProgress->Cancel != csContinue) Abort();
  1087. OperationProgress->SetFile(FileName);
  1088. }
  1089. LogEvent(FORMAT("Executing custom command \"%s\" (%d) on file \"%s\".",
  1090. (Params->Command, Params->Params, FileName)));
  1091. if (File) FileModified(File, FileName);
  1092. DoCustomCommandOnFile(FileName, File, Params->Command, Params->Params);
  1093. ReactOnCommand(fsAnyCommand);
  1094. }
  1095. //---------------------------------------------------------------------------
  1096. void __fastcall TTerminal::DoCustomCommandOnFile(AnsiString FileName,
  1097. const TRemoteFile * File, AnsiString Command, int Params)
  1098. {
  1099. try
  1100. {
  1101. assert(FFileSystem);
  1102. FFileSystem->CustomCommandOnFile(FileName, File, Command, Params);
  1103. }
  1104. catch(Exception & E)
  1105. {
  1106. COMMAND_ERROR_ARI
  1107. (
  1108. FMTLOAD(CUSTOM_COMMAND_ERROR, (Command, FileName)),
  1109. DoCustomCommandOnFile(FileName, File, Command, Params)
  1110. );
  1111. }
  1112. }
  1113. //---------------------------------------------------------------------------
  1114. void __fastcall TTerminal::CustomCommandOnFiles(AnsiString Command,
  1115. int Params, TStrings * Files)
  1116. {
  1117. TCustomCommandParams AParams;
  1118. AParams.Command = Command;
  1119. AParams.Params = Params;
  1120. ProcessFiles(Files, foCustomCommand, CustomCommandOnFile, &AParams);
  1121. }
  1122. //---------------------------------------------------------------------------
  1123. void __fastcall TTerminal::ChangeFileProperties(AnsiString FileName,
  1124. const TRemoteFile * File, /*const TRemoteProperties*/ void * Properties)
  1125. {
  1126. TRemoteProperties * RProperties = (TRemoteProperties *)Properties;
  1127. assert(RProperties && !RProperties->Valid.Empty());
  1128. if (FileName.IsEmpty() && File)
  1129. {
  1130. FileName = File->FileName;
  1131. }
  1132. if (OperationProgress && OperationProgress->Operation == foSetProperties)
  1133. {
  1134. if (OperationProgress->Cancel != csContinue) Abort();
  1135. OperationProgress->SetFile(FileName);
  1136. }
  1137. if (IsLogging())
  1138. {
  1139. LogEvent(FORMAT("Changing properties of \"%s\" (%s)",
  1140. (FileName, BooleanToEngStr(RProperties->Recursive))));
  1141. if (RProperties->Valid.Contains(vpRights))
  1142. {
  1143. LogEvent(FORMAT(" - mode: \"%s\"", (RProperties->Rights.ModeStr)));
  1144. }
  1145. if (RProperties->Valid.Contains(vpGroup))
  1146. {
  1147. LogEvent(FORMAT(" - group: \"%s\"", (RProperties->Group)));
  1148. }
  1149. if (RProperties->Valid.Contains(vpOwner))
  1150. {
  1151. LogEvent(FORMAT(" - owner: \"%s\"", (RProperties->Owner)));
  1152. }
  1153. }
  1154. if (File) FileModified(File, FileName);
  1155. DoChangeFileProperties(FileName, File, RProperties);
  1156. ReactOnCommand(fsChangeProperties);
  1157. }
  1158. //---------------------------------------------------------------------------
  1159. void __fastcall TTerminal::DoChangeFileProperties(const AnsiString FileName,
  1160. const TRemoteFile * File, const TRemoteProperties * Properties)
  1161. {
  1162. try
  1163. {
  1164. assert(FFileSystem);
  1165. FFileSystem->ChangeFileProperties(FileName, File, Properties);
  1166. }
  1167. catch(Exception & E)
  1168. {
  1169. COMMAND_ERROR_ARI
  1170. (
  1171. FMTLOAD(CHANGE_PROPERTIES_ERROR, (FileName)),
  1172. DoChangeFileProperties(FileName, File, Properties)
  1173. );
  1174. }
  1175. }
  1176. //---------------------------------------------------------------------------
  1177. void __fastcall TTerminal::ChangeFilesProperties(TStrings * FileList,
  1178. const TRemoteProperties * Properties)
  1179. {
  1180. ProcessFiles(FileList, foSetProperties, ChangeFileProperties, (void *)Properties);
  1181. }
  1182. //---------------------------------------------------------------------------
  1183. void __fastcall TTerminal::CalculateFileSize(AnsiString FileName,
  1184. const TRemoteFile * File, /*TCalculateSizeParams*/ void * Param)
  1185. {
  1186. assert(Param);
  1187. assert(File);
  1188. TCalculateSizeParams * AParams = static_cast<TCalculateSizeParams*>(Param);
  1189. if (FileName.IsEmpty() && File)
  1190. {
  1191. FileName = File->FileName;
  1192. }
  1193. if ((AParams->CopyParam == NULL) ||
  1194. AParams->CopyParam->AllowTransfer(UnixExtractFileName(FileName)))
  1195. {
  1196. if (File->IsDirectory && !File->IsSymLink)
  1197. {
  1198. LogEvent(FORMAT("Getting size of directory \"%s\"", (FileName)));
  1199. DoCalculateDirectorySize(FileName, File, AParams);
  1200. }
  1201. else
  1202. {
  1203. AParams->Size += File->Size;
  1204. }
  1205. }
  1206. if (OperationProgress && OperationProgress->Operation == foCalculateSize)
  1207. {
  1208. if (OperationProgress->Cancel != csContinue) Abort();
  1209. OperationProgress->SetFile(FileName);
  1210. }
  1211. }
  1212. //---------------------------------------------------------------------------
  1213. void __fastcall TTerminal::DoCalculateDirectorySize(const AnsiString FileName,
  1214. const TRemoteFile * File, TCalculateSizeParams * Params)
  1215. {
  1216. try
  1217. {
  1218. ProcessDirectory(FileName, CalculateFileSize, Params);
  1219. }
  1220. catch(Exception & E)
  1221. {
  1222. if (!Active || ((Params->Params & csIgnoreErrors) == 0))
  1223. {
  1224. COMMAND_ERROR_ARI
  1225. (
  1226. FMTLOAD(CALCULATE_SIZE_ERROR, (FileName)),
  1227. DoCalculateDirectorySize(FileName, File, Params)
  1228. );
  1229. }
  1230. }
  1231. }
  1232. //---------------------------------------------------------------------------
  1233. void __fastcall TTerminal::CalculateFilesSize(TStrings * FileList,
  1234. __int64 & Size, int Params, const TCopyParamType * CopyParam)
  1235. {
  1236. TCalculateSizeParams Param;
  1237. Param.Size = 0;
  1238. Param.Params = Params;
  1239. Param.CopyParam = CopyParam;
  1240. ProcessFiles(FileList, foCalculateSize, CalculateFileSize, &Param);
  1241. Size = Param.Size;
  1242. }
  1243. //---------------------------------------------------------------------------
  1244. void __fastcall TTerminal::RenameFile(const AnsiString FileName,
  1245. const AnsiString NewName)
  1246. {
  1247. LogEvent(FORMAT("Renaming file \"%s\" to \"%s\".", (FileName, NewName)));
  1248. DoRenameFile(FileName, NewName, false);
  1249. ReactOnCommand(fsRenameFile);
  1250. }
  1251. //---------------------------------------------------------------------------
  1252. void __fastcall TTerminal::RenameFile(const TRemoteFile * File,
  1253. const AnsiString NewName, bool CheckExistence)
  1254. {
  1255. assert(File && File->Directory == FFiles);
  1256. bool Proceed = true;
  1257. // if filename doesn't contain path, we check for existence of file
  1258. if ((File->FileName != NewName) && CheckExistence &&
  1259. Configuration->ConfirmOverwriting &&
  1260. UnixComparePaths(CurrentDirectory, FFiles->Directory))
  1261. {
  1262. TRemoteFile * DuplicateFile = FFiles->FindFile(NewName);
  1263. if (DuplicateFile)
  1264. {
  1265. AnsiString QuestionFmt;
  1266. if (DuplicateFile->IsDirectory) QuestionFmt = LoadStr(DIRECTORY_OVERWRITE);
  1267. else QuestionFmt = LoadStr(FILE_OVERWRITE);
  1268. int Result;
  1269. TQueryParams Params(qpNeverAskAgainCheck);
  1270. Result = DoQueryUser(FORMAT(QuestionFmt, (NewName)),
  1271. qaYes | qaNo, &Params);
  1272. if (Result == qaNeverAskAgain)
  1273. {
  1274. Proceed = true;
  1275. Configuration->ConfirmOverwriting = false;
  1276. }
  1277. else
  1278. {
  1279. Proceed = (Result == qaYes);
  1280. }
  1281. }
  1282. }
  1283. if (Proceed)
  1284. {
  1285. FileModified(File, File->FileName);
  1286. RenameFile(File->FileName, NewName);
  1287. }
  1288. }
  1289. //---------------------------------------------------------------------------
  1290. void __fastcall TTerminal::DoRenameFile(const AnsiString FileName,
  1291. const AnsiString NewName, bool Move)
  1292. {
  1293. try
  1294. {
  1295. assert(FFileSystem);
  1296. FFileSystem->RenameFile(FileName, NewName);
  1297. }
  1298. catch(Exception & E)
  1299. {
  1300. COMMAND_ERROR_ARI
  1301. (
  1302. FMTLOAD(Move ? MOVE_FILE_ERROR : RENAME_FILE_ERROR, (FileName, NewName)),
  1303. DoRenameFile(FileName, NewName, Move)
  1304. );
  1305. }
  1306. }
  1307. //---------------------------------------------------------------------------
  1308. void __fastcall TTerminal::MoveFile(const AnsiString FileName,
  1309. const TRemoteFile * File, /*const TMoveFileParams*/ void * Param)
  1310. {
  1311. if (OperationProgress && (OperationProgress->Operation == foRemoteMove))
  1312. {
  1313. if (OperationProgress->Cancel != csContinue) Abort();
  1314. OperationProgress->SetFile(FileName);
  1315. }
  1316. assert(Param != NULL);
  1317. const TMoveFileParams & Params = *static_cast<const TMoveFileParams*>(Param);
  1318. AnsiString NewName = UnixIncludeTrailingBackslash(Params.Target) +
  1319. MaskFileName(UnixExtractFileName(FileName), Params.FileMask);
  1320. LogEvent(FORMAT("Moving file \"%s\" to \"%s\".", (FileName, NewName)));
  1321. FileModified(File, FileName);
  1322. DoRenameFile(FileName, NewName, true);
  1323. ReactOnCommand(fsMoveFile);
  1324. }
  1325. //---------------------------------------------------------------------------
  1326. bool __fastcall TTerminal::MoveFiles(TStrings * FileList, const AnsiString Target,
  1327. const AnsiString FileMask)
  1328. {
  1329. TMoveFileParams Params;
  1330. Params.Target = Target;
  1331. Params.FileMask = FileMask;
  1332. DirectoryModified(Target, true);
  1333. return ProcessFiles(FileList, foRemoteMove, MoveFile, &Params);
  1334. }
  1335. //---------------------------------------------------------------------------
  1336. void __fastcall TTerminal::CreateDirectory(const AnsiString DirName,
  1337. const TRemoteProperties * Properties)
  1338. {
  1339. assert(FFileSystem);
  1340. EnsureNonExistence(DirName);
  1341. FileModified(NULL, DirName);
  1342. LogEvent(FORMAT("Creating directory \"%s\".", (DirName)));
  1343. DoCreateDirectory(DirName, Properties);
  1344. ReactOnCommand(fsCreateDirectory);
  1345. }
  1346. //---------------------------------------------------------------------------
  1347. void __fastcall TTerminal::DoCreateDirectory(const AnsiString DirName,
  1348. const TRemoteProperties * Properties)
  1349. {
  1350. try
  1351. {
  1352. assert(FFileSystem);
  1353. FFileSystem->CreateDirectory(DirName, Properties);
  1354. }
  1355. catch(Exception & E)
  1356. {
  1357. COMMAND_ERROR_ARI
  1358. (
  1359. FMTLOAD(CREATE_DIR_ERROR, (DirName)),
  1360. DoCreateDirectory(DirName, Properties)
  1361. );
  1362. }
  1363. }
  1364. //---------------------------------------------------------------------------
  1365. void __fastcall TTerminal::CreateLink(const AnsiString FileName,
  1366. const AnsiString PointTo, bool Symbolic)
  1367. {
  1368. assert(FFileSystem);
  1369. EnsureNonExistence(FileName);
  1370. if (SessionData->CacheDirectories)
  1371. {
  1372. DirectoryModified(CurrentDirectory, false);
  1373. }
  1374. LogEvent(FORMAT("Creating link \"%s\" to \"%s\" (symbolic: %s).",
  1375. (FileName, PointTo, BooleanToEngStr(Symbolic))));
  1376. DoCreateLink(FileName, PointTo, Symbolic);
  1377. ReactOnCommand(fsCreateDirectory);
  1378. }
  1379. //---------------------------------------------------------------------------
  1380. void __fastcall TTerminal::DoCreateLink(const AnsiString FileName,
  1381. const AnsiString PointTo, bool Symbolic)
  1382. {
  1383. try
  1384. {
  1385. assert(FFileSystem);
  1386. FFileSystem->CreateLink(FileName, PointTo, Symbolic);
  1387. }
  1388. catch(Exception & E)
  1389. {
  1390. COMMAND_ERROR_ARI
  1391. (
  1392. FMTLOAD(CREATE_LINK_ERROR, (FileName)),
  1393. DoCreateLink(FileName, PointTo, Symbolic);
  1394. );
  1395. }
  1396. }
  1397. //---------------------------------------------------------------------------
  1398. void __fastcall TTerminal::HomeDirectory()
  1399. {
  1400. assert(FFileSystem);
  1401. try
  1402. {
  1403. LogEvent("Changing directory to home directory.");
  1404. FFileSystem->HomeDirectory();
  1405. ReactOnCommand(fsHomeDirectory);
  1406. }
  1407. catch (Exception &E)
  1408. {
  1409. CommandError(&E, LoadStr(CHANGE_HOMEDIR_ERROR));
  1410. }
  1411. }
  1412. //---------------------------------------------------------------------------
  1413. void __fastcall TTerminal::ChangeDirectory(const AnsiString Directory)
  1414. {
  1415. assert(FFileSystem);
  1416. try
  1417. {
  1418. AnsiString CachedDirectory;
  1419. assert(!SessionData->CacheDirectoryChanges || (FDirectoryChangesCache != NULL));
  1420. if (SessionData->CacheDirectoryChanges &&
  1421. FDirectoryChangesCache->GetDirectoryChange(PeekCurrentDirectory(),
  1422. Directory, CachedDirectory))
  1423. {
  1424. LogEvent(FORMAT("Cached directory change via \"%s\" to \"%s\".",
  1425. (Directory, CachedDirectory)));
  1426. FFileSystem->CachedChangeDirectory(CachedDirectory);
  1427. }
  1428. else
  1429. {
  1430. LogEvent(FORMAT("Changing directory to \"%s\".", (Directory)));
  1431. FFileSystem->ChangeDirectory(Directory);
  1432. }
  1433. FLastDirectoryChange = Directory;
  1434. ReactOnCommand(fsChangeDirectory);
  1435. }
  1436. catch (Exception &E)
  1437. {
  1438. CommandError(&E, FMTLOAD(CHANGE_DIR_ERROR, (Directory)));
  1439. }
  1440. }
  1441. //---------------------------------------------------------------------------
  1442. void __fastcall TTerminal::LookupUsersGroups()
  1443. {
  1444. assert(FFileSystem);
  1445. assert(IsCapable[fcUserGroupListing]);
  1446. try
  1447. {
  1448. FUsersGroupsLookedup = true;
  1449. LogEvent("Looking up groups and users.");
  1450. FFileSystem->LookupUsersGroups();
  1451. ReactOnCommand(fsLookupUsersGroups);
  1452. if (IsLogging())
  1453. {
  1454. if (FGroups->Count > 0)
  1455. {
  1456. LogEvent("Following groups found:");
  1457. for (int Index = 0; Index < FGroups->Count; Index++)
  1458. {
  1459. LogEvent(AnsiString(" ") + FGroups->Strings[Index]);
  1460. }
  1461. }
  1462. else
  1463. {
  1464. LogEvent("No groups found.");
  1465. }
  1466. if (FUsers->Count > 0)
  1467. {
  1468. LogEvent("Following users found:");
  1469. for (int Index = 0; Index < FUsers->Count; Index++)
  1470. {
  1471. LogEvent(AnsiString(" ") + FUsers->Strings[Index]);
  1472. }
  1473. }
  1474. else
  1475. {
  1476. LogEvent("No users found.");
  1477. }
  1478. }
  1479. }
  1480. catch (Exception &E)
  1481. {
  1482. CommandError(&E, LoadStr(LOOKUP_GROUPS_ERROR));
  1483. }
  1484. }
  1485. //---------------------------------------------------------------------------
  1486. bool __fastcall TTerminal::AllowedAnyCommand(const AnsiString Command)
  1487. {
  1488. return !Command.Trim().IsEmpty();
  1489. }
  1490. //---------------------------------------------------------------------------
  1491. void __fastcall TTerminal::AnyCommand(const AnsiString Command)
  1492. {
  1493. assert(FFileSystem);
  1494. try
  1495. {
  1496. DirectoryModified(CurrentDirectory, false);
  1497. LogEvent("Executing used defined command.");
  1498. FFileSystem->AnyCommand(Command);
  1499. ReactOnCommand(fsAnyCommand);
  1500. }
  1501. catch (Exception &E)
  1502. {
  1503. if (ExceptionOnFail || (E.InheritsFrom(__classid(EFatal)))) throw;
  1504. else DoShowExtendedException(&E);
  1505. }
  1506. }
  1507. //---------------------------------------------------------------------------
  1508. bool __fastcall TTerminal::CreateLocalFile(const AnsiString FileName,
  1509. TFileOperationProgressType * OperationProgress, HANDLE * AHandle)
  1510. {
  1511. assert(AHandle);
  1512. bool Result = true;
  1513. FILE_OPERATION_LOOP (FMTLOAD(CREATE_FILE_ERROR, (FileName)),
  1514. bool Done;
  1515. do
  1516. {
  1517. *AHandle = CreateFile(FileName.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
  1518. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  1519. Done = (*AHandle != INVALID_HANDLE_VALUE);
  1520. if (!Done)
  1521. {
  1522. int FileAttr;
  1523. if (FileExists(FileName) &&
  1524. (((FileAttr = FileGetAttr(FileName)) & faReadOnly) != 0))
  1525. {
  1526. if (OperationProgress->NoToAll)
  1527. {
  1528. Result = false;
  1529. }
  1530. else if (!OperationProgress->YesToAll)
  1531. {
  1532. int Answer;
  1533. SUSPEND_OPERATION
  1534. (
  1535. Answer = DoQueryUser(
  1536. FMTLOAD(READ_ONLY_OVERWRITE, (FileName)),
  1537. qaYes | qaNo | qaAbort | qaYesToAll | qaNoToAll, 0);
  1538. );
  1539. switch (Answer) {
  1540. case qaYesToAll: OperationProgress->YesToAll = true; break;
  1541. case qaAbort: OperationProgress->Cancel = csCancel; // continue on next case
  1542. case qaNoToAll: OperationProgress->NoToAll = true;
  1543. case qaNo: Result = false; break;
  1544. }
  1545. }
  1546. if (Result)
  1547. {
  1548. FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (FileName)),
  1549. if (FileSetAttr(FileName, FileAttr & ~faReadOnly) != 0)
  1550. {
  1551. EXCEPTION;
  1552. }
  1553. );
  1554. }
  1555. else
  1556. {
  1557. Done = true;
  1558. }
  1559. }
  1560. else
  1561. {
  1562. EXCEPTION;
  1563. }
  1564. }
  1565. }
  1566. while (!Done);
  1567. );
  1568. return Result;
  1569. }
  1570. //---------------------------------------------------------------------------
  1571. void __fastcall TTerminal::OpenLocalFile(const AnsiString FileName,
  1572. int Access, int * AAttrs, HANDLE * AHandle, unsigned long * ACTime,
  1573. unsigned long * AMTime, unsigned long * AATime, __int64 * ASize,
  1574. bool TryWriteReadOnly)
  1575. {
  1576. int Attrs = 0;
  1577. HANDLE Handle = 0;
  1578. FILE_OPERATION_LOOP (FMTLOAD(FILE_NOT_EXISTS, (FileName)),
  1579. Attrs = FileGetAttr(FileName);
  1580. if (Attrs == -1) EXCEPTION;
  1581. )
  1582. if ((Attrs & faDirectory) == 0)
  1583. {
  1584. bool NoHandle = false;
  1585. if (!TryWriteReadOnly && (Access == GENERIC_WRITE) &&
  1586. ((Attrs & faReadOnly) != 0))
  1587. {
  1588. Access = GENERIC_READ;
  1589. NoHandle = true;
  1590. }
  1591. FILE_OPERATION_LOOP (FMTLOAD(OPENFILE_ERROR, (FileName)),
  1592. Handle = CreateFile(FileName.c_str(), Access,
  1593. Access == GENERIC_READ ? FILE_SHARE_READ | FILE_SHARE_WRITE : FILE_SHARE_READ,
  1594. NULL, OPEN_EXISTING, 0, 0);
  1595. if (Handle == INVALID_HANDLE_VALUE)
  1596. {
  1597. Handle = 0;
  1598. EXCEPTION;
  1599. }
  1600. );
  1601. try
  1602. {
  1603. if (AATime || AMTime || ACTime)
  1604. {
  1605. // Get last file access and modification time
  1606. FILE_OPERATION_LOOP (FMTLOAD(CANT_GET_ATTRS, (FileName)),
  1607. FILETIME ATime;
  1608. FILETIME MTime;
  1609. FILETIME CTime;
  1610. if (!GetFileTime(Handle, &CTime, &ATime, &MTime)) EXCEPTION;
  1611. if (ACTime)
  1612. {
  1613. *ACTime = ConvertTimestampToUnix(CTime, SessionData->ConsiderDST);
  1614. }
  1615. if (AATime)
  1616. {
  1617. *AATime = ConvertTimestampToUnix(ATime, SessionData->ConsiderDST);
  1618. }
  1619. if (AMTime)
  1620. {
  1621. *AMTime = ConvertTimestampToUnix(MTime, SessionData->ConsiderDST);
  1622. }
  1623. );
  1624. }
  1625. if (ASize)
  1626. {
  1627. // Get file size
  1628. FILE_OPERATION_LOOP (FMTLOAD(CANT_GET_ATTRS, (FileName)),
  1629. unsigned long LSize;
  1630. unsigned long HSize;
  1631. LSize = GetFileSize(Handle, &HSize);
  1632. if ((LSize == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) EXCEPTION;
  1633. *ASize = (__int64(HSize) << 32) + LSize;
  1634. );
  1635. }
  1636. if ((AHandle == NULL) || NoHandle)
  1637. {
  1638. CloseHandle(Handle);
  1639. Handle = NULL;
  1640. }
  1641. }
  1642. catch(...)
  1643. {
  1644. CloseHandle(Handle);
  1645. throw;
  1646. }
  1647. }
  1648. if (AAttrs) *AAttrs = Attrs;
  1649. if (AHandle) *AHandle = Handle;
  1650. }
  1651. //---------------------------------------------------------------------------
  1652. void __fastcall TTerminal::CalculateLocalFileSize(const AnsiString FileName,
  1653. const TSearchRec Rec, /*TCalculateSizeParams*/ void * Params)
  1654. {
  1655. TCalculateSizeParams * AParams = static_cast<TCalculateSizeParams*>(Params);
  1656. if ((AParams->CopyParam == NULL) ||
  1657. AParams->CopyParam->AllowTransfer(ExtractFileName(FileName)))
  1658. {
  1659. if (FLAGCLEAR(Rec.Attr, faDirectory))
  1660. {
  1661. AParams->Size +=
  1662. (static_cast<__int64>(Rec.FindData.nFileSizeHigh) << 32) +
  1663. Rec.FindData.nFileSizeLow;
  1664. }
  1665. else
  1666. {
  1667. ProcessLocalDirectory(FileName, CalculateLocalFileSize, Params);
  1668. }
  1669. }
  1670. if (OperationProgress && OperationProgress->Operation == foCalculateSize)
  1671. {
  1672. if (OperationProgress->Cancel != csContinue) Abort();
  1673. OperationProgress->SetFile(FileName);
  1674. }
  1675. }
  1676. //---------------------------------------------------------------------------
  1677. void __fastcall TTerminal::CalculateLocalFilesSize(TStrings * FileList,
  1678. __int64 & Size, const TCopyParamType * CopyParam)
  1679. {
  1680. TFileOperationProgressType OperationProgress(FOnProgress, FOnFinished);
  1681. OperationProgress.Start(foCalculateSize, osLocal, FileList->Count);
  1682. try
  1683. {
  1684. TCalculateSizeParams Params;
  1685. Params.Size = 0;
  1686. Params.Params = 0;
  1687. Params.CopyParam = CopyParam;
  1688. assert(!FOperationProgress);
  1689. FOperationProgress = &OperationProgress;
  1690. TSearchRec Rec;
  1691. for (int Index = 0; Index < FileList->Count; Index++)
  1692. {
  1693. if (FileSearchRec(FileList->Strings[Index], Rec))
  1694. {
  1695. if (Rec.Attr & faDirectory)
  1696. {
  1697. ProcessLocalDirectory(FileList->Strings[Index],
  1698. CalculateLocalFileSize, &Params);
  1699. }
  1700. CalculateLocalFileSize(FileList->Strings[Index], Rec, &Params);
  1701. }
  1702. }
  1703. Size = Params.Size;
  1704. }
  1705. __finally
  1706. {
  1707. FOperationProgress = NULL;
  1708. OperationProgress.Stop();
  1709. }
  1710. }
  1711. //---------------------------------------------------------------------------
  1712. struct TSynchronizeFileData
  1713. {
  1714. int Time;
  1715. int Attr;
  1716. unsigned long SizeHigh;
  1717. unsigned long SizeLow;
  1718. FILETIME LastWriteTime;
  1719. bool Modified;
  1720. bool New;
  1721. };
  1722. //---------------------------------------------------------------------------
  1723. struct TSynchronizeData
  1724. {
  1725. AnsiString LocalDirectory;
  1726. AnsiString RemoteDirectory;
  1727. TTerminal::TSynchronizeMode Mode;
  1728. int Params;
  1729. TSynchronizeDirectory OnSynchronizeDirectory;
  1730. TStringList * LocalFileList;
  1731. TStringList * ModifiedRemoteFileList;
  1732. TStringList * NewRemoteFileList;
  1733. const TCopyParamType * CopyParam;
  1734. };
  1735. //---------------------------------------------------------------------------
  1736. void __fastcall TTerminal::Synchronize(const AnsiString LocalDirectory,
  1737. const AnsiString RemoteDirectory, TSynchronizeMode Mode,
  1738. const TCopyParamType * CopyParam, int Params,
  1739. TSynchronizeDirectory OnSynchronizeDirectory)
  1740. {
  1741. assert(CopyParam != NULL);
  1742. TCopyParamType SyncCopyParam = *CopyParam;
  1743. SyncCopyParam.PreserveTime = true;
  1744. BeginTransaction();
  1745. try
  1746. {
  1747. DoSynchronizeDirectory(LocalDirectory, RemoteDirectory, Mode,
  1748. &SyncCopyParam, Params, OnSynchronizeDirectory);
  1749. }
  1750. __finally
  1751. {
  1752. EndTransaction();
  1753. }
  1754. }
  1755. //---------------------------------------------------------------------------
  1756. void __fastcall TTerminal::DoSynchronizeProgress(const TSynchronizeData & Data)
  1757. {
  1758. bool Continue = true;
  1759. Data.OnSynchronizeDirectory(Data.LocalDirectory, Data.RemoteDirectory, Continue);
  1760. if (!Continue)
  1761. {
  1762. Abort();
  1763. }
  1764. }
  1765. //---------------------------------------------------------------------------
  1766. void __fastcall TTerminal::DoSynchronizeDirectory(const AnsiString LocalDirectory,
  1767. const AnsiString RemoteDirectory, TSynchronizeMode Mode,
  1768. const TCopyParamType * CopyParam, int Params,
  1769. TSynchronizeDirectory OnSynchronizeDirectory)
  1770. {
  1771. TSearchRec SearchRec;
  1772. bool Found;
  1773. bool Delete = (Params & spDelete) != 0;
  1774. TSynchronizeData Data;
  1775. Data.LocalDirectory = IncludeTrailingBackslash(LocalDirectory);
  1776. Data.RemoteDirectory = UnixIncludeTrailingBackslash(RemoteDirectory);
  1777. Data.Mode = Mode;
  1778. Data.Params = Params;
  1779. Data.OnSynchronizeDirectory = OnSynchronizeDirectory;
  1780. Data.LocalFileList = NULL;
  1781. Data.NewRemoteFileList = NULL;
  1782. Data.ModifiedRemoteFileList = NULL;
  1783. Data.CopyParam = CopyParam;
  1784. TStrings * LocalFileList = NULL;
  1785. LogEvent(FORMAT("Synchronizing local directory '%s' with remote directory '%s', "
  1786. "mode = %d, params = %d", (LocalDirectory, RemoteDirectory,
  1787. int(Mode), int(Params))));
  1788. if (FLAGCLEAR(Params, spDelayProgress))
  1789. {
  1790. DoSynchronizeProgress(Data);
  1791. }
  1792. try
  1793. {
  1794. Data.LocalFileList = new TStringList();
  1795. Data.LocalFileList->Sorted = true;
  1796. Data.LocalFileList->CaseSensitive = false;
  1797. Data.NewRemoteFileList = new TStringList();
  1798. Data.ModifiedRemoteFileList = new TStringList();
  1799. LocalFileList = new TStringList();
  1800. FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (LocalDirectory)),
  1801. int FindAttrs = faReadOnly | faHidden | faSysFile | faDirectory | faArchive;
  1802. Found = (FindFirst(Data.LocalDirectory + "*.*", FindAttrs, SearchRec) == 0);
  1803. );
  1804. if (Found)
  1805. {
  1806. try
  1807. {
  1808. AnsiString FileName;
  1809. while (Found)
  1810. {
  1811. FileName = SearchRec.Name;
  1812. if ((FileName != ".") && (FileName != "..") &&
  1813. (FLAGCLEAR(SearchRec.Attr, faDirectory) ||
  1814. FLAGCLEAR(Params, spNoRecurse)) &&
  1815. CopyParam->AllowTransfer(FileName))
  1816. {
  1817. TSynchronizeFileData * FileData = new TSynchronizeFileData;
  1818. FileData->Time = SearchRec.Time;
  1819. FileData->SizeHigh = SearchRec.FindData.nFileSizeHigh;
  1820. FileData->SizeLow = SearchRec.FindData.nFileSizeLow;
  1821. FileData->Attr = SearchRec.Attr;
  1822. FileData->LastWriteTime = SearchRec.FindData.ftLastWriteTime;
  1823. FileData->New = true;
  1824. FileData->Modified = false;
  1825. Data.LocalFileList->AddObject(FileName,
  1826. reinterpret_cast<TObject*>(FileData));
  1827. }
  1828. FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (LocalDirectory)),
  1829. Found = (FindNext(SearchRec) == 0);
  1830. );
  1831. }
  1832. }
  1833. __finally
  1834. {
  1835. FindClose(SearchRec);
  1836. }
  1837. // can we expect that ProcessDirectory would take so little time
  1838. // that we can pospone showing progress window until anything actually happens?
  1839. bool Cached = FLAGSET(Params, spUseCache) && SessionData->CacheDirectories &&
  1840. FDirectoryCache->HasFileList(RemoteDirectory);
  1841. if (!Cached && FLAGSET(Params, spDelayProgress))
  1842. {
  1843. DoSynchronizeProgress(Data);
  1844. }
  1845. ProcessDirectory(RemoteDirectory, SynchronizeFile, &Data,
  1846. FLAGSET(Params, spUseCache));
  1847. TSynchronizeFileData * FileData;
  1848. for (int Index = 0; Index < Data.LocalFileList->Count; Index++)
  1849. {
  1850. FileData = reinterpret_cast<TSynchronizeFileData *>
  1851. (Data.LocalFileList->Objects[Index]);
  1852. // add local file either if we are going to upload it
  1853. // (i.e. if it is updated or we want to upload even new files)
  1854. // or if we are going to delete it (i.e. all "new"=obsolete files)
  1855. if ((FileData->Modified && ((Mode == smBoth) || (Mode == smRemote))) ||
  1856. (FileData->New && ((Mode == smLocal) || FLAGCLEAR(Params, spExistingOnly))))
  1857. {
  1858. LocalFileList->Add(Data.LocalDirectory + Data.LocalFileList->Strings[Index]);
  1859. }
  1860. }
  1861. if (((Mode == smBoth) || (Mode == smLocal)) &&
  1862. FLAGCLEAR(Params, spExistingOnly))
  1863. {
  1864. Data.ModifiedRemoteFileList->AddStrings(Data.NewRemoteFileList);
  1865. }
  1866. int CopyParams = (Params & spNoConfirmation) != 0 ? cpNoConfirmation : 0;
  1867. bool Upload = (LocalFileList->Count > 0) &&
  1868. ((Mode == smBoth) || (Mode == smRemote));
  1869. bool DeleteLocal = (LocalFileList->Count > 0) &&
  1870. (Mode == smLocal) && Delete;
  1871. bool Download = (Data.ModifiedRemoteFileList->Count > 0) &&
  1872. ((Mode == smBoth) || (Mode == smLocal));
  1873. bool DeleteRemote = (Data.NewRemoteFileList->Count > 0) &&
  1874. (Mode == smRemote) && Delete;
  1875. if (Upload || DeleteLocal || Download || DeleteRemote)
  1876. {
  1877. if (Cached && FLAGSET(Params, spDelayProgress))
  1878. {
  1879. DoSynchronizeProgress(Data);
  1880. }
  1881. if (Upload &&
  1882. !CopyToRemote(LocalFileList, RemoteDirectory, CopyParam, CopyParams))
  1883. {
  1884. Abort();
  1885. }
  1886. if (DeleteLocal && !DeleteLocalFiles(LocalFileList))
  1887. {
  1888. Abort();
  1889. }
  1890. if (Download &&
  1891. !CopyToLocal(Data.ModifiedRemoteFileList, LocalDirectory, CopyParam, CopyParams))
  1892. {
  1893. Abort();
  1894. }
  1895. if (DeleteRemote && !DeleteFiles(Data.NewRemoteFileList))
  1896. {
  1897. Abort();
  1898. }
  1899. }
  1900. }
  1901. }
  1902. __finally
  1903. {
  1904. if (Data.LocalFileList != NULL)
  1905. {
  1906. for (int Index = 0; Index < Data.LocalFileList->Count; Index++)
  1907. {
  1908. delete reinterpret_cast<TSynchronizeFileData*>
  1909. (Data.LocalFileList->Objects[Index]);
  1910. }
  1911. delete Data.LocalFileList;
  1912. }
  1913. TStringList * FileList = Data.NewRemoteFileList;
  1914. while (FileList != Data.ModifiedRemoteFileList)
  1915. {
  1916. if (FileList != NULL)
  1917. {
  1918. for (int Index = 0; Index < FileList->Count; Index++)
  1919. {
  1920. delete static_cast<TRemoteFile*>(FileList->Objects[Index]);
  1921. }
  1922. delete FileList;
  1923. }
  1924. FileList = Data.ModifiedRemoteFileList;
  1925. }
  1926. delete LocalFileList;
  1927. }
  1928. }
  1929. //---------------------------------------------------------------------------
  1930. void __fastcall TTerminal::SynchronizeFile(const AnsiString FileName,
  1931. const TRemoteFile * File, /*TSynchronizeData*/ void * Param)
  1932. {
  1933. TSynchronizeData * Data = static_cast<TSynchronizeData *>(Param);
  1934. if (Data->CopyParam->AllowTransfer(File->FileName))
  1935. {
  1936. bool Modified = false;
  1937. int Index = Data->LocalFileList->IndexOf(File->FileName);
  1938. bool New = (Index < 0);
  1939. if (!New)
  1940. {
  1941. TSynchronizeFileData * LocalData =
  1942. reinterpret_cast<TSynchronizeFileData *>(Data->LocalFileList->Objects[Index]);
  1943. LocalData->New = false;
  1944. bool LocalDirectory = (LocalData->Attr & faDirectory) != 0;
  1945. if (File->IsDirectory != LocalDirectory)
  1946. {
  1947. LogEvent(FORMAT("%s is directory on one side, but file on the another",
  1948. (File->FileName)));
  1949. }
  1950. else if (!File->IsDirectory)
  1951. {
  1952. FILETIME LocalLastWriteTime;
  1953. SYSTEMTIME SystemLastWriteTime;
  1954. FileTimeToLocalFileTime(&LocalData->LastWriteTime, &LocalLastWriteTime);
  1955. FileTimeToSystemTime(&LocalLastWriteTime, &SystemLastWriteTime);
  1956. TDateTime LocalTime = SystemTimeToDateTime(SystemLastWriteTime);
  1957. TDateTime RemoteTime = File->Modification;
  1958. UnifyDateTimePrecision(LocalTime, RemoteTime);
  1959. if (LocalTime < RemoteTime)
  1960. {
  1961. Modified = true;
  1962. }
  1963. else if (LocalTime > RemoteTime)
  1964. {
  1965. LocalData->Modified = true;
  1966. }
  1967. }
  1968. else if (FLAGCLEAR(Data->Params, spNoRecurse))
  1969. {
  1970. DoSynchronizeDirectory(
  1971. Data->LocalDirectory + File->FileName,
  1972. Data->RemoteDirectory + File->FileName,
  1973. Data->Mode, Data->CopyParam, Data->Params, Data->OnSynchronizeDirectory);
  1974. }
  1975. }
  1976. else
  1977. {
  1978. New = !File->IsDirectory || FLAGCLEAR(Data->Params, spNoRecurse);
  1979. }
  1980. if (New || Modified)
  1981. {
  1982. assert(!New || !Modified);
  1983. TStringList * FileList = New ? Data->NewRemoteFileList :
  1984. Data->ModifiedRemoteFileList;
  1985. FileList->AddObject(FileName,
  1986. const_cast<TRemoteFile *>(File)->Duplicate());
  1987. }
  1988. }
  1989. }
  1990. //---------------------------------------------------------------------------
  1991. bool __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
  1992. const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params)
  1993. {
  1994. assert(FFileSystem);
  1995. assert(FilesToCopy);
  1996. assert(IsCapable[fcNewerOnlyUpload] || FLAGCLEAR(Params, cpNewerOnly));
  1997. bool Result = false;
  1998. bool DisconnectWhenComplete = false;
  1999. try
  2000. {
  2001. __int64 Size;
  2002. if (CopyParam->CalculateSize)
  2003. {
  2004. // dirty trick: when moving, do not pass copy param to avoid exclude mask
  2005. CalculateLocalFilesSize(FilesToCopy, Size,
  2006. (FLAGCLEAR(Params, cpDelete) ? CopyParam : NULL));
  2007. }
  2008. TFileOperationProgressType OperationProgress(FOnProgress, FOnFinished);
  2009. OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osLocal,
  2010. FilesToCopy->Count, Params & cpDragDrop, TargetDir);
  2011. OperationProgress.YesToNewer = FLAGSET(Params, cpNewerOnly);
  2012. FOperationProgress = &OperationProgress;
  2013. try
  2014. {
  2015. if (CopyParam->CalculateSize)
  2016. {
  2017. OperationProgress.SetTotalSize(Size);
  2018. }
  2019. AnsiString UnlockedTargetDir = TranslateLockedPath(TargetDir, false);
  2020. BeginTransaction();
  2021. try
  2022. {
  2023. if (IsLogging())
  2024. {
  2025. LogEvent(FORMAT("Copying %d files/directories to remote directory "
  2026. "\"%s\"", (FilesToCopy->Count, TargetDir)));
  2027. LogEvent(CopyParam->LogStr);
  2028. }
  2029. FFileSystem->CopyToRemote(FilesToCopy, UnlockedTargetDir,
  2030. CopyParam, Params, &OperationProgress, DisconnectWhenComplete);
  2031. }
  2032. __finally
  2033. {
  2034. if (Active)
  2035. {
  2036. ReactOnCommand(fsCopyToRemote);
  2037. EndTransaction();
  2038. }
  2039. }
  2040. if (OperationProgress.Cancel == csContinue)
  2041. {
  2042. Result = true;
  2043. }
  2044. }
  2045. __finally
  2046. {
  2047. OperationProgress.Stop();
  2048. FOperationProgress = NULL;
  2049. }
  2050. }
  2051. catch (Exception &E)
  2052. {
  2053. CommandError(&E, LoadStr(TOREMOTE_COPY_ERROR));
  2054. DisconnectWhenComplete = false;
  2055. }
  2056. if (DisconnectWhenComplete) CloseOnCompletion();
  2057. return Result;
  2058. }
  2059. //---------------------------------------------------------------------------
  2060. bool __fastcall TTerminal::CopyToLocal(TStrings * FilesToCopy,
  2061. const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params)
  2062. {
  2063. assert(FFileSystem);
  2064. // see scp.c: sink(), tolocal()
  2065. bool Result = false;
  2066. bool OwnsFileList = (FilesToCopy == NULL);
  2067. bool DisconnectWhenComplete = false;
  2068. try
  2069. {
  2070. if (OwnsFileList)
  2071. {
  2072. FilesToCopy = new TStringList();
  2073. FilesToCopy->Assign(Files->SelectedFiles);
  2074. }
  2075. BeginTransaction();
  2076. try
  2077. {
  2078. __int64 TotalSize;
  2079. bool TotalSizeKnown = false;
  2080. TFileOperationProgressType OperationProgress(FOnProgress, FOnFinished);
  2081. if (CopyParam->CalculateSize)
  2082. {
  2083. ExceptionOnFail = true;
  2084. try
  2085. {
  2086. // dirty trick: when moving, do not pass copy param to avoid exclude mask
  2087. CalculateFilesSize(FilesToCopy, TotalSize, csIgnoreErrors,
  2088. (FLAGCLEAR(Params, cpDelete) ? CopyParam : NULL));
  2089. TotalSizeKnown = true;
  2090. }
  2091. __finally
  2092. {
  2093. ExceptionOnFail = false;
  2094. }
  2095. }
  2096. OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osRemote,
  2097. FilesToCopy->Count, Params & cpDragDrop, TargetDir);
  2098. OperationProgress.YesToNewer = FLAGSET(Params, cpNewerOnly);
  2099. FOperationProgress = &OperationProgress;
  2100. try
  2101. {
  2102. if (TotalSizeKnown)
  2103. {
  2104. OperationProgress.SetTotalSize(TotalSize);
  2105. }
  2106. try
  2107. {
  2108. try
  2109. {
  2110. FFileSystem->CopyToLocal(FilesToCopy, TargetDir, CopyParam, Params,
  2111. &OperationProgress, DisconnectWhenComplete);
  2112. }
  2113. __finally
  2114. {
  2115. if (Active)
  2116. {
  2117. ReactOnCommand(fsCopyToLocal);
  2118. }
  2119. }
  2120. }
  2121. catch (Exception &E)
  2122. {
  2123. CommandError(&E, LoadStr(TOLOCAL_COPY_ERROR));
  2124. DisconnectWhenComplete = false;
  2125. }
  2126. if (OperationProgress.Cancel == csContinue)
  2127. {
  2128. Result = true;
  2129. }
  2130. }
  2131. __finally
  2132. {
  2133. FOperationProgress = NULL;
  2134. OperationProgress.Stop();
  2135. }
  2136. }
  2137. __finally
  2138. {
  2139. // If session is still active (no fatal error) we reload directory
  2140. // by calling EndTransaction
  2141. EndTransaction();
  2142. }
  2143. }
  2144. __finally
  2145. {
  2146. if (OwnsFileList) delete FilesToCopy;
  2147. }
  2148. if (DisconnectWhenComplete) CloseOnCompletion();
  2149. return Result;
  2150. }
  2151. //---------------------------------------------------------------------------
  2152. __fastcall TTerminalList::TTerminalList(TConfiguration * AConfiguration) :
  2153. TObjectList()
  2154. {
  2155. assert(AConfiguration);
  2156. FConfiguration = AConfiguration;
  2157. }
  2158. //---------------------------------------------------------------------------
  2159. __fastcall TTerminalList::~TTerminalList()
  2160. {
  2161. assert(Count == 0);
  2162. }
  2163. //---------------------------------------------------------------------------
  2164. TTerminal * __fastcall TTerminalList::NewTerminal(TSessionData * Data)
  2165. {
  2166. TTerminal * Terminal = new TTerminal();
  2167. try
  2168. {
  2169. Terminal->Configuration = FConfiguration;
  2170. Terminal->SessionData = Data;
  2171. Add(Terminal);
  2172. }
  2173. catch(...)
  2174. {
  2175. delete Terminal;
  2176. throw;
  2177. }
  2178. return Terminal;
  2179. }
  2180. //---------------------------------------------------------------------------
  2181. void __fastcall TTerminalList::FreeTerminal(TTerminal * Terminal)
  2182. {
  2183. assert(IndexOf(Terminal) >= 0);
  2184. Remove(Terminal);
  2185. }
  2186. //---------------------------------------------------------------------------
  2187. void __fastcall TTerminalList::FreeAndNullTerminal(TTerminal * & Terminal)
  2188. {
  2189. TTerminal * T = Terminal;
  2190. Terminal = NULL;
  2191. FreeTerminal(T);
  2192. }
  2193. //---------------------------------------------------------------------------
  2194. TTerminal * __fastcall TTerminalList::GetTerminal(int Index)
  2195. {
  2196. return dynamic_cast<TTerminal *>(Items[Index]);
  2197. }
  2198. //---------------------------------------------------------------------------
  2199. void __fastcall TTerminalList::Idle()
  2200. {
  2201. TTerminal * Terminal;
  2202. for (int i = 0; i < Count; i++)
  2203. {
  2204. Terminal = Terminals[i];
  2205. if (Terminal->Status == sshReady)
  2206. {
  2207. Terminal->Idle();
  2208. }
  2209. }
  2210. }