RemoteFiles.cpp 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "RemoteFiles.h"
  5. #include <SysUtils.hpp>
  6. #include "Common.h"
  7. #include "Exceptions.h"
  8. #include "Interface.h"
  9. #include "Terminal.h"
  10. #include "TextsCore.h"
  11. /* TODO 1 : Path class instead of AnsiString (handle relativity...) */
  12. //---------------------------------------------------------------------------
  13. AnsiString __fastcall UnixIncludeTrailingBackslash(const AnsiString Path)
  14. {
  15. // it used to return "/" when input path was empty
  16. if (!Path.IsEmpty() && !Path.IsDelimiter("/", Path.Length()))
  17. {
  18. return Path + "/";
  19. }
  20. else
  21. {
  22. return Path;
  23. }
  24. }
  25. //---------------------------------------------------------------------------
  26. // Keeps "/" for root path
  27. AnsiString __fastcall UnixExcludeTrailingBackslash(const AnsiString Path)
  28. {
  29. if ((Path.Length() > 1) && Path.IsDelimiter("/", Path.Length()))
  30. return Path.SubString(1, Path.Length() - 1);
  31. else return Path;
  32. }
  33. //---------------------------------------------------------------------------
  34. Boolean __fastcall ComparePaths(const AnsiString Path1, const AnsiString Path2)
  35. {
  36. return AnsiSameText(IncludeTrailingBackslash(Path1), IncludeTrailingBackslash(Path2));
  37. }
  38. //---------------------------------------------------------------------------
  39. Boolean __fastcall UnixComparePaths(const AnsiString Path1, const AnsiString Path2)
  40. {
  41. return (UnixIncludeTrailingBackslash(Path1) == UnixIncludeTrailingBackslash(Path2));
  42. }
  43. //---------------------------------------------------------------------------
  44. AnsiString __fastcall UnixExtractFileDir(const AnsiString Path)
  45. {
  46. int Pos = Path.LastDelimiter('/');
  47. // it used to return Path when no slash was found
  48. if (Pos > 1)
  49. {
  50. return Path.SubString(1, Pos - 1);
  51. }
  52. else
  53. {
  54. return (Pos == 1) ? AnsiString("/") : AnsiString();
  55. }
  56. }
  57. //---------------------------------------------------------------------------
  58. // must return trailing backslash
  59. AnsiString __fastcall UnixExtractFilePath(const AnsiString Path)
  60. {
  61. int Pos = Path.LastDelimiter('/');
  62. // it used to return Path when no slash was found
  63. return (Pos > 0) ? Path.SubString(1, Pos) : AnsiString();
  64. }
  65. //---------------------------------------------------------------------------
  66. AnsiString __fastcall UnixExtractFileName(const AnsiString Path)
  67. {
  68. int Pos = Path.LastDelimiter('/');
  69. return (Pos > 0) ? Path.SubString(Pos + 1, Path.Length() - Pos) : Path;
  70. }
  71. //---------------------------------------------------------------------------
  72. AnsiString __fastcall UnixExtractFileExt(const AnsiString Path)
  73. {
  74. AnsiString FileName = UnixExtractFileName(Path);
  75. int Pos = FileName.LastDelimiter(".");
  76. return (Pos > 0) ? Path.SubString(Pos, Path.Length() - Pos + 1) : AnsiString();
  77. }
  78. //---------------------------------------------------------------------------
  79. bool __fastcall ExtractCommonPath(TStrings * Files, AnsiString & Path)
  80. {
  81. assert(Files->Count > 0);
  82. Path = ExtractFilePath(Files->Strings[0]);
  83. bool Result = !Path.IsEmpty();
  84. if (Result)
  85. {
  86. for (int Index = 1; Index < Files->Count; Index++)
  87. {
  88. while (Path.IsEmpty() &&
  89. (Files->Strings[Index].SubString(1, Path.Length()) != Path))
  90. {
  91. int PrevLen = Path.Length();
  92. Path = ExtractFilePath(ExcludeTrailingBackslash(Path));
  93. if (Path.Length() == PrevLen)
  94. {
  95. Path = "";
  96. }
  97. }
  98. }
  99. }
  100. return Result;
  101. }
  102. //---------------------------------------------------------------------------
  103. bool __fastcall UnixExtractCommonPath(TStrings * Files, AnsiString & Path)
  104. {
  105. assert(Files->Count > 0);
  106. Path = UnixExtractFilePath(Files->Strings[0]);
  107. bool Result = !Path.IsEmpty();
  108. if (Result)
  109. {
  110. for (int Index = 1; Index < Files->Count; Index++)
  111. {
  112. while (Path.IsEmpty() &&
  113. (Files->Strings[Index].SubString(1, Path.Length()) != Path))
  114. {
  115. int PrevLen = Path.Length();
  116. Path = UnixExtractFilePath(UnixExcludeTrailingBackslash(Path));
  117. if (Path.Length() == PrevLen)
  118. {
  119. Path = "";
  120. }
  121. }
  122. }
  123. }
  124. return Result;
  125. }
  126. //---------------------------------------------------------------------------
  127. bool __fastcall IsUnixRootPath(const AnsiString Path)
  128. {
  129. return Path.IsEmpty() || (Path == ROOTDIRECTORY);
  130. }
  131. //---------------------------------------------------------------------------
  132. bool __fastcall IsUnixHiddenFile(const AnsiString FileName)
  133. {
  134. return (FileName != ROOTDIRECTORY) && (FileName != PARENTDIRECTORY) &&
  135. !FileName.IsEmpty() && (FileName[1] == '.');
  136. }
  137. //---------------------------------------------------------------------------
  138. AnsiString __fastcall FromUnixPath(const AnsiString Path)
  139. {
  140. return StringReplace(Path, "/", "\\", TReplaceFlags() << rfReplaceAll);
  141. }
  142. //---------------------------------------------------------------------------
  143. AnsiString __fastcall ToUnixPath(const AnsiString Path)
  144. {
  145. return StringReplace(Path, "\\", "/", TReplaceFlags() << rfReplaceAll);
  146. }
  147. //---------------------------------------------------------------------------
  148. static void __fastcall CutFirstDirectory(AnsiString & S, bool Unix)
  149. {
  150. bool Root;
  151. int P;
  152. AnsiString Sep = Unix ? "/" : "\\";
  153. if (S == Sep)
  154. {
  155. S = "";
  156. }
  157. else
  158. {
  159. if (S[1] == Sep[1])
  160. {
  161. Root = true;
  162. S.Delete(1, 1);
  163. }
  164. else
  165. {
  166. Root = false;
  167. }
  168. if (S[1] == '.')
  169. {
  170. S.Delete(1, 4);
  171. }
  172. P = S.AnsiPos(Sep[1]);
  173. if (P)
  174. {
  175. S.Delete(1, P);
  176. S = "..." + Sep + S;
  177. }
  178. else
  179. {
  180. S = "";
  181. }
  182. if (Root)
  183. {
  184. S = Sep + S;
  185. }
  186. }
  187. }
  188. //---------------------------------------------------------------------------
  189. AnsiString __fastcall MinimizeName(const AnsiString FileName, int MaxLen, bool Unix)
  190. {
  191. AnsiString Drive, Dir, Name, Result;
  192. AnsiString Sep = Unix ? "/" : "\\";
  193. Result = FileName;
  194. if (Unix)
  195. {
  196. int P = Result.LastDelimiter("/");
  197. if (P)
  198. {
  199. Dir = Result.SubString(1, P);
  200. Name = Result.SubString(P + 1, Result.Length() - P);
  201. }
  202. else
  203. {
  204. Dir = "";
  205. Name = Result;
  206. }
  207. }
  208. else
  209. {
  210. Dir = ExtractFilePath(Result);
  211. Name = ExtractFileName(Result);
  212. if (Dir.Length() >= 2 && Dir[2] == ':')
  213. {
  214. Drive = Dir.SubString(1, 2);
  215. Dir.Delete(1, 2);
  216. }
  217. }
  218. while ((!Dir.IsEmpty() || !Drive.IsEmpty()) && (Result.Length() > MaxLen))
  219. {
  220. if (Dir == Sep + "..." + Sep)
  221. {
  222. Dir = "..." + Sep;
  223. }
  224. else if (Dir == "")
  225. {
  226. Drive = "";
  227. }
  228. else
  229. {
  230. CutFirstDirectory(Dir, Unix);
  231. }
  232. Result = Drive + Dir + Name;
  233. }
  234. if (Result.Length() > MaxLen)
  235. {
  236. Result = Result.SubString(1, MaxLen);
  237. }
  238. return Result;
  239. }
  240. //---------------------------------------------------------------------------
  241. AnsiString __fastcall MakeFileList(TStrings * FileList)
  242. {
  243. AnsiString Result;
  244. for (int Index = 0; Index < FileList->Count; Index++)
  245. {
  246. if (!Result.IsEmpty())
  247. {
  248. Result += " ";
  249. }
  250. AnsiString FileName = FileList->Strings[Index];
  251. // currently this is used for local file only, so no delimiting is done
  252. if (FileName.Pos(" ") > 0)
  253. {
  254. Result += "\"" + FileName + "\"";
  255. }
  256. else
  257. {
  258. Result += FileName;
  259. }
  260. }
  261. return Result;
  262. }
  263. //---------------------------------------------------------------------------
  264. // copy from BaseUtils.pas
  265. void __fastcall ReduceDateTimePrecision(TDateTime & DateTime,
  266. TModificationFmt Precision)
  267. {
  268. if (Precision != mfFull)
  269. {
  270. unsigned short Y, M, D, H, N, S, MS;
  271. DecodeDate(DateTime, Y, M, D);
  272. DecodeTime(DateTime, H, N, S, MS);
  273. switch (Precision)
  274. {
  275. case mfMDHM:
  276. S = 0;
  277. MS = 0;
  278. break;
  279. case mfMDY:
  280. H = 0;
  281. N = 0;
  282. S = 0;
  283. MS = 0;
  284. default:
  285. assert(false);
  286. }
  287. DateTime = EncodeDate(Y, M, D) + EncodeTime(H, N, S, MS);
  288. }
  289. }
  290. //- TRemoteFiles ------------------------------------------------------------
  291. __fastcall TRemoteFile::TRemoteFile(TRemoteFile * ALinkedByFile):
  292. TPersistent()
  293. {
  294. FLinkedFile = NULL;
  295. FRights = new TRights();
  296. FIconIndex = -1;
  297. FCyclicLink = false;
  298. FModificationFmt = mfFull;
  299. FLinkedByFile = ALinkedByFile;
  300. FTerminal = NULL;
  301. FDirectory = NULL;
  302. FIsHidden = -1;
  303. }
  304. //---------------------------------------------------------------------------
  305. __fastcall TRemoteFile::~TRemoteFile()
  306. {
  307. delete FRights;
  308. delete FLinkedFile;
  309. }
  310. //---------------------------------------------------------------------------
  311. TRemoteFile * __fastcall TRemoteFile::Duplicate(bool Standalone)
  312. {
  313. TRemoteFile * Result;
  314. Result = new TRemoteFile();
  315. try
  316. {
  317. if (FLinkedFile)
  318. {
  319. Result->FLinkedFile = FLinkedFile->Duplicate(true);
  320. Result->FLinkedFile->FLinkedByFile = Result;
  321. }
  322. *Result->Rights = *FRights;
  323. #define COPY_FP(PROP) Result->F ## PROP = F ## PROP;
  324. COPY_FP(Terminal);
  325. COPY_FP(Owner);
  326. COPY_FP(ModificationFmt);
  327. COPY_FP(Size);
  328. COPY_FP(FileName);
  329. COPY_FP(INodeBlocks);
  330. COPY_FP(Modification);
  331. COPY_FP(LastAccess);
  332. COPY_FP(Group);
  333. COPY_FP(IconIndex);
  334. COPY_FP(TypeName);
  335. COPY_FP(IsSymLink);
  336. COPY_FP(LinkTo);
  337. COPY_FP(Type);
  338. COPY_FP(Selected);
  339. COPY_FP(CyclicLink);
  340. #undef COPY_FP
  341. if (Standalone && (!FFullFileName.IsEmpty() || (Directory != NULL)))
  342. {
  343. Result->FFullFileName = FullFileName;
  344. }
  345. }
  346. catch(...)
  347. {
  348. delete Result;
  349. throw;
  350. }
  351. return Result;
  352. }
  353. //---------------------------------------------------------------------------
  354. void __fastcall TRemoteFile::LoadTypeInfo()
  355. {
  356. /* TODO : If file is link: Should be attributes taken from linked file? */
  357. unsigned long Attrs = FILE_ATTRIBUTE_NORMAL;
  358. if (IsDirectory) Attrs |= FILE_ATTRIBUTE_DIRECTORY;
  359. if (IsHidden) Attrs |= FILE_ATTRIBUTE_HIDDEN;
  360. TSHFileInfo SHFileInfo;
  361. AnsiString DumbFileName = (IsSymLink && !LinkTo.IsEmpty() ? LinkTo : FileName);
  362. // On Win2k we get icon of "ZIP drive" for ".." (parent directory)
  363. if (DumbFileName == "..") DumbFileName = "dumb";
  364. // this should be somewhere else, probably in TUnixDirView,
  365. // as the "partial" overlay is added there too
  366. if (AnsiSameText(UnixExtractFileExt(DumbFileName), PARTIAL_EXT))
  367. {
  368. static const size_t PartialExtLen = sizeof(PARTIAL_EXT) - 1;
  369. DumbFileName.SetLength(DumbFileName.Length() - PartialExtLen);
  370. }
  371. SHGetFileInfo(DumbFileName.c_str(),
  372. Attrs, &SHFileInfo, sizeof(SHFileInfo),
  373. SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME);
  374. FIconIndex = SHFileInfo.iIcon;
  375. FTypeName = SHFileInfo.szTypeName;
  376. }
  377. //---------------------------------------------------------------------------
  378. Integer __fastcall TRemoteFile::GetIconIndex()
  379. {
  380. assert(FIconIndex >= -1);
  381. if (FIconIndex < 0)
  382. {
  383. LoadTypeInfo();
  384. }
  385. return FIconIndex;
  386. }
  387. //---------------------------------------------------------------------------
  388. AnsiString __fastcall TRemoteFile::GetTypeName()
  389. {
  390. // check avilability of type info by icon index, because type name can be empty
  391. if (FIconIndex < 0)
  392. {
  393. LoadTypeInfo();
  394. }
  395. return FTypeName;
  396. }
  397. //---------------------------------------------------------------------------
  398. Boolean __fastcall TRemoteFile::GetIsHidden()
  399. {
  400. bool Result;
  401. switch (FIsHidden)
  402. {
  403. case 0:
  404. Result = false;
  405. break;
  406. case 1:
  407. Result = true;
  408. break;
  409. default:
  410. Result = IsUnixHiddenFile(FileName);
  411. break;
  412. }
  413. return Result;
  414. }
  415. //---------------------------------------------------------------------------
  416. void __fastcall TRemoteFile::SetIsHidden(bool value)
  417. {
  418. FIsHidden = value ? 1 : 0;
  419. }
  420. //---------------------------------------------------------------------------
  421. Boolean __fastcall TRemoteFile::GetIsDirectory() const
  422. {
  423. return (toupper(Type) == FILETYPE_DIRECTORY);
  424. }
  425. //---------------------------------------------------------------------------
  426. Boolean __fastcall TRemoteFile::GetIsParentDirectory() const
  427. {
  428. return (FileName == PARENTDIRECTORY);
  429. }
  430. //---------------------------------------------------------------------------
  431. Boolean __fastcall TRemoteFile::GetIsThisDirectory() const
  432. {
  433. return (FileName == THISDIRECTORY);
  434. }
  435. //---------------------------------------------------------------------------
  436. Boolean __fastcall TRemoteFile::GetIsInaccesibleDirectory() const
  437. {
  438. Boolean Result;
  439. if (IsDirectory)
  440. {
  441. assert(Terminal);
  442. Result = !
  443. (((Rights->RightUndef[TRights::rrOtherExec] != TRights::rsNo)) ||
  444. ((Rights->Right[TRights::rrGroupExec] != TRights::rsNo) &&
  445. (Terminal->Groups->IndexOf(Group) >= 0)) ||
  446. ((Rights->Right[TRights::rrUserExec] != TRights::rsNo) &&
  447. (AnsiCompareText(Terminal->UserName, Owner) == 0)));
  448. }
  449. else Result = False;
  450. return Result;
  451. }
  452. //---------------------------------------------------------------------------
  453. char __fastcall TRemoteFile::GetType() const
  454. {
  455. if (IsSymLink && FLinkedFile) return FLinkedFile->Type;
  456. else return FType;
  457. }
  458. //---------------------------------------------------------------------------
  459. void __fastcall TRemoteFile::SetType(char AType)
  460. {
  461. FType = AType;
  462. // Allow even non-standard file types (e.g. 'S')
  463. // if (!AnsiString("-DL").Pos((Char)toupper(FType))) Abort();
  464. FIsSymLink = ((Char)toupper(FType) == FILETYPE_SYMLINK);
  465. }
  466. //---------------------------------------------------------------------------
  467. TRemoteFile * __fastcall TRemoteFile::GetLinkedFile()
  468. {
  469. // it would be called releatedly for broken symlinks
  470. //if (!FLinkedFile) FindLinkedFile();
  471. return FLinkedFile;
  472. }
  473. //---------------------------------------------------------------------------
  474. void __fastcall TRemoteFile::SetLinkedFile(TRemoteFile * value)
  475. {
  476. if (FLinkedFile != value)
  477. {
  478. if (FLinkedFile) delete FLinkedFile;
  479. FLinkedFile = value;
  480. }
  481. }
  482. //---------------------------------------------------------------------------
  483. bool __fastcall TRemoteFile::GetBrokenLink()
  484. {
  485. assert(Terminal);
  486. // If file is symlink but we couldn't find linked file we assume broken link
  487. return (IsSymLink && (FCyclicLink || !FLinkedFile) &&
  488. Terminal->ResolvingSymlinks);
  489. // "!FLinkTo.IsEmpty()" removed because it does not work with SFTP
  490. }
  491. //---------------------------------------------------------------------------
  492. void __fastcall TRemoteFile::ShiftTime(const TDateTime & Difference)
  493. {
  494. double D = double(Difference);
  495. if ((D != 0) && (FModificationFmt != mfMDY))
  496. {
  497. assert(int(FModification) != 0);
  498. FModification = double(FModification) + D;
  499. assert(int(FLastAccess) != 0);
  500. FLastAccess = double(FLastAccess) + D;
  501. }
  502. }
  503. //---------------------------------------------------------------------------
  504. void __fastcall TRemoteFile::SetModification(const TDateTime & value)
  505. {
  506. if (FModification != value)
  507. {
  508. FModificationFmt = mfFull;
  509. FModification = value;
  510. }
  511. }
  512. //---------------------------------------------------------------------------
  513. AnsiString __fastcall TRemoteFile::GetUserModificationStr()
  514. {
  515. switch (FModificationFmt)
  516. {
  517. case mfMDY:
  518. return FormatDateTime("ddddd", Modification);
  519. case mfMDHM:
  520. return FormatDateTime("ddddd t", Modification);
  521. case mfFull:
  522. default:
  523. return FormatDateTime("ddddd tt", Modification);
  524. }
  525. }
  526. //---------------------------------------------------------------------------
  527. AnsiString __fastcall TRemoteFile::GetModificationStr()
  528. {
  529. Word Year, Month, Day, Hour, Min, Sec, MSec;
  530. Modification.DecodeDate(&Year, &Month, &Day);
  531. Modification.DecodeTime(&Hour, &Min, &Sec, &MSec);
  532. switch (FModificationFmt)
  533. {
  534. case mfMDY:
  535. return FORMAT("%3s %2d %2d", (EngShortMonthNames[Month-1], Day, Year));
  536. case mfMDHM:
  537. return FORMAT("%3s %2d %2d:%2.2d",
  538. (EngShortMonthNames[Month-1], Day, Hour, Min));
  539. default:
  540. assert(false);
  541. // fall thru
  542. case mfFull:
  543. return FORMAT("%3s %2d %2d:%2.2d:%2.2d %4d",
  544. (EngShortMonthNames[Month-1], Day, Hour, Min, Sec, Year));
  545. }
  546. }
  547. //---------------------------------------------------------------------------
  548. AnsiString __fastcall TRemoteFile::GetExtension()
  549. {
  550. return UnixExtractFileExt(FFileName);
  551. }
  552. //---------------------------------------------------------------------------
  553. void __fastcall TRemoteFile::SetRights(TRights * value)
  554. {
  555. FRights->Assign(value);
  556. }
  557. //---------------------------------------------------------------------------
  558. AnsiString __fastcall TRemoteFile::GetRightsStr()
  559. {
  560. return FRights->Text;
  561. }
  562. //---------------------------------------------------------------------------
  563. void __fastcall TRemoteFile::SetListingStr(AnsiString value)
  564. {
  565. // Value stored in 'value' can be used for error message
  566. AnsiString Line = value;
  567. FIconIndex = -1;
  568. try
  569. {
  570. AnsiString Col;
  571. // Do we need to do this (is ever TAB is LS output)?
  572. Line = ReplaceChar(Line, '\t', ' ');
  573. Type = Line[1];
  574. Line.Delete(1, 1);
  575. #define GETNCOL \
  576. { if (Line.IsEmpty()) throw Exception(""); \
  577. Integer P = Line.Pos(' '); \
  578. if (P) { Col = Line.SubString(1, P-1); Line.Delete(1, P); } \
  579. else { Col = Line; Line = ""; } \
  580. }
  581. #define GETCOL { GETNCOL; Line = TrimLeft(Line); }
  582. // Rights string may contain special permission attributes (S,t, ...)
  583. Rights->AllowUndef = True;
  584. // On some system there is no space between permissions and node blocks count columns
  585. // so we get only first 9 characters and trim all following spaces (if any)
  586. Rights->Text = Line.SubString(1, 9);
  587. Line.Delete(1, 9);
  588. // Rights column maybe followed by '+' sign, we ignore it
  589. if (!Line.IsEmpty() && (Line[1] == '+')) Line.Delete(1, 1);
  590. Line = Line.TrimLeft();
  591. GETCOL;
  592. FINodeBlocks = StrToInt(Col);
  593. GETCOL;
  594. FOwner = Col;
  595. // #60 17.10.01: group name can contain space
  596. FGroup = "";
  597. GETCOL;
  598. __int64 ASize;
  599. do
  600. {
  601. FGroup += Col;
  602. GETCOL;
  603. assert(!Col.IsEmpty());
  604. // for devices etc.. there is additional column ending by comma, we ignore it
  605. if (Col[Col.Length()] == ',') GETCOL;
  606. ASize = StrToInt64Def(Col, -1);
  607. // if it's not a number (file size) we take it as part of group name
  608. // (at least on CygWin, there can be group with space in its name)
  609. if (ASize < 0) Col = " " + Col;
  610. }
  611. while (ASize < 0);
  612. // do not read modification time and filename if it is already set
  613. if (double(FModification) == 0 && FileName.IsEmpty())
  614. {
  615. FSize = ASize;
  616. bool FullTime = false;
  617. bool DayMonthFormat = false;
  618. Word Day, Month, Year, Hour, Min, Sec, P;
  619. GETCOL;
  620. // format dd mmm or mmm dd ?
  621. Day = (Word)StrToIntDef(Col, 0);
  622. if (Day > 0)
  623. {
  624. DayMonthFormat = true;
  625. GETCOL;
  626. }
  627. Month = 0;
  628. #define COL2MONTH \
  629. for (Word IMonth = 0; IMonth < 12; IMonth++) \
  630. if (!Col.AnsiCompareIC(EngShortMonthNames[IMonth])) { Month = IMonth; Month++; break; }
  631. COL2MONTH;
  632. // if the column is not known month name, it may have been "yyyy-mm-dd"
  633. // for --full-time format
  634. if ((Month == 0) && (Col.Length() == 10) && (Col[5] == '-') && (Col[8] == '-'))
  635. {
  636. Year = (Word)Col.SubString(1, 4).ToInt();
  637. Month = (Word)Col.SubString(6, 2).ToInt();
  638. Day = (Word)Col.SubString(9, 2).ToInt();
  639. GETCOL;
  640. Hour = (Word)Col.SubString(1, 2).ToInt();
  641. Min = (Word)Col.SubString(4, 2).ToInt();
  642. Sec = (Word)Col.SubString(7, 2).ToInt();
  643. FModificationFmt = mfFull;
  644. // skip TZ (TODO)
  645. // do not trim leading space of filename
  646. GETNCOL;
  647. }
  648. else
  649. {
  650. // or it may have been day name for another format of --full-time
  651. if (Month == 0)
  652. {
  653. GETCOL;
  654. COL2MONTH;
  655. // neither standard, not --full-time format
  656. if (Month == 0)
  657. {
  658. Abort();
  659. }
  660. else
  661. {
  662. FullTime = true;
  663. }
  664. }
  665. #undef COL2MONTH
  666. if (Day == 0)
  667. {
  668. GETNCOL;
  669. Day = (Word)StrToInt(Col);
  670. }
  671. if ((Day < 1) || (Day > 31)) Abort();
  672. // second full-time format
  673. // ddd mmm dd hh:nn:ss yyyy
  674. if (FullTime)
  675. {
  676. GETCOL;
  677. if (Col.Length() != 8)
  678. {
  679. Abort();
  680. }
  681. Hour = (Word)StrToInt(Col.SubString(1, 2));
  682. Min = (Word)StrToInt(Col.SubString(4, 2));
  683. Sec = (Word)StrToInt(Col.SubString(7, 2));
  684. FModificationFmt = mfFull;
  685. // do not trim leading space of filename
  686. GETNCOL;
  687. Year = (Word)StrToInt(Col);
  688. }
  689. else
  690. {
  691. // for format dd mmm the below description seems not to be true,
  692. // the year is not aligned to 5 characters
  693. if (DayMonthFormat)
  694. {
  695. GETCOL;
  696. }
  697. else
  698. {
  699. // Time/Year indicator is always 5 charactes long (???), on most
  700. // systems year is aligned to right (_YYYY), but on some to left (YYYY_),
  701. // we must ensure that trailing space is also deleted, so real
  702. // separator space is not treated as part of file name
  703. Col = Line.SubString(1, 6).Trim();
  704. Line.Delete(1, 6);
  705. }
  706. // GETNCOL; // We don't want to trim input strings (name with space at beginning???)
  707. // Check if we got time (contains :) or year
  708. if ((P = (Word)Col.Pos(':')) > 0)
  709. {
  710. Word CurrMonth, CurrDay;
  711. Hour = (Word)StrToInt(Col.SubString(1, P-1));
  712. Min = (Word)StrToInt(Col.SubString(P+1, Col.Length() - P));
  713. if (Hour > 23 || Hour > 59) Abort();
  714. // When we don't got year, we assume current year
  715. // with exception that the date would be in future
  716. // in this case we assume last year.
  717. DecodeDate(Date(), Year, CurrMonth, CurrDay);
  718. if ((Month > CurrMonth) ||
  719. (Month == CurrMonth && Day > CurrDay)) Year--;
  720. Sec = 0;
  721. FModificationFmt = mfMDHM;
  722. }
  723. else
  724. {
  725. Year = (Word)StrToInt(Col);
  726. if (Year > 10000) Abort();
  727. // When we don't got time we assume midnight
  728. Hour = 0; Min = 0; Sec = 0;
  729. FModificationFmt = mfMDY;
  730. }
  731. }
  732. }
  733. FModification = EncodeDate(Year, Month, Day) + EncodeTime(Hour, Min, Sec, 0);
  734. // adjust only when time is known,
  735. // adjusting default "midnight" time makes no sense
  736. if ((FModificationFmt == mfMDHM) || (FModificationFmt == mfFull))
  737. {
  738. assert(Terminal != NULL);
  739. FModification = AdjustDateTimeFromUnix(FModification,
  740. Terminal->SessionData->ConsiderDST);
  741. }
  742. if (double(FLastAccess) == 0)
  743. {
  744. FLastAccess = FModification;
  745. }
  746. // separating space is already deleted, other spaces are treated as part of name
  747. {
  748. int P;
  749. FLinkTo = "";
  750. if (IsSymLink)
  751. {
  752. P = Line.Pos(SYMLINKSTR);
  753. if (P)
  754. {
  755. FLinkTo = Line.SubString(
  756. P + strlen(SYMLINKSTR), Line.Length() - P + strlen(SYMLINKSTR) + 1);
  757. Line.SetLength(P - 1);
  758. }
  759. else
  760. {
  761. Abort();
  762. }
  763. }
  764. FFileName = UnixExtractFileName(Line);
  765. }
  766. }
  767. #undef GETNCOL
  768. #undef GETCOL
  769. }
  770. catch (Exception &E)
  771. {
  772. throw ETerminal(&E, FmtLoadStr(LIST_LINE_ERROR, ARRAYOFCONST((value))));
  773. }
  774. }
  775. //---------------------------------------------------------------------------
  776. void __fastcall TRemoteFile::Complete()
  777. {
  778. assert(Terminal != NULL);
  779. if (IsSymLink && Terminal->ResolvingSymlinks)
  780. {
  781. FindLinkedFile();
  782. }
  783. }
  784. //---------------------------------------------------------------------------
  785. void __fastcall TRemoteFile::FindLinkedFile()
  786. {
  787. assert(Terminal && IsSymLink);
  788. if (FLinkedFile) delete FLinkedFile;
  789. FLinkedFile = NULL;
  790. FCyclicLink = false;
  791. if (!LinkTo.IsEmpty())
  792. {
  793. // check for cyclic link
  794. TRemoteFile * LinkedBy = FLinkedByFile;
  795. while (LinkedBy)
  796. {
  797. if (LinkedBy->LinkTo == LinkTo)
  798. {
  799. // this is currenly redundant information, because it is used only to
  800. // detect broken symlink, which would be otherwise detected
  801. // by FLinkedFile == NULL
  802. FCyclicLink = true;
  803. break;
  804. }
  805. LinkedBy = LinkedBy->FLinkedByFile;
  806. }
  807. }
  808. if (FCyclicLink)
  809. {
  810. TRemoteFile * LinkedBy = FLinkedByFile;
  811. while (LinkedBy)
  812. {
  813. LinkedBy->FCyclicLink = true;
  814. LinkedBy = LinkedBy->FLinkedByFile;
  815. }
  816. }
  817. else
  818. {
  819. assert(Terminal->ResolvingSymlinks);
  820. Terminal->ExceptionOnFail = true;
  821. try
  822. {
  823. try
  824. {
  825. Terminal->ReadSymlink(this, FLinkedFile);
  826. }
  827. __finally
  828. {
  829. Terminal->ExceptionOnFail = false;
  830. }
  831. }
  832. catch (Exception &E)
  833. {
  834. if (E.InheritsFrom(__classid(EFatal))) throw;
  835. else Terminal->DoHandleExtendedException(&E);
  836. }
  837. }
  838. }
  839. //---------------------------------------------------------------------------
  840. AnsiString __fastcall TRemoteFile::GetListingStr()
  841. {
  842. // note that ModificationStr is longer than 12 for mfFull
  843. return Format("%s%s %3s %-8s %-8s %9s %-12s %s%s", ARRAYOFCONST((
  844. Type, Rights->Text, IntToStr(INodeBlocks), Owner,
  845. Group, IntToStr(Size), ModificationStr, FileName,
  846. (IsSymLink ? AnsiString(SYMLINKSTR) + LinkTo : AnsiString()))));
  847. }
  848. //---------------------------------------------------------------------------
  849. AnsiString __fastcall TRemoteFile::GetFullFileName() const
  850. {
  851. if (FFullFileName.IsEmpty())
  852. {
  853. assert(Terminal);
  854. assert(Directory != NULL);
  855. AnsiString Path;
  856. if (IsParentDirectory) Path = Directory->ParentPath;
  857. else
  858. if (IsDirectory) Path = UnixIncludeTrailingBackslash(Directory->FullDirectory + FileName);
  859. else Path = Directory->FullDirectory + FileName;
  860. return Terminal->TranslateLockedPath(Path, true);
  861. }
  862. else
  863. {
  864. return FFullFileName;
  865. }
  866. }
  867. //---------------------------------------------------------------------------
  868. Integer __fastcall TRemoteFile::GetAttr()
  869. {
  870. Integer Result = 0;
  871. if (Rights->ReadOnly) Result |= faReadOnly;
  872. if (IsHidden) Result |= faHidden;
  873. return Result;
  874. }
  875. //---------------------------------------------------------------------------
  876. void __fastcall TRemoteFile::SetTerminal(TTerminal * value)
  877. {
  878. FTerminal = value;
  879. if (FLinkedFile)
  880. {
  881. FLinkedFile->Terminal = value;
  882. }
  883. }
  884. //---------------------------------------------------------------------------
  885. //---------------------------------------------------------------------------
  886. __fastcall TRemoteDirectoryFile::TRemoteDirectoryFile() : TRemoteFile()
  887. {
  888. Modification = Now();
  889. LastAccess = Modification;
  890. Type = 'D';
  891. Size = 0;
  892. }
  893. //---------------------------------------------------------------------------
  894. //---------------------------------------------------------------------------
  895. __fastcall TRemoteParentDirectory::TRemoteParentDirectory() : TRemoteDirectoryFile()
  896. {
  897. FileName = PARENTDIRECTORY;
  898. }
  899. //=== TRemoteFileList ------------------------------------------------------
  900. __fastcall TRemoteFileList::TRemoteFileList():
  901. TObjectList()
  902. {
  903. FTimestamp = Now();
  904. }
  905. //---------------------------------------------------------------------------
  906. void __fastcall TRemoteFileList::AddFile(TRemoteFile * File)
  907. {
  908. Add(File);
  909. File->Directory = this;
  910. }
  911. //---------------------------------------------------------------------------
  912. void __fastcall TRemoteFileList::DuplicateTo(TRemoteFileList * Copy)
  913. {
  914. Copy->Clear();
  915. for (int Index = 0; Index < Count; Index++)
  916. {
  917. TRemoteFile * File = Files[Index];
  918. Copy->AddFile(File->Duplicate(false));
  919. }
  920. Copy->FDirectory = Directory;
  921. Copy->FTimestamp = FTimestamp;
  922. }
  923. //---------------------------------------------------------------------------
  924. void __fastcall TRemoteFileList::Clear()
  925. {
  926. FTimestamp = Now();
  927. TObjectList::Clear();
  928. }
  929. //---------------------------------------------------------------------------
  930. void __fastcall TRemoteFileList::SetDirectory(AnsiString value)
  931. {
  932. FDirectory = UnixExcludeTrailingBackslash(value);
  933. }
  934. //---------------------------------------------------------------------------
  935. AnsiString __fastcall TRemoteFileList::GetFullDirectory()
  936. {
  937. return UnixIncludeTrailingBackslash(Directory);
  938. }
  939. //---------------------------------------------------------------------------
  940. TRemoteFile * __fastcall TRemoteFileList::GetFiles(Integer Index)
  941. {
  942. return (TRemoteFile *)Items[Index];
  943. }
  944. //---------------------------------------------------------------------------
  945. Boolean __fastcall TRemoteFileList::GetIsRoot()
  946. {
  947. return (Directory == ROOTDIRECTORY);
  948. }
  949. //---------------------------------------------------------------------------
  950. AnsiString __fastcall TRemoteFileList::GetParentPath()
  951. {
  952. return UnixExtractFilePath(Directory);
  953. }
  954. //---------------------------------------------------------------------------
  955. __int64 __fastcall TRemoteFileList::GetTotalSize()
  956. {
  957. __int64 Result = 0;
  958. for (Integer Index = 0; Index < Count; Index++)
  959. if (!Files[Index]->IsDirectory) Result += Files[Index]->Size;
  960. return Result;
  961. }
  962. //---------------------------------------------------------------------------
  963. TRemoteFile * __fastcall TRemoteFileList::FindFile(const AnsiString &FileName)
  964. {
  965. for (Integer Index = 0; Index < Count; Index++)
  966. if (Files[Index]->FileName == FileName) return Files[Index];
  967. return NULL;
  968. }
  969. //=== TRemoteDirectory ------------------------------------------------------
  970. __fastcall TRemoteDirectory::TRemoteDirectory(TTerminal * aTerminal):
  971. TRemoteFileList(), FTerminal(aTerminal)
  972. {
  973. FSelectedFiles = NULL;
  974. FThisDirectory = NULL;
  975. FParentDirectory = NULL;
  976. FIncludeThisDirectory = false;
  977. FIncludeParentDirectory = true;
  978. }
  979. //---------------------------------------------------------------------------
  980. void __fastcall TRemoteDirectory::Clear()
  981. {
  982. if (ThisDirectory && !IncludeThisDirectory)
  983. {
  984. delete FThisDirectory;
  985. FThisDirectory = NULL;
  986. }
  987. if (ParentDirectory && !IncludeParentDirectory)
  988. {
  989. delete FParentDirectory;
  990. FParentDirectory = NULL;
  991. }
  992. TRemoteFileList::Clear();
  993. }
  994. //---------------------------------------------------------------------------
  995. void __fastcall TRemoteDirectory::SetDirectory(AnsiString value)
  996. {
  997. TRemoteFileList::SetDirectory(value);
  998. //Load();
  999. }
  1000. //---------------------------------------------------------------------------
  1001. void __fastcall TRemoteDirectory::AddFile(TRemoteFile * File)
  1002. {
  1003. if (File->IsThisDirectory) FThisDirectory = File;
  1004. if (File->IsParentDirectory) FParentDirectory = File;
  1005. if ((!File->IsThisDirectory || IncludeThisDirectory) &&
  1006. (!File->IsParentDirectory || IncludeParentDirectory))
  1007. {
  1008. TRemoteFileList::AddFile(File);
  1009. }
  1010. File->Terminal = Terminal;
  1011. }
  1012. //---------------------------------------------------------------------------
  1013. void __fastcall TRemoteDirectory::DuplicateTo(TRemoteFileList * Copy)
  1014. {
  1015. TRemoteFileList::DuplicateTo(Copy);
  1016. if (ThisDirectory && !IncludeThisDirectory)
  1017. {
  1018. Copy->AddFile(ThisDirectory->Duplicate(false));
  1019. }
  1020. if (ParentDirectory && !IncludeParentDirectory)
  1021. {
  1022. Copy->AddFile(ParentDirectory->Duplicate(false));
  1023. }
  1024. }
  1025. //---------------------------------------------------------------------------
  1026. bool __fastcall TRemoteDirectory::GetLoaded()
  1027. {
  1028. return ((Terminal != NULL) && Terminal->Active && !Directory.IsEmpty());
  1029. }
  1030. //---------------------------------------------------------------------------
  1031. TStrings * __fastcall TRemoteDirectory::GetSelectedFiles()
  1032. {
  1033. if (!FSelectedFiles)
  1034. {
  1035. FSelectedFiles = new TStringList();
  1036. }
  1037. else
  1038. {
  1039. FSelectedFiles->Clear();
  1040. }
  1041. for (int Index = 0; Index < Count; Index ++)
  1042. {
  1043. if (Files[Index]->Selected)
  1044. {
  1045. FSelectedFiles->Add(Files[Index]->FullFileName);
  1046. }
  1047. }
  1048. return FSelectedFiles;
  1049. }
  1050. //---------------------------------------------------------------------------
  1051. void __fastcall TRemoteDirectory::SetIncludeParentDirectory(Boolean value)
  1052. {
  1053. if (IncludeParentDirectory != value)
  1054. {
  1055. FIncludeParentDirectory = value;
  1056. if (value && ParentDirectory)
  1057. {
  1058. assert(IndexOf(ParentDirectory) < 0);
  1059. Add(ParentDirectory);
  1060. }
  1061. else if (!value && ParentDirectory)
  1062. {
  1063. assert(IndexOf(ParentDirectory) >= 0);
  1064. Extract(ParentDirectory);
  1065. }
  1066. }
  1067. }
  1068. //---------------------------------------------------------------------------
  1069. void __fastcall TRemoteDirectory::SetIncludeThisDirectory(Boolean value)
  1070. {
  1071. if (IncludeThisDirectory != value)
  1072. {
  1073. FIncludeThisDirectory = value;
  1074. if (value && ThisDirectory)
  1075. {
  1076. assert(IndexOf(ThisDirectory) < 0);
  1077. Add(ThisDirectory);
  1078. }
  1079. else if (!value && ThisDirectory)
  1080. {
  1081. assert(IndexOf(ThisDirectory) >= 0);
  1082. Extract(ThisDirectory);
  1083. }
  1084. }
  1085. }
  1086. //===========================================================================
  1087. __fastcall TRemoteDirectoryCache::TRemoteDirectoryCache(): TStringList()
  1088. {
  1089. FSection = new TCriticalSection();
  1090. Sorted = true;
  1091. Duplicates = dupError;
  1092. CaseSensitive = true;
  1093. }
  1094. //---------------------------------------------------------------------------
  1095. __fastcall TRemoteDirectoryCache::~TRemoteDirectoryCache()
  1096. {
  1097. Clear();
  1098. delete FSection;
  1099. }
  1100. //---------------------------------------------------------------------------
  1101. void __fastcall TRemoteDirectoryCache::Clear()
  1102. {
  1103. TGuard Guard(FSection);
  1104. try
  1105. {
  1106. for (int Index = 0; Index < Count; Index++)
  1107. {
  1108. delete (TRemoteFileList *)Objects[Index];
  1109. Objects[Index] = NULL;
  1110. }
  1111. }
  1112. __finally
  1113. {
  1114. TStringList::Clear();
  1115. }
  1116. }
  1117. //---------------------------------------------------------------------------
  1118. bool __fastcall TRemoteDirectoryCache::GetIsEmpty() const
  1119. {
  1120. TGuard Guard(FSection);
  1121. return (const_cast<TRemoteDirectoryCache*>(this)->Count == 0);
  1122. }
  1123. //---------------------------------------------------------------------------
  1124. bool __fastcall TRemoteDirectoryCache::HasFileList(const AnsiString Directory)
  1125. {
  1126. TGuard Guard(FSection);
  1127. int Index = IndexOf(UnixExcludeTrailingBackslash(Directory));
  1128. return (Index >= 0);
  1129. }
  1130. //---------------------------------------------------------------------------
  1131. bool __fastcall TRemoteDirectoryCache::HasNewerFileList(const AnsiString Directory,
  1132. TDateTime Timestamp)
  1133. {
  1134. TGuard Guard(FSection);
  1135. int Index = IndexOf(UnixExcludeTrailingBackslash(Directory));
  1136. if (Index >= 0)
  1137. {
  1138. TRemoteFileList * FileList = dynamic_cast<TRemoteFileList *>(Objects[Index]);
  1139. if (FileList->Timestamp <= Timestamp)
  1140. {
  1141. Index = -1;
  1142. }
  1143. }
  1144. return (Index >= 0);
  1145. }
  1146. //---------------------------------------------------------------------------
  1147. bool __fastcall TRemoteDirectoryCache::GetFileList(const AnsiString Directory,
  1148. TRemoteFileList * FileList)
  1149. {
  1150. TGuard Guard(FSection);
  1151. int Index = IndexOf(UnixExcludeTrailingBackslash(Directory));
  1152. bool Result = (Index >= 0);
  1153. if (Result)
  1154. {
  1155. assert(Objects[Index] != NULL);
  1156. dynamic_cast<TRemoteFileList *>(Objects[Index])->DuplicateTo(FileList);
  1157. }
  1158. return Result;
  1159. }
  1160. //---------------------------------------------------------------------------
  1161. void __fastcall TRemoteDirectoryCache::AddFileList(TRemoteFileList * FileList)
  1162. {
  1163. // file list cannot be cached already with only one thread, but it can be
  1164. // when directory is loaded by secondary terminal
  1165. ClearFileList(FileList->Directory, false);
  1166. assert(FileList);
  1167. TRemoteFileList * Copy = new TRemoteFileList();
  1168. FileList->DuplicateTo(Copy);
  1169. {
  1170. TGuard Guard(FSection);
  1171. AddObject(Copy->Directory, Copy);
  1172. }
  1173. }
  1174. //---------------------------------------------------------------------------
  1175. void __fastcall TRemoteDirectoryCache::ClearFileList(AnsiString Directory, bool SubDirs)
  1176. {
  1177. TGuard Guard(FSection);
  1178. Directory = UnixExcludeTrailingBackslash(Directory);
  1179. int Index = IndexOf(Directory);
  1180. if (Index >= 0)
  1181. {
  1182. Delete(Index);
  1183. }
  1184. if (SubDirs)
  1185. {
  1186. Directory = UnixIncludeTrailingBackslash(Directory);
  1187. Index = Count-1;
  1188. while (Index >= 0)
  1189. {
  1190. if (Strings[Index].SubString(1, Directory.Length()) == Directory)
  1191. {
  1192. Delete(Index);
  1193. }
  1194. Index--;
  1195. }
  1196. }
  1197. }
  1198. //---------------------------------------------------------------------------
  1199. void __fastcall TRemoteDirectoryCache::Delete(int Index)
  1200. {
  1201. delete (TRemoteFileList *)Objects[Index];
  1202. TStringList::Delete(Index);
  1203. }
  1204. //---------------------------------------------------------------------------
  1205. //---------------------------------------------------------------------------
  1206. __fastcall TRemoteDirectoryChangesCache::TRemoteDirectoryChangesCache() :
  1207. TStringList()
  1208. {
  1209. }
  1210. //---------------------------------------------------------------------------
  1211. void __fastcall TRemoteDirectoryChangesCache::Clear()
  1212. {
  1213. TStringList::Clear();
  1214. }
  1215. //---------------------------------------------------------------------------
  1216. bool __fastcall TRemoteDirectoryChangesCache::GetIsEmpty() const
  1217. {
  1218. return (const_cast<TRemoteDirectoryChangesCache*>(this)->Count == 0);
  1219. }
  1220. //---------------------------------------------------------------------------
  1221. void __fastcall TRemoteDirectoryChangesCache::AddDirectoryChange(
  1222. const AnsiString SourceDir, const AnsiString Change,
  1223. const AnsiString TargetDir)
  1224. {
  1225. assert(!TargetDir.IsEmpty());
  1226. Values[TargetDir] = "//";
  1227. if (TTerminal::ExpandFileName(Change, SourceDir) != TargetDir)
  1228. {
  1229. AnsiString Key;
  1230. if (DirectoryChangeKey(SourceDir, Change, Key))
  1231. {
  1232. Values[Key] = TargetDir;
  1233. }
  1234. }
  1235. }
  1236. //---------------------------------------------------------------------------
  1237. void __fastcall TRemoteDirectoryChangesCache::ClearDirectoryChange(
  1238. AnsiString SourceDir)
  1239. {
  1240. for (int Index = 0; Index < Count; Index++)
  1241. {
  1242. if (Names[Index].SubString(1, SourceDir.Length()) == SourceDir)
  1243. {
  1244. Delete(Index);
  1245. Index--;
  1246. }
  1247. }
  1248. }
  1249. //---------------------------------------------------------------------------
  1250. void __fastcall TRemoteDirectoryChangesCache::ClearDirectoryChangeTarget(
  1251. AnsiString TargetDir)
  1252. {
  1253. for (int Index = 0; Index < Count; Index++)
  1254. {
  1255. AnsiString Name = Names[Index];
  1256. if ((Name.SubString(1, TargetDir.Length()) == TargetDir) ||
  1257. (Values[Name].SubString(1, TargetDir.Length()) == TargetDir))
  1258. {
  1259. Delete(Index);
  1260. Index--;
  1261. }
  1262. }
  1263. }
  1264. //---------------------------------------------------------------------------
  1265. bool __fastcall TRemoteDirectoryChangesCache::GetDirectoryChange(
  1266. const AnsiString SourceDir, const AnsiString Change, AnsiString & TargetDir)
  1267. {
  1268. AnsiString Key;
  1269. bool Result;
  1270. Key = TTerminal::ExpandFileName(Change, SourceDir);
  1271. Result = (IndexOfName(Key) >= 0);
  1272. if (Result)
  1273. {
  1274. TargetDir = Values[Key];
  1275. // TargetDir is not "//" here only when Change is full path to symbolic link
  1276. if (TargetDir == "//")
  1277. {
  1278. TargetDir = Key;
  1279. }
  1280. }
  1281. else
  1282. {
  1283. Result = DirectoryChangeKey(SourceDir, Change, Key);
  1284. if (Result)
  1285. {
  1286. AnsiString Directory = Values[Key];
  1287. Result = !Directory.IsEmpty();
  1288. if (Result)
  1289. {
  1290. TargetDir = Directory;
  1291. }
  1292. }
  1293. }
  1294. return Result;
  1295. }
  1296. //---------------------------------------------------------------------------
  1297. void __fastcall TRemoteDirectoryChangesCache::Serialize(AnsiString & Data)
  1298. {
  1299. Data = "A" + Text;
  1300. }
  1301. //---------------------------------------------------------------------------
  1302. void __fastcall TRemoteDirectoryChangesCache::Deserialize(const AnsiString Data)
  1303. {
  1304. if (Data.IsEmpty())
  1305. {
  1306. Text = "";
  1307. }
  1308. else
  1309. {
  1310. Text = Data.c_str() + 1;
  1311. }
  1312. }
  1313. //---------------------------------------------------------------------------
  1314. bool __fastcall TRemoteDirectoryChangesCache::DirectoryChangeKey(
  1315. const AnsiString SourceDir, const AnsiString Change, AnsiString & Key)
  1316. {
  1317. bool Result = !Change.IsEmpty();
  1318. if (Result)
  1319. {
  1320. bool Absolute = TTerminal::IsAbsolutePath(Change);
  1321. Result = !SourceDir.IsEmpty() || Absolute;
  1322. if (Result)
  1323. {
  1324. Key = Absolute ? Change : SourceDir + "," + Change;
  1325. }
  1326. }
  1327. return Result;
  1328. }
  1329. //=== TRights ---------------------------------------------------------------
  1330. const char TRights::BasicSymbols[] = "rwxrwxrwx";
  1331. const char TRights::CombinedSymbols[] = "--s--s--t";
  1332. const char TRights::ExtendedSymbols[] = "--S--S--T";
  1333. const char TRights::ModeGroups[] = "ugo";
  1334. //---------------------------------------------------------------------------
  1335. __fastcall TRights::TRights()
  1336. {
  1337. FAllowUndef = false;
  1338. FSet = 0;
  1339. FUnset = 0;
  1340. Number = 0;
  1341. }
  1342. //---------------------------------------------------------------------------
  1343. __fastcall TRights::TRights(unsigned short ANumber)
  1344. {
  1345. FAllowUndef = false;
  1346. FSet = 0;
  1347. FUnset = 0;
  1348. Number = ANumber;
  1349. }
  1350. //---------------------------------------------------------------------------
  1351. __fastcall TRights::TRights(const TRights & Source)
  1352. {
  1353. Assign(&Source);
  1354. }
  1355. //---------------------------------------------------------------------------
  1356. void __fastcall TRights::Assign(const TRights * Source)
  1357. {
  1358. FAllowUndef = Source->AllowUndef;
  1359. FSet = Source->FSet;
  1360. FUnset = Source->FUnset;
  1361. FText = Source->FText;
  1362. }
  1363. //---------------------------------------------------------------------------
  1364. TRights::TFlag __fastcall TRights::RightToFlag(TRights::TRight Right)
  1365. {
  1366. return static_cast<TFlag>(1 << (rrLast - Right));
  1367. }
  1368. //---------------------------------------------------------------------------
  1369. bool __fastcall TRights::operator ==(const TRights & rhr) const
  1370. {
  1371. if (AllowUndef || rhr.AllowUndef)
  1372. {
  1373. for (int Right = rrFirst; Right <= rrLast; Right++)
  1374. {
  1375. if (RightUndef[static_cast<TRight>(Right)] !=
  1376. rhr.RightUndef[static_cast<TRight>(Right)])
  1377. {
  1378. return false;
  1379. }
  1380. }
  1381. return true;
  1382. }
  1383. else
  1384. {
  1385. return (Number == rhr.Number);
  1386. }
  1387. }
  1388. //---------------------------------------------------------------------------
  1389. bool __fastcall TRights::operator ==(unsigned short rhr) const
  1390. {
  1391. return (Number == rhr);
  1392. }
  1393. //---------------------------------------------------------------------------
  1394. bool __fastcall TRights::operator !=(const TRights & rhr) const
  1395. {
  1396. return !(*this == rhr);
  1397. }
  1398. //---------------------------------------------------------------------------
  1399. TRights & __fastcall TRights::operator =(unsigned short rhr)
  1400. {
  1401. Number = rhr;
  1402. return *this;
  1403. }
  1404. //---------------------------------------------------------------------------
  1405. TRights & __fastcall TRights::operator =(const TRights & rhr)
  1406. {
  1407. Assign(&rhr);
  1408. return *this;
  1409. }
  1410. //---------------------------------------------------------------------------
  1411. TRights __fastcall TRights::operator ~() const
  1412. {
  1413. TRights Result(static_cast<unsigned short>(~Number));
  1414. return Result;
  1415. }
  1416. //---------------------------------------------------------------------------
  1417. TRights __fastcall TRights::operator &(const TRights & rhr) const
  1418. {
  1419. TRights Result(*this);
  1420. Result &= rhr;
  1421. return Result;
  1422. }
  1423. //---------------------------------------------------------------------------
  1424. TRights __fastcall TRights::operator &(unsigned short rhr) const
  1425. {
  1426. TRights Result(*this);
  1427. Result &= rhr;
  1428. return Result;
  1429. }
  1430. //---------------------------------------------------------------------------
  1431. TRights & __fastcall TRights::operator &=(const TRights & rhr)
  1432. {
  1433. if (AllowUndef || rhr.AllowUndef)
  1434. {
  1435. for (int Right = rrFirst; Right <= rrLast; Right++)
  1436. {
  1437. if (RightUndef[static_cast<TRight>(Right)] !=
  1438. rhr.RightUndef[static_cast<TRight>(Right)])
  1439. {
  1440. RightUndef[static_cast<TRight>(Right)] = rsUndef;
  1441. }
  1442. }
  1443. }
  1444. else
  1445. {
  1446. Number &= rhr.Number;
  1447. }
  1448. return *this;
  1449. }
  1450. //---------------------------------------------------------------------------
  1451. TRights & __fastcall TRights::operator &=(unsigned short rhr)
  1452. {
  1453. Number &= rhr;
  1454. return *this;
  1455. }
  1456. //---------------------------------------------------------------------------
  1457. TRights __fastcall TRights::operator |(const TRights & rhr) const
  1458. {
  1459. TRights Result(*this);
  1460. Result |= rhr;
  1461. return Result;
  1462. }
  1463. //---------------------------------------------------------------------------
  1464. TRights __fastcall TRights::operator |(unsigned short rhr) const
  1465. {
  1466. TRights Result(*this);
  1467. Result |= rhr;
  1468. return Result;
  1469. }
  1470. //---------------------------------------------------------------------------
  1471. TRights & __fastcall TRights::operator |=(const TRights & rhr)
  1472. {
  1473. Number |= rhr.Number;
  1474. return *this;
  1475. }
  1476. //---------------------------------------------------------------------------
  1477. TRights & __fastcall TRights::operator |=(unsigned short rhr)
  1478. {
  1479. Number |= rhr;
  1480. return *this;
  1481. }
  1482. //---------------------------------------------------------------------------
  1483. void __fastcall TRights::SetAllowUndef(bool value)
  1484. {
  1485. if (FAllowUndef != value)
  1486. {
  1487. assert(!value || ((FSet | FUnset) == rfAllSpecials));
  1488. FAllowUndef = value;
  1489. }
  1490. }
  1491. //---------------------------------------------------------------------------
  1492. void __fastcall TRights::SetText(const AnsiString & value)
  1493. {
  1494. if (value != Text)
  1495. {
  1496. if ((value.Length() != TextLen) ||
  1497. (!AllowUndef && (value.Pos(UndefSymbol) > 0)) ||
  1498. (value.Pos(" ") > 0))
  1499. {
  1500. throw Exception(FMTLOAD(RIGHTS_ERROR, (value)));
  1501. }
  1502. FSet = 0;
  1503. FUnset = 0;
  1504. int Flag = 00001;
  1505. int ExtendedFlag = 01000;
  1506. bool KeepText = false;
  1507. for (int i = TextLen; i >= 1; i--)
  1508. {
  1509. if (value[i] == UnsetSymbol)
  1510. {
  1511. FUnset |= static_cast<unsigned short>(Flag | ExtendedFlag);
  1512. }
  1513. else if (value[i] == UndefSymbol)
  1514. {
  1515. // do nothing
  1516. }
  1517. else if (value[i] == CombinedSymbols[i - 1])
  1518. {
  1519. FSet |= static_cast<unsigned short>(Flag | ExtendedFlag);
  1520. }
  1521. else if (value[i] == ExtendedSymbols[i - 1])
  1522. {
  1523. FSet |= static_cast<unsigned short>(ExtendedFlag);
  1524. FUnset |= static_cast<unsigned short>(Flag);
  1525. }
  1526. else
  1527. {
  1528. if (value[i] != BasicSymbols[i - 1])
  1529. {
  1530. KeepText = true;
  1531. }
  1532. FSet |= static_cast<unsigned short>(Flag);
  1533. FUnset |= static_cast<unsigned short>(ExtendedFlag);
  1534. }
  1535. Flag <<= 1;
  1536. if (i % 3 == 1)
  1537. {
  1538. ExtendedFlag <<= 1;
  1539. }
  1540. }
  1541. FText = KeepText ? value : AnsiString();
  1542. }
  1543. }
  1544. //---------------------------------------------------------------------------
  1545. AnsiString __fastcall TRights::GetText() const
  1546. {
  1547. if (!FText.IsEmpty())
  1548. {
  1549. return FText;
  1550. }
  1551. else
  1552. {
  1553. AnsiString Result;
  1554. Result.SetLength(TextLen);
  1555. int Flag = 00001;
  1556. int ExtendedFlag = 01000;
  1557. bool ExtendedPos = true;
  1558. char Symbol;
  1559. int i = TextLen;
  1560. while (i >= 1)
  1561. {
  1562. if (ExtendedPos &&
  1563. ((FSet & (Flag | ExtendedFlag)) == (Flag | ExtendedFlag)))
  1564. {
  1565. Symbol = CombinedSymbols[i - 1];
  1566. }
  1567. else if ((FSet & Flag) != 0)
  1568. {
  1569. Symbol = BasicSymbols[i - 1];
  1570. }
  1571. else if (ExtendedPos && ((FSet & ExtendedFlag) != 0))
  1572. {
  1573. Symbol = ExtendedSymbols[i - 1];
  1574. }
  1575. else if ((!ExtendedPos && ((FUnset & Flag) == Flag)) ||
  1576. (ExtendedPos && ((FUnset & (Flag | ExtendedFlag)) == (Flag | ExtendedFlag))))
  1577. {
  1578. Symbol = UnsetSymbol;
  1579. }
  1580. else
  1581. {
  1582. Symbol = UndefSymbol;
  1583. }
  1584. Result[i] = Symbol;
  1585. Flag <<= 1;
  1586. i--;
  1587. ExtendedPos = ((i % 3) == 0);
  1588. if (ExtendedPos)
  1589. {
  1590. ExtendedFlag <<= 1;
  1591. }
  1592. }
  1593. return Result;
  1594. }
  1595. }
  1596. //---------------------------------------------------------------------------
  1597. void __fastcall TRights::SetOctal(AnsiString value)
  1598. {
  1599. AnsiString AValue(value);
  1600. if (AValue.Length() == 3)
  1601. {
  1602. AValue = "0" + AValue;
  1603. }
  1604. if (Octal != AValue)
  1605. {
  1606. bool Correct = (AValue.Length() == 4);
  1607. if (Correct)
  1608. {
  1609. for (int i = 1; (i <= AValue.Length()) && Correct; i++)
  1610. {
  1611. Correct = (AValue[i] >= '0') && (AValue[i] <= '7');
  1612. }
  1613. }
  1614. if (!Correct)
  1615. {
  1616. throw Exception(FMTLOAD(INVALID_OCTAL_PERMISSIONS, (value)));
  1617. }
  1618. Number = static_cast<unsigned short>(
  1619. ((AValue[1] - '0') << 9) +
  1620. ((AValue[2] - '0') << 6) +
  1621. ((AValue[3] - '0') << 3) +
  1622. ((AValue[4] - '0') << 0));
  1623. }
  1624. }
  1625. //---------------------------------------------------------------------------
  1626. AnsiString __fastcall TRights::GetOctal() const
  1627. {
  1628. AnsiString Result;
  1629. unsigned short N = NumberSet; // used to be "Number"
  1630. Result.SetLength(4);
  1631. Result[1] = static_cast<char>('0' + ((N & 07000) >> 9));
  1632. Result[2] = static_cast<char>('0' + ((N & 00700) >> 6));
  1633. Result[3] = static_cast<char>('0' + ((N & 00070) >> 3));
  1634. Result[4] = static_cast<char>('0' + ((N & 00007) >> 0));
  1635. return Result;
  1636. }
  1637. //---------------------------------------------------------------------------
  1638. void __fastcall TRights::SetNumber(unsigned short value)
  1639. {
  1640. if ((FSet != value) || ((FSet | FUnset) != rfAllSpecials))
  1641. {
  1642. FSet = value;
  1643. FUnset = static_cast<unsigned short>(rfAllSpecials & ~FSet);
  1644. FText = "";
  1645. }
  1646. }
  1647. //---------------------------------------------------------------------------
  1648. unsigned short __fastcall TRights::GetNumber() const
  1649. {
  1650. assert(!IsUndef);
  1651. return FSet;
  1652. }
  1653. //---------------------------------------------------------------------------
  1654. void __fastcall TRights::SetRight(TRight Right, bool value)
  1655. {
  1656. RightUndef[Right] = (value ? rsYes : rsNo);
  1657. }
  1658. //---------------------------------------------------------------------------
  1659. bool __fastcall TRights::GetRight(TRight Right) const
  1660. {
  1661. TState State = RightUndef[Right];
  1662. assert(State != rsUndef);
  1663. return (State == rsYes);
  1664. }
  1665. //---------------------------------------------------------------------------
  1666. void __fastcall TRights::SetRightUndef(TRight Right, TState value)
  1667. {
  1668. if (value != RightUndef[Right])
  1669. {
  1670. assert((value != rsUndef) || AllowUndef);
  1671. TFlag Flag = RightToFlag(Right);
  1672. switch (value)
  1673. {
  1674. case rsYes:
  1675. FSet |= Flag;
  1676. FUnset &= ~Flag;
  1677. break;
  1678. case rsNo:
  1679. FSet &= ~Flag;
  1680. FUnset |= Flag;
  1681. break;
  1682. case rsUndef:
  1683. default:
  1684. FSet &= ~Flag;
  1685. FUnset &= ~Flag;
  1686. break;
  1687. }
  1688. FText = "";
  1689. }
  1690. }
  1691. //---------------------------------------------------------------------------
  1692. TRights::TState __fastcall TRights::GetRightUndef(TRight Right) const
  1693. {
  1694. TFlag Flag = RightToFlag(Right);
  1695. TState Result;
  1696. if ((FSet & Flag) != 0)
  1697. {
  1698. Result = rsYes;
  1699. }
  1700. else if ((FUnset & Flag) != 0)
  1701. {
  1702. Result = rsNo;
  1703. }
  1704. else
  1705. {
  1706. Result = rsUndef;
  1707. }
  1708. return Result;
  1709. }
  1710. //---------------------------------------------------------------------------
  1711. void __fastcall TRights::SetReadOnly(bool value)
  1712. {
  1713. Right[rrUserWrite] = !value;
  1714. Right[rrGroupWrite] = !value;
  1715. Right[rrOtherWrite] = !value;
  1716. }
  1717. //---------------------------------------------------------------------------
  1718. bool __fastcall TRights::GetReadOnly()
  1719. {
  1720. return Right[rrUserWrite] && Right[rrGroupWrite] && Right[rrOtherWrite];
  1721. }
  1722. //---------------------------------------------------------------------------
  1723. AnsiString __fastcall TRights::GetSimplestStr() const
  1724. {
  1725. return IsUndef ? ModeStr : Octal;
  1726. }
  1727. //---------------------------------------------------------------------------
  1728. AnsiString __fastcall TRights::GetModeStr() const
  1729. {
  1730. AnsiString Result;
  1731. AnsiString SetModeStr, UnsetModeStr;
  1732. TRight Right;
  1733. int Index;
  1734. for (int Group = 0; Group < 3; Group++)
  1735. {
  1736. SetModeStr = "";
  1737. UnsetModeStr = "";
  1738. for (int Mode = 0; Mode < 3; Mode++)
  1739. {
  1740. Index = (Group * 3) + Mode;
  1741. Right = static_cast<TRight>(rrUserRead + Index);
  1742. switch (RightUndef[Right])
  1743. {
  1744. case rsYes:
  1745. SetModeStr += BasicSymbols[Index];
  1746. break;
  1747. case rsNo:
  1748. UnsetModeStr += BasicSymbols[Index];
  1749. break;
  1750. }
  1751. }
  1752. Right = static_cast<TRight>(rrUserIDExec + Group);
  1753. Index = (Group * 3) + 2;
  1754. switch (RightUndef[Right])
  1755. {
  1756. case rsYes:
  1757. SetModeStr += CombinedSymbols[Index];
  1758. break;
  1759. case rsNo:
  1760. UnsetModeStr += CombinedSymbols[Index];
  1761. break;
  1762. }
  1763. if (!SetModeStr.IsEmpty() || !UnsetModeStr.IsEmpty())
  1764. {
  1765. if (!Result.IsEmpty())
  1766. {
  1767. Result += ',';
  1768. }
  1769. Result += ModeGroups[Group];
  1770. if (!SetModeStr.IsEmpty())
  1771. {
  1772. Result += "+" + SetModeStr;
  1773. }
  1774. if (!UnsetModeStr.IsEmpty())
  1775. {
  1776. Result += "-" + UnsetModeStr;
  1777. }
  1778. }
  1779. }
  1780. return Result;
  1781. }
  1782. //---------------------------------------------------------------------------
  1783. void __fastcall TRights::AddExecute()
  1784. {
  1785. for (int Group = 0; Group < 3; Group++)
  1786. {
  1787. if ((RightUndef[static_cast<TRight>(rrUserRead + (Group * 3))] == rsYes) ||
  1788. (RightUndef[static_cast<TRight>(rrUserWrite + (Group * 3))] == rsYes))
  1789. {
  1790. Right[static_cast<TRight>(rrUserExec + (Group * 3))] = true;
  1791. }
  1792. }
  1793. }
  1794. //---------------------------------------------------------------------------
  1795. void __fastcall TRights::AllUndef()
  1796. {
  1797. if ((FSet != 0) || (FUnset != 0))
  1798. {
  1799. FSet = 0;
  1800. FUnset = 0;
  1801. FText = "";
  1802. }
  1803. }
  1804. //---------------------------------------------------------------------------
  1805. bool __fastcall TRights::GetIsUndef() const
  1806. {
  1807. return ((FSet | FUnset) != rfAllSpecials);
  1808. }
  1809. //---------------------------------------------------------------------------
  1810. __fastcall TRights::operator unsigned short() const
  1811. {
  1812. return Number;
  1813. }
  1814. //---------------------------------------------------------------------------
  1815. __fastcall TRights::operator unsigned long() const
  1816. {
  1817. return Number;
  1818. }
  1819. //=== TRemoteProperties -------------------------------------------------------
  1820. __fastcall TRemoteProperties::TRemoteProperties()
  1821. {
  1822. Valid.Clear();
  1823. AddXToDirectories = false;
  1824. Rights.AllowUndef = false;
  1825. Rights.Number = 0;
  1826. Group = "";
  1827. Owner = "";
  1828. Recursive = false;
  1829. };
  1830. //---------------------------------------------------------------------------
  1831. bool __fastcall TRemoteProperties::operator ==(const TRemoteProperties & rhp) const
  1832. {
  1833. bool Result = (Valid == rhp.Valid && Recursive == rhp.Recursive);
  1834. if (Result)
  1835. {
  1836. if ((Valid.Contains(vpRights) &&
  1837. (Rights != rhp.Rights || AddXToDirectories != rhp.AddXToDirectories)) ||
  1838. (Valid.Contains(vpOwner) && Owner != rhp.Owner) ||
  1839. (Valid.Contains(vpGroup) && Group != rhp.Group) ||
  1840. (Valid.Contains(vpModification) && (Modification != rhp.Modification)) ||
  1841. (Valid.Contains(vpLastAccess) && (LastAccess != rhp.LastAccess)))
  1842. {
  1843. Result = false;
  1844. }
  1845. }
  1846. return Result;
  1847. }
  1848. //---------------------------------------------------------------------------
  1849. bool __fastcall TRemoteProperties::operator !=(const TRemoteProperties & rhp) const
  1850. {
  1851. return !(*this == rhp);
  1852. }
  1853. //---------------------------------------------------------------------------
  1854. TRemoteProperties __fastcall TRemoteProperties::CommonProperties(TStrings * FileList)
  1855. {
  1856. // TODO: Modification and LastAccess
  1857. TRemoteProperties CommonProperties;
  1858. for (int Index = 0; Index < FileList->Count; Index++)
  1859. {
  1860. TRemoteFile * File = (TRemoteFile *)(FileList->Objects[Index]);
  1861. assert(File);
  1862. if (!Index)
  1863. {
  1864. CommonProperties.Rights = *(File->Rights);
  1865. // previously we allowed undef implicitly for directories,
  1866. // now we do it explicitly in properties dialog and only in combination
  1867. // with "recursive" option
  1868. CommonProperties.Rights.AllowUndef = File->Rights->IsUndef;
  1869. CommonProperties.Valid << vpRights;
  1870. if (!File->Owner.IsEmpty())
  1871. {
  1872. CommonProperties.Owner = File->Owner;
  1873. CommonProperties.Valid << vpOwner;
  1874. }
  1875. if (!File->Group.IsEmpty())
  1876. {
  1877. CommonProperties.Group = File->Group;
  1878. CommonProperties.Valid << vpGroup;
  1879. }
  1880. }
  1881. else
  1882. {
  1883. CommonProperties.Rights.AllowUndef = True;
  1884. CommonProperties.Rights &= *File->Rights;
  1885. if (CommonProperties.Owner != File->Owner)
  1886. {
  1887. CommonProperties.Owner = "";
  1888. CommonProperties.Valid >> vpOwner;
  1889. };
  1890. if (CommonProperties.Group != File->Group)
  1891. {
  1892. CommonProperties.Group = "";
  1893. CommonProperties.Valid >> vpGroup;
  1894. };
  1895. }
  1896. }
  1897. return CommonProperties;
  1898. }
  1899. //---------------------------------------------------------------------------
  1900. TRemoteProperties __fastcall TRemoteProperties::ChangedProperties(
  1901. const TRemoteProperties & OriginalProperties, TRemoteProperties NewProperties)
  1902. {
  1903. // TODO: Modification and LastAccess
  1904. if (!NewProperties.Recursive)
  1905. {
  1906. if (NewProperties.Rights == OriginalProperties.Rights &&
  1907. !NewProperties.AddXToDirectories)
  1908. {
  1909. NewProperties.Valid >> vpRights;
  1910. }
  1911. if (NewProperties.Group == OriginalProperties.Group)
  1912. {
  1913. NewProperties.Valid >> vpGroup;
  1914. }
  1915. if (NewProperties.Owner == OriginalProperties.Owner)
  1916. {
  1917. NewProperties.Valid >> vpOwner;
  1918. }
  1919. }
  1920. return NewProperties;
  1921. }