SftpFileAttributes.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Globalization;
  5. namespace Renci.SshNet.Sftp
  6. {
  7. /// <summary>
  8. /// Contains SFTP file attributes.
  9. /// </summary>
  10. public class SftpFileAttributes
  11. {
  12. #region Bitmask constats
  13. private const UInt32 S_IFMT = 0xF000; // bitmask for the file type bitfields
  14. private const UInt32 S_IFSOCK = 0xC000; // socket
  15. private const UInt32 S_IFLNK = 0xA000; // symbolic link
  16. private const UInt32 S_IFREG = 0x8000; // regular file
  17. private const UInt32 S_IFBLK = 0x6000; // block device
  18. private const UInt32 S_IFDIR = 0x4000; // directory
  19. private const UInt32 S_IFCHR = 0x2000; // character device
  20. private const UInt32 S_IFIFO = 0x1000; // FIFO
  21. private const UInt32 S_ISUID = 0x0800; // set UID bit
  22. private const UInt32 S_ISGID = 0x0400; // set-group-ID bit (see below)
  23. private const UInt32 S_ISVTX = 0x0200; // sticky bit (see below)
  24. private const UInt32 S_IRUSR = 0x0100; // owner has read permission
  25. private const UInt32 S_IWUSR = 0x0080; // owner has write permission
  26. private const UInt32 S_IXUSR = 0x0040; // owner has execute permission
  27. private const UInt32 S_IRGRP = 0x0020; // group has read permission
  28. private const UInt32 S_IWGRP = 0x0010; // group has write permission
  29. private const UInt32 S_IXGRP = 0x0008; // group has execute permission
  30. private const UInt32 S_IROTH = 0x0004; // others have read permission
  31. private const UInt32 S_IWOTH = 0x0002; // others have write permission
  32. private const UInt32 S_IXOTH = 0x0001; // others have execute permission
  33. #endregion
  34. private bool _isBitFiledsBitSet;
  35. private bool _isUIDBitSet;
  36. private bool _isGroupIDBitSet;
  37. private bool _isStickyBitSet;
  38. private readonly DateTime _originalLastAccessTime;
  39. private readonly DateTime _originalLastWriteTime;
  40. private readonly long _originalSize;
  41. private readonly int _originalUserId;
  42. private readonly int _originalGroupId;
  43. private readonly uint _originalPermissions;
  44. private readonly IDictionary<string, string> _originalExtensions;
  45. internal bool IsLastAccessTimeChanged
  46. {
  47. get { return this._originalLastAccessTime != this.LastAccessTime; }
  48. }
  49. internal bool IsLastWriteTimeChanged
  50. {
  51. get { return this._originalLastWriteTime != this.LastWriteTime; }
  52. }
  53. internal bool IsSizeChanged
  54. {
  55. get { return this._originalSize != this.Size; }
  56. }
  57. internal bool IsUserIdChanged
  58. {
  59. get { return this._originalUserId != this.UserId; }
  60. }
  61. internal bool IsGroupIdChanged
  62. {
  63. get { return this._originalGroupId != this.GroupId; }
  64. }
  65. internal bool IsPermissionsChanged
  66. {
  67. get { return this._originalPermissions != this.Permissions; }
  68. }
  69. internal bool IsExtensionsChanged
  70. {
  71. get { return this._originalExtensions != null && this.Extensions != null && !this._originalExtensions.SequenceEqual(this.Extensions); }
  72. }
  73. /// <summary>
  74. /// Gets or sets the time the current file or directory was last accessed.
  75. /// </summary>
  76. /// <value>
  77. /// The time that the current file or directory was last accessed.
  78. /// </value>
  79. public DateTime LastAccessTime { get; set; }
  80. /// <summary>
  81. /// Gets or sets the time when the current file or directory was last written to.
  82. /// </summary>
  83. /// <value>
  84. /// The time the current file was last written.
  85. /// </value>
  86. public DateTime LastWriteTime { get; set; }
  87. /// <summary>
  88. /// Gets or sets the size, in bytes, of the current file.
  89. /// </summary>
  90. /// <value>
  91. /// The size of the current file in bytes.
  92. /// </value>
  93. public long Size { get; set; }
  94. /// <summary>
  95. /// Gets or sets file user id.
  96. /// </summary>
  97. /// <value>
  98. /// File user id.
  99. /// </value>
  100. public int UserId { get; set; }
  101. /// <summary>
  102. /// Gets or sets file group id.
  103. /// </summary>
  104. /// <value>
  105. /// File group id.
  106. /// </value>
  107. public int GroupId { get; set; }
  108. /// <summary>
  109. /// Gets a value indicating whether file represents a socket.
  110. /// </summary>
  111. /// <value>
  112. /// <c>true</c> if file represents a socket; otherwise, <c>false</c>.
  113. /// </value>
  114. public bool IsSocket { get; private set; }
  115. /// <summary>
  116. /// Gets a value indicating whether file represents a symbolic link.
  117. /// </summary>
  118. /// <value>
  119. /// <c>true</c> if file represents a symbolic link; otherwise, <c>false</c>.
  120. /// </value>
  121. public bool IsSymbolicLink { get; private set; }
  122. /// <summary>
  123. /// Gets a value indicating whether file represents a regular file.
  124. /// </summary>
  125. /// <value>
  126. /// <c>true</c> if file represents a regular file; otherwise, <c>false</c>.
  127. /// </value>
  128. public bool IsRegularFile { get; private set; }
  129. /// <summary>
  130. /// Gets a value indicating whether file represents a block device.
  131. /// </summary>
  132. /// <value>
  133. /// <c>true</c> if file represents a block device; otherwise, <c>false</c>.
  134. /// </value>
  135. public bool IsBlockDevice { get; private set; }
  136. /// <summary>
  137. /// Gets a value indicating whether file represents a directory.
  138. /// </summary>
  139. /// <value>
  140. /// <c>true</c> if file represents a directory; otherwise, <c>false</c>.
  141. /// </value>
  142. public bool IsDirectory { get; private set; }
  143. /// <summary>
  144. /// Gets a value indicating whether file represents a character device.
  145. /// </summary>
  146. /// <value>
  147. /// <c>true</c> if file represents a character device; otherwise, <c>false</c>.
  148. /// </value>
  149. public bool IsCharacterDevice { get; private set; }
  150. /// <summary>
  151. /// Gets a value indicating whether file represents a named pipe.
  152. /// </summary>
  153. /// <value>
  154. /// <c>true</c> if file represents a named pipe; otherwise, <c>false</c>.
  155. /// </value>
  156. public bool IsNamedPipe { get; private set; }
  157. /// <summary>
  158. /// Gets a value indicating whether the owner can read from this file.
  159. /// </summary>
  160. /// <value>
  161. /// <c>true</c> if owner can read from this file; otherwise, <c>false</c>.
  162. /// </value>
  163. public bool OwnerCanRead { get; set; }
  164. /// <summary>
  165. /// Gets a value indicating whether the owner can write into this file.
  166. /// </summary>
  167. /// <value>
  168. /// <c>true</c> if owner can write into this file; otherwise, <c>false</c>.
  169. /// </value>
  170. public bool OwnerCanWrite { get; set; }
  171. /// <summary>
  172. /// Gets a value indicating whether the owner can execute this file.
  173. /// </summary>
  174. /// <value>
  175. /// <c>true</c> if owner can execute this file; otherwise, <c>false</c>.
  176. /// </value>
  177. public bool OwnerCanExecute { get; set; }
  178. /// <summary>
  179. /// Gets a value indicating whether the group members can read from this file.
  180. /// </summary>
  181. /// <value>
  182. /// <c>true</c> if group members can read from this file; otherwise, <c>false</c>.
  183. /// </value>
  184. public bool GroupCanRead { get; set; }
  185. /// <summary>
  186. /// Gets a value indicating whether the group members can write into this file.
  187. /// </summary>
  188. /// <value>
  189. /// <c>true</c> if group members can write into this file; otherwise, <c>false</c>.
  190. /// </value>
  191. public bool GroupCanWrite { get; set; }
  192. /// <summary>
  193. /// Gets a value indicating whether the group members can execute this file.
  194. /// </summary>
  195. /// <value>
  196. /// <c>true</c> if group members can execute this file; otherwise, <c>false</c>.
  197. /// </value>
  198. public bool GroupCanExecute { get; set; }
  199. /// <summary>
  200. /// Gets a value indicating whether the others can read from this file.
  201. /// </summary>
  202. /// <value>
  203. /// <c>true</c> if others can read from this file; otherwise, <c>false</c>.
  204. /// </value>
  205. public bool OthersCanRead { get; set; }
  206. /// <summary>
  207. /// Gets a value indicating whether the others can write into this file.
  208. /// </summary>
  209. /// <value>
  210. /// <c>true</c> if others can write into this file; otherwise, <c>false</c>.
  211. /// </value>
  212. public bool OthersCanWrite { get; set; }
  213. /// <summary>
  214. /// Gets a value indicating whether the others can execute this file.
  215. /// </summary>
  216. /// <value>
  217. /// <c>true</c> if others can execute this file; otherwise, <c>false</c>.
  218. /// </value>
  219. public bool OthersCanExecute { get; set; }
  220. /// <summary>
  221. /// Gets or sets the extensions.
  222. /// </summary>
  223. /// <value>
  224. /// The extensions.
  225. /// </value>
  226. public IDictionary<string, string> Extensions { get; private set; }
  227. internal uint Permissions
  228. {
  229. get
  230. {
  231. uint permission = 0;
  232. if (this._isBitFiledsBitSet)
  233. permission = permission | S_IFMT;
  234. if (this.IsSocket)
  235. permission = permission | S_IFSOCK;
  236. if (this.IsSymbolicLink)
  237. permission = permission | S_IFLNK;
  238. if (this.IsRegularFile)
  239. permission = permission | S_IFREG;
  240. if (this.IsBlockDevice)
  241. permission = permission | S_IFBLK;
  242. if (this.IsDirectory)
  243. permission = permission | S_IFDIR;
  244. if (this.IsCharacterDevice)
  245. permission = permission | S_IFCHR;
  246. if (this.IsNamedPipe)
  247. permission = permission | S_IFIFO;
  248. if (this._isUIDBitSet)
  249. permission = permission | S_ISUID;
  250. if (this._isGroupIDBitSet)
  251. permission = permission | S_ISGID;
  252. if (this._isStickyBitSet)
  253. permission = permission | S_ISVTX;
  254. if (this.OwnerCanRead)
  255. permission = permission | S_IRUSR;
  256. if (this.OwnerCanWrite)
  257. permission = permission | S_IWUSR;
  258. if (this.OwnerCanExecute)
  259. permission = permission | S_IXUSR;
  260. if (this.GroupCanRead)
  261. permission = permission | S_IRGRP;
  262. if (this.GroupCanWrite)
  263. permission = permission | S_IWGRP;
  264. if (this.GroupCanExecute)
  265. permission = permission | S_IXGRP;
  266. if (this.OthersCanRead)
  267. permission = permission | S_IROTH;
  268. if (this.OthersCanWrite)
  269. permission = permission | S_IWOTH;
  270. if (this.OthersCanExecute)
  271. permission = permission | S_IXOTH;
  272. return permission;
  273. }
  274. private set
  275. {
  276. this._isBitFiledsBitSet = ((value & S_IFMT) == S_IFMT);
  277. this.IsSocket = ((value & S_IFSOCK) == S_IFSOCK);
  278. this.IsSymbolicLink = ((value & S_IFLNK) == S_IFLNK);
  279. this.IsRegularFile = ((value & S_IFREG) == S_IFREG);
  280. this.IsBlockDevice = ((value & S_IFBLK) == S_IFBLK);
  281. this.IsDirectory = ((value & S_IFDIR) == S_IFDIR);
  282. this.IsCharacterDevice = ((value & S_IFCHR) == S_IFCHR);
  283. this.IsNamedPipe = ((value & S_IFIFO) == S_IFIFO);
  284. this._isUIDBitSet = ((value & S_ISUID) == S_ISUID);
  285. this._isGroupIDBitSet = ((value & S_ISGID) == S_ISGID);
  286. this._isStickyBitSet = ((value & S_ISVTX) == S_ISVTX);
  287. this.OwnerCanRead = ((value & S_IRUSR) == S_IRUSR);
  288. this.OwnerCanWrite = ((value & S_IWUSR) == S_IWUSR);
  289. this.OwnerCanExecute = ((value & S_IXUSR) == S_IXUSR);
  290. this.GroupCanRead = ((value & S_IRGRP) == S_IRGRP);
  291. this.GroupCanWrite = ((value & S_IWGRP) == S_IWGRP);
  292. this.GroupCanExecute = ((value & S_IXGRP) == S_IXGRP);
  293. this.OthersCanRead = ((value & S_IROTH) == S_IROTH);
  294. this.OthersCanWrite = ((value & S_IWOTH) == S_IWOTH);
  295. this.OthersCanExecute = ((value & S_IXOTH) == S_IXOTH);
  296. }
  297. }
  298. internal SftpFileAttributes()
  299. {
  300. }
  301. internal SftpFileAttributes(DateTime lastAccessTime, DateTime lastWriteTime, long size, int userId, int groupId, uint permissions, IDictionary<string, string> extensions)
  302. {
  303. this.LastAccessTime = this._originalLastAccessTime = lastAccessTime;
  304. this.LastWriteTime = this._originalLastWriteTime = lastWriteTime;
  305. this.Size = this._originalSize = size;
  306. this.UserId = this._originalUserId = userId;
  307. this.GroupId = this._originalGroupId = groupId;
  308. this.Permissions = this._originalPermissions = permissions;
  309. this.Extensions = this._originalExtensions = extensions;
  310. }
  311. /// <summary>
  312. /// Sets the permissions.
  313. /// </summary>
  314. /// <param name="mode">The mode.</param>
  315. public void SetPermissions(short mode)
  316. {
  317. if (mode < 0 || mode > 999)
  318. {
  319. throw new ArgumentOutOfRangeException("mode");
  320. }
  321. var modeBytes = mode.ToString(CultureInfo.InvariantCulture).PadLeft(3, '0').ToArray();
  322. var permission = (modeBytes[0] & 0x0F) * 8 * 8 + (modeBytes[1] & 0x0F) * 8 + (modeBytes[2] & 0x0F);
  323. this.OwnerCanRead = (permission & S_IRUSR) == S_IRUSR;
  324. this.OwnerCanWrite = (permission & S_IWUSR) == S_IWUSR;
  325. this.OwnerCanExecute = (permission & S_IXUSR) == S_IXUSR;
  326. this.GroupCanRead = (permission & S_IRGRP) == S_IRGRP;
  327. this.GroupCanWrite = (permission & S_IWGRP) == S_IWGRP;
  328. this.GroupCanExecute = (permission & S_IXGRP) == S_IXGRP;
  329. this.OthersCanRead = (permission & S_IROTH) == S_IROTH;
  330. this.OthersCanWrite = (permission & S_IWOTH) == S_IWOTH;
  331. this.OthersCanExecute = (permission & S_IXOTH) == S_IXOTH;
  332. }
  333. }
  334. }