PageRenderTime 60ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/CoreDroid.Test.Plugin/DirectoryService.cs

http://coredroidservice.googlecode.com/
C# | 296 lines | 234 code | 60 blank | 2 comment | 91 complexity | c3f199cf0155e991f8e89348a6fc2e90 MD5 | raw file
  1. using System;
  2. using System.Linq;
  3. using CoreDroid.Contract;
  4. using System.Collections.Generic;
  5. using DiskDroid.FileSystem.Contract;
  6. using Mono.Unix.Native;
  7. using System.Text;
  8. namespace DiskDroid.FileSystem
  9. {
  10. [ServiceContract]
  11. public class DirectoryService
  12. {
  13. public static readonly DateTime UnixEpoch = new DateTime (1970, 1, 1);
  14. public static DateTime UnixToDateTime (long unix)
  15. {
  16. return UnixEpoch.Add (TimeSpan.FromSeconds (unix)).ToLocalTime ();
  17. }
  18. private Dictionary<string, FileSystemItemInfo> cache = new Dictionary<string, FileSystemItemInfo> ();
  19. private uint? currentUID = null;
  20. protected uint CurrentUID {
  21. get {
  22. if (currentUID == null) {
  23. currentUID = Syscall.getuid ();
  24. }
  25. return currentUID.Value;
  26. }
  27. }
  28. private IEnumerable<uint> currentGID = null;
  29. protected IEnumerable<uint> CurrentGID {
  30. get {
  31. if (currentGID == null) {
  32. List<uint> groupList = new List<uint> ();
  33. groupList.Add (Syscall.getgid ());
  34. uint[] buf = new uint[32];
  35. int amount = Syscall.getgroups (32, buf);
  36. uint[] ret = new uint[amount];
  37. Array.Copy (buf, ret, amount);
  38. groupList.AddRange (ret);
  39. currentGID = groupList.ToArray ();
  40. }
  41. return currentGID;
  42. }
  43. }
  44. [ServiceMember]
  45. public FileSystemItemInfo Get (string path, int lifeTime)
  46. {
  47. // fix path
  48. if (path.Length > 1 && path.EndsWith ("/"))
  49. path = path.Remove (path.Length - 1);
  50. if (this.cache.ContainsKey (path) && DateTime.UtcNow > this.cache [path].LoadTime.AddSeconds (lifeTime))
  51. this.cache.Remove (path);
  52. if (!this.cache.ContainsKey (path)) {
  53. Stat? stat = new Stat ();
  54. Stat tmpStat = new Stat ();
  55. stat = Syscall.stat (path, out tmpStat) == 0 ? tmpStat as Stat? : null;
  56. string symlinkPath = null;
  57. Stat? usingStat = new Stat ();
  58. if (stat.HasValue) {
  59. if ((stat.Value.st_mode & FilePermissions.S_IFLNK) == FilePermissions.S_IFLNK) {
  60. StringBuilder sb = new StringBuilder ();
  61. Syscall.readlink (path, sb);
  62. symlinkPath = sb.ToString ();
  63. tmpStat = new Stat ();
  64. usingStat = Syscall.stat (path, out tmpStat) == 0 ? tmpStat as Stat? : null;
  65. } else
  66. usingStat = stat;
  67. }
  68. if (usingStat != null) {
  69. this.cache.Add (path, this.CreateItem (path, usingStat.Value, symlinkPath));
  70. } else {
  71. return null;
  72. }
  73. }
  74. return cache [path];
  75. }
  76. private FileSystemItemInfo CreateItem (string path, Stat stat, string symlinkPath)
  77. {
  78. FileSystemItemInfo item = null;
  79. if ((stat.st_mode & FilePermissions.S_IFDIR) == FilePermissions.S_IFDIR) {
  80. item = new DirectoryItemInfo (path);
  81. // TODO: search for mount device
  82. } else {
  83. item = new FileItemInfo (path);
  84. ((FileItemInfo)item).Size = stat.st_size; // i know, also directories, links and whatever have a size, but I want to have the pure data size shown
  85. ((FileItemInfo)item).IsBlockDevice = (stat.st_mode & FilePermissions.S_IFBLK) == FilePermissions.S_IFBLK;
  86. ((FileItemInfo)item).IsCharacterDevice = (stat.st_mode & FilePermissions.S_IFCHR) == FilePermissions.S_IFCHR;
  87. ((FileItemInfo)item).IsSocket = (stat.st_mode & FilePermissions.S_IFSOCK) == FilePermissions.S_IFSOCK;
  88. ((FileItemInfo)item).IsFIFO = (stat.st_mode & FilePermissions.S_IFIFO) == FilePermissions.S_IFIFO;
  89. }
  90. item.LastAccessTime = UnixToDateTime (stat.st_atime);
  91. item.LastModificationTime = UnixToDateTime (stat.st_mtime);
  92. item.LastStatusChangeTime = UnixToDateTime (stat.st_ctime);
  93. item.LinkTarget = symlinkPath;
  94. item.UID = stat.st_uid;
  95. item.User = Mono.Posix.Syscall.getusername (Convert.ToInt32 (item.UID));
  96. item.GID = stat.st_gid;
  97. item.Group = Mono.Posix.Syscall.getgroupname (Convert.ToInt32 (item.GID));
  98. item.OtherMode = 0;
  99. item.GroupMode = 0;
  100. item.UserMode = 0;
  101. if ((stat.st_mode & FilePermissions.S_IXOTH) == FilePermissions.S_IXOTH)
  102. item.OtherMode = item.OtherMode | FilePermission.Execute;
  103. if ((stat.st_mode & FilePermissions.S_IWOTH) == FilePermissions.S_IWOTH)
  104. item.OtherMode = item.OtherMode | FilePermission.Write;
  105. if ((stat.st_mode & FilePermissions.S_IROTH) == FilePermissions.S_IROTH)
  106. item.OtherMode = item.OtherMode | FilePermission.Read;
  107. if ((stat.st_mode & FilePermissions.S_IXGRP) == FilePermissions.S_IXGRP)
  108. item.GroupMode = item.GroupMode | FilePermission.Execute;
  109. if ((stat.st_mode & FilePermissions.S_IWGRP) == FilePermissions.S_IWGRP)
  110. item.GroupMode = item.GroupMode | FilePermission.Write;
  111. if ((stat.st_mode & FilePermissions.S_IRGRP) == FilePermissions.S_IRGRP)
  112. item.GroupMode = item.GroupMode | FilePermission.Read;
  113. if ((stat.st_mode & FilePermissions.S_IXUSR) == FilePermissions.S_IXUSR)
  114. item.UserMode = item.UserMode | FilePermission.Execute;
  115. if ((stat.st_mode & FilePermissions.S_IWUSR) == FilePermissions.S_IWUSR)
  116. item.UserMode = item.UserMode | FilePermission.Write;
  117. if ((stat.st_mode & FilePermissions.S_IRUSR) == FilePermissions.S_IRUSR)
  118. item.UserMode = item.UserMode | FilePermission.Read;
  119. item.UIDBit = (stat.st_mode & FilePermissions.S_ISUID) == FilePermissions.S_ISUID;
  120. item.GIDBit = (stat.st_mode & FilePermissions.S_ISGID) == FilePermissions.S_ISGID;
  121. item.StickyBit = (stat.st_mode & FilePermissions.S_ISVTX) == FilePermissions.S_ISVTX;
  122. return item;
  123. }
  124. [ServiceMember]
  125. public IEnumerable<FileSystemItemInfo> GetContents (DirectoryItemInfo directory, int lifeTime)
  126. {
  127. directory = this.Reload<DirectoryItemInfo> (directory);
  128. if (!directory.CanRead () && directory.CanExecute ())
  129. throw(new AccessViolationException ("you are not allowed to read and execute <" + directory.Path + ">"));
  130. List<FileSystemItemInfo> items = new List<FileSystemItemInfo> ();
  131. items.AddRange (System.IO.Directory.GetDirectories (directory.Path).OrderBy (d => d).Select (d => this.Get (d, lifeTime)));
  132. items.AddRange (System.IO.Directory.GetFiles (directory.Path).OrderBy (f => f).Select (f => this.Get (f, lifeTime)));
  133. return items.AsEnumerable ();
  134. }
  135. public void Copy (FileSystemItemInfo source, DirectoryItemInfo target)
  136. {
  137. source = this.Reload<FileSystemItemInfo> (source);
  138. target = this.Reload<DirectoryItemInfo> (target);
  139. if (!source.CanCopy () && target.CanWrite ())
  140. throw(new AccessViolationException ("you are not allowed to copy <" + source.Path + ">"));
  141. if (!(source is FileItemInfo) && string.IsNullOrEmpty (source.LinkTarget))
  142. throw(new ArgumentException ("can only copy files and symbolic links, recursive operations are not supported by directory service"));
  143. if (string.IsNullOrEmpty (source.LinkTarget)) {
  144. System.IO.File.Copy (source.Path, System.IO.Path.Combine (target.Path, source.Name));
  145. } else {
  146. Syscall.symlink (source.LinkTarget, System.IO.Path.Combine (target.Path, source.Name));
  147. }
  148. }
  149. public void Move (FileSystemItemInfo source, DirectoryItemInfo target)
  150. {
  151. source = this.Reload<FileSystemItemInfo> (source);
  152. target = this.Reload<DirectoryItemInfo> (target);
  153. if (!source.CanMove () && target.CanWrite ())
  154. throw(new AccessViolationException ("you are not allowed to move <" + source.Path + ">"));
  155. if (!(source is FileItemInfo) && string.IsNullOrEmpty (source.LinkTarget))
  156. throw(new ArgumentException ("can only copy files and symbolic links, recursive operations are not supported by directory service"));
  157. if (string.IsNullOrEmpty (source.LinkTarget)) {
  158. System.IO.File.Move (source.Path, System.IO.Path.Combine (target.Path, source.Name));
  159. } else {
  160. Syscall.symlink (source.LinkTarget, System.IO.Path.Combine (target.Path, source.Name));
  161. this.Delete (source);
  162. }
  163. }
  164. public void Delete (FileSystemItemInfo item)
  165. {
  166. item = this.Reload<FileSystemItemInfo> (item);
  167. if (!item.CanDelete ())
  168. throw(new AccessViolationException ("you are not allowed to move <" + item.Path + ">"));
  169. if (item is DirectoryItemInfo && string.IsNullOrEmpty (item.LinkTarget)) {
  170. System.IO.Directory.Delete (item.Path);
  171. } else {
  172. Syscall.unlink (item.Path);
  173. }
  174. item.SetExpired ();
  175. }
  176. public void ChangeOwner (FileSystemItemInfo item, uint newUID, uint newGID)
  177. {
  178. item = this.Reload< FileSystemItemInfo> (item);
  179. if (!item.CanChange ())
  180. throw(new AccessViolationException ("you are not allowed to change <" + item.Path + ">"));
  181. Syscall.chown (item.Path, newUID, newGID);
  182. item.SetExpired ();
  183. }
  184. public void ChangePermissions (FileSystemItemInfo item, FilePermission userMode, FilePermission groupMode, FilePermission otherMode, bool uidBit, bool gidBit, bool stickyBit)
  185. {
  186. item = this.Reload< FileSystemItemInfo> (item);
  187. if (!item.CanChange ())
  188. throw(new AccessViolationException ("you are not allowed to change <" + item.Path + ">"));
  189. Stat? stat = new Stat ();
  190. Stat tmpStat = new Stat ();
  191. stat = Syscall.stat (item.Path, out tmpStat) == 0 ? tmpStat as Stat? : null;
  192. if (stat.HasValue) {
  193. FilePermissions mode = stat.Value.st_mode;
  194. mode = mode ^ FilePermissions.S_IXOTH ^ FilePermissions.S_IWOTH ^ FilePermissions.S_IROTH;
  195. mode = mode ^ FilePermissions.S_IXGRP ^ FilePermissions.S_IWGRP ^ FilePermissions.S_IRGRP;
  196. mode = mode ^ FilePermissions.S_IXUSR ^ FilePermissions.S_IWUSR ^ FilePermissions.S_IRUSR;
  197. mode = mode ^ FilePermissions.S_ISUID ^ FilePermissions.S_ISGID ^ FilePermissions.S_ISVTX;
  198. if ((otherMode & FilePermission.Execute) == FilePermission.Execute)
  199. mode = mode | FilePermissions.S_IXOTH;
  200. if ((otherMode & FilePermission.Write) == FilePermission.Write)
  201. mode = mode | FilePermissions.S_IWOTH;
  202. if ((otherMode & FilePermission.Read) == FilePermission.Read)
  203. mode = mode | FilePermissions.S_IROTH;
  204. if ((groupMode & FilePermission.Execute) == FilePermission.Execute)
  205. mode = mode | FilePermissions.S_IXGRP;
  206. if ((groupMode & FilePermission.Write) == FilePermission.Write)
  207. mode = mode | FilePermissions.S_IWGRP;
  208. if ((groupMode & FilePermission.Read) == FilePermission.Read)
  209. mode = mode | FilePermissions.S_IRGRP;
  210. if ((userMode & FilePermission.Execute) == FilePermission.Execute)
  211. mode = mode | FilePermissions.S_IXUSR;
  212. if ((userMode & FilePermission.Write) == FilePermission.Write)
  213. mode = mode | FilePermissions.S_IWUSR;
  214. if ((userMode & FilePermission.Read) == FilePermission.Read)
  215. mode = mode | FilePermissions.S_IRUSR;
  216. if (uidBit)
  217. mode = mode | FilePermissions.S_ISUID;
  218. if (gidBit)
  219. mode = mode | FilePermissions.S_ISGID;
  220. if (stickyBit)
  221. mode = mode | FilePermissions.S_ISVTX;
  222. Syscall.chmod (item.Path, mode);
  223. item.SetExpired ();
  224. } else {
  225. throw(new ArgumentException ("<" + item.Path + "> is not more existing or accessable"));
  226. }
  227. }
  228. private T Reload<T> (T item) where T : FileSystemItemInfo
  229. {
  230. item = this.Get (item.Path, 0) as T;
  231. if (item == null)
  232. throw(new ArgumentException ("<" + item.Path + "> is not more existing or accessable"));
  233. return item;
  234. }
  235. }
  236. }