FilePermissions.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. {
  137. Numeric = TextToNumeric(text),
  138. _readOnly = true
  139. };
  140. return result;
  141. }
  142. internal static int TextToNumeric(string text)
  143. {
  144. if (text.Length != BasicSymbols.Length)
  145. {
  146. throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "{0} is not valid permissions string", text));
  147. }
  148. int result = 0;
  149. int flag = 1;
  150. int extendedFlag = 0x200;
  151. for (int i = text.Length - 1; i >= 0; i--)
  152. {
  153. if (text[i] == UnsetSymbol)
  154. {
  155. // noop
  156. }
  157. else if (text[i] == CombinedSymbols[i])
  158. {
  159. result |= flag | extendedFlag;
  160. }
  161. else if (text[i] == ExtendedSymbols[i])
  162. {
  163. result |= extendedFlag;
  164. }
  165. else
  166. {
  167. result |= flag;
  168. }
  169. flag <<= 1;
  170. if (i % 3 == 0)
  171. {
  172. extendedFlag <<= 1;
  173. }
  174. }
  175. return result;
  176. }
  177. private static string NumericToText(int numeric)
  178. {
  179. char[] buf = new char[BasicSymbols.Length];
  180. int flag = 1;
  181. int extendedFlag = 0x200;
  182. bool extendedPos = true;
  183. int i = BasicSymbols.Length - 1;
  184. while (i >= 0)
  185. {
  186. char symbol;
  187. if (extendedPos &&
  188. ((numeric & (flag | extendedFlag)) == (flag | extendedFlag)))
  189. {
  190. symbol = CombinedSymbols[i];
  191. }
  192. else if ((numeric & flag) != 0)
  193. {
  194. symbol = BasicSymbols[i];
  195. }
  196. else if (extendedPos && ((numeric & extendedFlag) != 0))
  197. {
  198. symbol = ExtendedSymbols[i];
  199. }
  200. else
  201. {
  202. symbol = UnsetSymbol;
  203. }
  204. buf[i] = symbol;
  205. flag <<= 1;
  206. i--;
  207. extendedPos = ((i % 3) == 2);
  208. if (extendedPos)
  209. {
  210. extendedFlag <<= 1;
  211. }
  212. }
  213. return new string(buf);
  214. }
  215. private bool GetBit(int bit)
  216. {
  217. return (Numeric & (1 << bit)) != 0;
  218. }
  219. private void SetBit(int bit, bool value)
  220. {
  221. if (value)
  222. {
  223. Numeric |= (1 << bit);
  224. }
  225. else
  226. {
  227. Numeric &= ~(1 << bit);
  228. }
  229. }
  230. private int _numeric;
  231. private bool _readOnly;
  232. }
  233. }