RemoteFiles.cpp 51 KB

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