CliProgram.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. using SvdCli.App;
  2. using SvdCli.ServiceUtils;
  3. using SvdCli.Storage;
  4. using SvdCli.WindowsService;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Management;
  10. using System.Net;
  11. using System.Reflection;
  12. using System.Security;
  13. using System.ServiceProcess;
  14. using System.Text.RegularExpressions;
  15. using SvdCli.DiskUtils;
  16. using SvdCli.Storage.Implements;
  17. namespace SvdCli
  18. {
  19. internal static class CliProgram
  20. {
  21. private static void Main(string[] args)
  22. {
  23. if (args.Length < 2)
  24. {
  25. Console.WriteLine(@"Usage:");
  26. Console.WriteLine(@"");
  27. Console.WriteLine(@"Create Raw 50GB C:\Path\To\Your\Image.img");
  28. Console.WriteLine(@"Create Bdd 10GB 64KB C:\Path\To\Your\Bdd.bdd");
  29. Console.WriteLine(@"Create Bdd 64KB C:\Path\To\Your\Image.img C:\Path\To\Your\Bdd.bdd");
  30. Console.WriteLine(@"Compact Bdd C:\Path\To\Your\Bdd.bdd");
  31. Console.WriteLine(@"");
  32. Console.WriteLine(@"[Install ServiceName|Service] <Mount|Server 0.0.0.0 2333> RamDisk 10GB");
  33. Console.WriteLine(@"[Install ServiceName|Service] <Mount|Server 0.0.0.0 2333> NtfsRamDisk 10GB");
  34. Console.WriteLine(@"[Install ServiceName|Service] <Mount|Server 0.0.0.0 2333> TempNtfsRamDisk 10GB");
  35. Console.WriteLine(@"[Install ServiceName|Service] <Mount|Server 0.0.0.0 2333> RamDisk 10GB C:\Path\To\Your\Bdd.Bdd [ReadOnly]");
  36. Console.WriteLine(@"[Install ServiceName|Service] <Mount|Server 0.0.0.0 2333> Image C:\Path\To\Your\Image.img [ReadOnly]");
  37. Console.WriteLine(@"[Install ServiceName|Service] <Mount|Server 0.0.0.0 2333> Bdd C:\Path\To\Your\Bdd.bdd [ReadOnly]");
  38. Console.WriteLine(@"[Install ServiceName|Service] Mount Net 192.168.233.233 2333");
  39. Console.WriteLine(@"[Install ServiceName|Service] Mount ZTempNtfsRamDisk 10GB");
  40. Console.WriteLine(@"[Install ServiceName|Service] Server 192.168.233.233 2333 Dispatch 64KB C:\Path\To\Your\Image.img C:\Path\To\Your\Dir\");
  41. Console.WriteLine(@"");
  42. Console.WriteLine(@"Uninstall ServiceName Safe:Restrict to register by this program");
  43. Console.WriteLine(@"");
  44. Console.Write("Press ENTER to exit...");
  45. Console.ReadLine();
  46. return;
  47. }
  48. EndPoint serverEndPoint = null;
  49. ISvdStorage storage = null;
  50. switch (args[0].ToLower())
  51. {
  52. case "install":
  53. {
  54. var serviceName = args[1];
  55. var serviceArgs = new List<string>() { Assembly.GetExecutingAssembly().Location, "Service" };
  56. serviceArgs.AddRange(args.Skip(2));
  57. ServiceHelper.Install(serviceName, "", string.Join(" ", serviceArgs), "", ServiceStartType.Auto);
  58. }
  59. break;
  60. case "uninstall":
  61. {
  62. var serviceName = args[1];
  63. var binPath = ServiceHelper.GetBinPath(serviceName);
  64. if (true == binPath?.Contains(Path.GetFileName(Assembly.GetExecutingAssembly().Location))) ServiceHelper.Uninstall(serviceName);
  65. else throw new SecurityException("Specified service must register by this program");
  66. }
  67. break;
  68. case "service":
  69. args = args.Skip(1).ToArray();
  70. switch (args[0].ToLower())
  71. {
  72. default: throw new InvalidOperationException("Invalid param: OP");
  73. case "server":
  74. serverEndPoint = new IPEndPoint(IPAddress.Parse(args[1]), int.Parse(args[2]));
  75. if (args[3].ToLower() == "dispatch")
  76. {
  77. //Start TCP Server and listening
  78. //Accept and Get Client MAC
  79. //Create Bdd If Not Exist
  80. //Serving Bdd in `forked' Process use Socket.DuplicateAndClose
  81. throw new NotImplementedException();
  82. }
  83. args = args.Skip(3).ToArray();
  84. goto case "mount";
  85. case "mount":
  86. storage = ParseMount(args.Skip(1).ToArray());
  87. break;
  88. }
  89. ServiceBase.Run(new ServiceBase[] { new SvdServiceForWindows(new SvdService(storage, serverEndPoint)) });
  90. break;
  91. default:
  92. switch (args[0].ToLower())
  93. {
  94. case "create":
  95. ParseCreate(args.Skip(1).ToArray());
  96. return;
  97. case "compact":
  98. ParseCompact(args.Skip(1).ToArray());
  99. return;
  100. case "server":
  101. serverEndPoint = new IPEndPoint(IPAddress.Parse(args[1]), int.Parse(args[2]));
  102. args = args.Skip(3).ToArray();
  103. goto case "mount";
  104. case "mount":
  105. storage = ParseMount(args.Skip(1).ToArray());
  106. break;
  107. }
  108. var svc = new SvdService(storage, serverEndPoint);
  109. svc.Start();
  110. Console.WriteLine();
  111. Console.Write("Press ENTER to Stop...");
  112. Console.ReadLine();
  113. Console.Write("Stopping...");
  114. svc.Stop();
  115. Console.Write("Stopped.");
  116. break;
  117. }
  118. }
  119. private static void ParseCreate(string[] args)
  120. {
  121. // 0 1 2 3
  122. // Bdd 10GB 64KB C:\Path\To\Your\Bdd.bdd
  123. // Bdd 64KB C:\Path\To\Your\Image.img C:\Path\To\Your\Bdd.bdd
  124. // Raw 50GB C:\Path\To\Your\Image.img
  125. if (false == ParseDiskSize(args[1], out var value1, out var unit1)) throw new ArgumentException("Failure to parse disk size");
  126. var size1 = CalcDiskSize(value1, unit1);
  127. switch (args[0].ToLower())
  128. {
  129. case "raw":
  130. if (File.Exists(args[2])) throw new IOException("File Already Exist");
  131. {
  132. using var img = File.Create(args[2]);
  133. img.SetSparse();
  134. img.SetLength(size1);
  135. }
  136. break;
  137. case "bdd":
  138. if (args.Length > 3)
  139. {
  140. if (ParseDiskSize(args[2], out var value2, out var unit2)
  141. && ".bdd" == Path.GetFileName(args[2])?.ToLower()
  142. && false == File.Exists(args[3]))
  143. {
  144. //bdd 2=size 3=bdd[not exist]
  145. var size = size1;
  146. var blockSize = CalcDiskSize(value2, unit2);
  147. throw new NotImplementedException();
  148. }
  149. if (".img" == Path.GetExtension(args[2])?.ToLower()
  150. && File.Exists(args[2])
  151. && ".bdd" == Path.GetExtension(args[3])?.ToLower()
  152. && false == File.Exists(args[3]))
  153. {
  154. //snapshot 2=img[exist] 3=bdd[not exist]
  155. var blockSize = value1;
  156. throw new NotImplementedException();
  157. }
  158. }
  159. throw new ArgumentException("Unknown bdd create action");
  160. default: throw new ArgumentException("Unknown image type");
  161. }
  162. }
  163. private static ISvdStorage ParseMount(string[] args)
  164. {
  165. // 0 1 2 3
  166. // RamDisk 10GB C:\Path\To\Your\Bdd.Bdd [ReadOnly]
  167. // RamDisk 10GB
  168. // NtfsRamDisk 10GB
  169. // TempNtfsRamDisk 10GB
  170. // Image C:\Path\To\Your\Image.img [ReadOnly]
  171. // Bdd C:\Path\To\Your\Bdd.bdd [ReadOnly]
  172. // Net 192.168.233.233 2333
  173. var op = args[0].ToLower();
  174. switch (op)
  175. {
  176. case "ramdisk":
  177. case "ntfsramdisk":
  178. case "tempntfsramdisk":
  179. case "ztempntfsramdisk":
  180. if (ParseDiskSize(args[1], out var value, out var unit))
  181. {
  182. if (false == string.IsNullOrWhiteSpace(unit) && false == unit.StartsWith("g"))
  183. throw new ArgumentException("RamDisk only GB supported");
  184. var storage = new UnmanagedGigabyteRamDisk(value);
  185. //TODO: load bdd
  186. if (args.Length > 2) throw new NotImplementedException();
  187. if (args.Length > 3 && args[3].ToLower() == "readonly") storage.WriteProtect = true;
  188. if (op == "ntfsramdisk") FsMaker.MakeNtfs(storage, "RamDisk");
  189. if (op == "tempntfsramdisk") FsMaker.MakeNtfs(storage, "RamDisk", n => n.CreateDirectory("Temp"));
  190. if (op == "ztempntfsramdisk")
  191. {
  192. var guid = Guid.NewGuid().ToString("N");
  193. FsMaker.MakeNtfs(storage, guid, n => n.CreateDirectory("Temp"));
  194. storage.Mounted += delegate
  195. {
  196. var volumes = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_Volume");
  197. foreach (ManagementObject volume in volumes.Get())
  198. {
  199. volume.Get();
  200. if (volume["Label"] is string str && str == guid)
  201. {
  202. volume["Label"] = "RamDisk";
  203. volume["DriveLetter"] = "Z:";
  204. volume.Put();
  205. break;
  206. }
  207. }
  208. };
  209. }
  210. return storage;
  211. }
  212. throw new ArgumentException("Failure to parse args");
  213. case "image":
  214. {
  215. var storage = new RawImageStorage(args[1], args.Length > 2 && "readonly" == args[2].ToLower());
  216. return storage;
  217. }
  218. case "bdd":
  219. case "net":
  220. default:
  221. throw new ArgumentOutOfRangeException();
  222. }
  223. }
  224. private static void ParseCompact(string[] args)
  225. {
  226. //Bdd C:\Path\To\Your\Bdd.bdd
  227. throw new NotImplementedException();
  228. }
  229. //////////////////////////////////////////////
  230. private static readonly Regex DiskSizeRegex = new Regex(@"^(\d+)([KkMmGg]{1}[Bb]{0,1}){0,1}$", RegexOptions.Compiled);
  231. private static bool ParseDiskSize(string input, out int value, out string unit)
  232. {
  233. var m = DiskSizeRegex.Match(input);
  234. if (false == m.Success)
  235. {
  236. value = 0;
  237. unit = null;
  238. return false;
  239. }
  240. unit = m.Groups[2].Value.ToLower();
  241. value = int.Parse(m.Groups[1].Value);
  242. return true;
  243. }
  244. private static long CalcDiskSize(int value, string unit)
  245. {
  246. switch (unit.ToLower())
  247. {
  248. //case "":
  249. // return value;
  250. case "k":
  251. case "kb":
  252. return value * CapacityUnits.KiloByte;
  253. case "m":
  254. case "mb":
  255. return value * CapacityUnits.MegaByte;
  256. case "g":
  257. case "gb":
  258. return value * CapacityUnits.Gigabyte;
  259. default: throw new ArgumentOutOfRangeException();
  260. }
  261. }
  262. }
  263. }