FilePermissions.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using System;
  2. using System.Globalization;
  3. using System.Runtime.InteropServices;
  4. namespace WinSCP
  5. {
  6. [Guid("90A290B2-C8CE-4900-8C42-7736F9E435C6")]
  7. [ClassInterface(Constants.ClassInterface)]
  8. [ComVisible(true)]
  9. public sealed class FilePermissions
  10. {
  11. public int Numeric
  12. {
  13. get
  14. {
  15. return _numeric;
  16. }
  17. set
  18. {
  19. if (_readOnly)
  20. {
  21. throw new InvalidOperationException("Cannot change read-only permissions");
  22. }
  23. if ((value < 0) || (value > 0xFFF))
  24. {
  25. throw new ArgumentOutOfRangeException(string.Format(CultureInfo.CurrentCulture, "{0} is not valid numerical permissions", value));
  26. }
  27. _numeric = value;
  28. }
  29. }
  30. public string Text
  31. {
  32. get
  33. {
  34. return NumericToText(Numeric);
  35. }
  36. set
  37. {
  38. Numeric = TextToNumeric(value);
  39. }
  40. }
  41. public string Octal
  42. {
  43. get
  44. {
  45. string result = Convert.ToString(Numeric, 8);
  46. return new string('0', Math.Max(3 - result.Length, 0)) + result;
  47. }
  48. set
  49. {
  50. if ((value == null) || ((value.Length != 3) && (value.Length != 4)))
  51. {
  52. throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "{0} is not valid octal permissions", value));
  53. }
  54. Numeric = Convert.ToInt16(value, 8);
  55. }
  56. }
  57. public bool OtherExecute
  58. {
  59. get { return GetBit(0); }
  60. set { SetBit(0, value); }
  61. }
  62. public bool OtherWrite
  63. {
  64. get { return GetBit(1); }
  65. set { SetBit(1, value); }
  66. }
  67. public bool OtherRead
  68. {
  69. get { return GetBit(2); }
  70. set { SetBit(2, value); }
  71. }
  72. public bool GroupExecute
  73. {
  74. get { return GetBit(3); }
  75. set { SetBit(3, value); }
  76. }
  77. public bool GroupWrite
  78. {
  79. get { return GetBit(4); }
  80. set { SetBit(4, value); }
  81. }
  82. public bool GroupRead
  83. {
  84. get { return GetBit(5); }
  85. set { SetBit(5, value); }
  86. }
  87. public bool UserExecute
  88. {
  89. get { return GetBit(6); }
  90. set { SetBit(6, value); }
  91. }
  92. public bool UserWrite
  93. {
  94. get { return GetBit(7); }
  95. set { SetBit(7, value); }
  96. }
  97. public bool UserRead
  98. {
  99. get { return GetBit(8); }
  100. set { SetBit(8, value); }
  101. }
  102. public bool Sticky
  103. {
  104. get { return GetBit(9); }
  105. set { SetBit(9, value); }
  106. }
  107. public bool SetGid
  108. {
  109. get { return GetBit(10); }
  110. set { SetBit(10, value); }
  111. }
  112. public bool SetUid
  113. {
  114. get { return GetBit(11); }
  115. set { SetBit(11, value); }
  116. }
  117. public FilePermissions() :
  118. this(0)
  119. {
  120. }
  121. public FilePermissions(int numeric)
  122. {
  123. Numeric = numeric;
  124. }
  125. public override string ToString()
  126. {
  127. return Text;
  128. }
  129. private const string BasicSymbols = "rwxrwxrwx";
  130. private const string CombinedSymbols = "--s--s--t";
  131. private const string ExtendedSymbols = "--S--S--T";
  132. private const char UnsetSymbol = '-';
  133. internal static FilePermissions CreateReadOnlyFromText(string text)
  134. {
  135. FilePermissions result = new FilePermissions();
  136. result.Numeric = TextToNumeric(text);
  137. result._readOnly = true;
  138. return result;
  139. }
  140. internal static int TextToNumeric(string text)
  141. {
  142. if (text.Length != BasicSymbols.Length)
  143. {
  144. throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "{0} is not valid permissions string", text));
  145. }
  146. int result = 0;
  147. int flag = 1;
  148. int extendedFlag = 0x200;
  149. for (int i = text.Length - 1; i >= 0; i--)
  150. {
  151. if (text[i] == UnsetSymbol)
  152. {
  153. // noop
  154. }
  155. else if (text[i] == CombinedSymbols[i])
  156. {
  157. result |= flag | extendedFlag;
  158. }
  159. else if (text[i] == ExtendedSymbols[i])
  160. {
  161. result |= extendedFlag;
  162. }
  163. else
  164. {
  165. result |= flag;
  166. }
  167. flag <<= 1;
  168. if (i % 3 == 0)
  169. {
  170. extendedFlag <<= 1;
  171. }
  172. }
  173. return result;
  174. }
  175. private static string NumericToText(int numeric)
  176. {
  177. char[] buf = new char[BasicSymbols.Length];
  178. int flag = 1;
  179. int extendedFlag = 0x200;
  180. bool extendedPos = true;
  181. int i = BasicSymbols.Length - 1;
  182. while (i >= 0)
  183. {
  184. char symbol;
  185. if (extendedPos &&
  186. ((numeric & (flag | extendedFlag)) == (flag | extendedFlag)))
  187. {
  188. symbol = CombinedSymbols[i];
  189. }
  190. else if ((numeric & flag) != 0)
  191. {
  192. symbol = BasicSymbols[i];
  193. }
  194. else if (extendedPos && ((numeric & extendedFlag) != 0))
  195. {
  196. symbol = ExtendedSymbols[i];
  197. }
  198. else
  199. {
  200. symbol = UnsetSymbol;
  201. }
  202. buf[i] = symbol;
  203. flag <<= 1;
  204. i--;
  205. extendedPos = ((i % 3) == 2);
  206. if (extendedPos)
  207. {
  208. extendedFlag <<= 1;
  209. }
  210. }
  211. return new string(buf);
  212. }
  213. private bool GetBit(int bit)
  214. {
  215. return (Numeric & (1 << bit)) != 0;
  216. }
  217. private void SetBit(int bit, bool value)
  218. {
  219. if (value)
  220. {
  221. Numeric |= (1 << bit);
  222. }
  223. else
  224. {
  225. Numeric &= ~(1 << bit);
  226. }
  227. }
  228. private int _numeric;
  229. private bool _readOnly;
  230. }
  231. }