/3.x/WBFSe3/IO/WbfsDriveInfo.cs

# · C# · 465 lines · 292 code · 84 blank · 89 comment · 53 complexity · ab67143841d8dd70fd6b34621037d448 MD5 · raw file

  1. //-----------------------------------------------------------------------------------------------------------
  2. // WBFSSync Project by Omega Frost
  3. // http://wbfssync.codeplex.com/
  4. //
  5. // WBFSSync is Licensed under the terms of the
  6. // Microsoft Reciprocal License (Ms-RL)
  7. //-----------------------------------------------------------------------------------------------------------
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Text;
  12. using System.IO;
  13. using WBFSe3.Native;
  14. using System.Runtime.InteropServices;
  15. using WBFSe3.Wbfs;
  16. namespace WBFSe3.IO
  17. {
  18. //-------------------------------------------------------------------------------------------------------
  19. //
  20. //-------------------------------------------------------------------------------------------------------
  21. public delegate void DriveUpdatedDelegate(WbfsDriveInfo sender, WbfsError error);
  22. public delegate void DriveClosedDelegate(WbfsDriveInfo sender);
  23. //-------------------------------------------------------------------------------------------------------
  24. //
  25. //-------------------------------------------------------------------------------------------------------
  26. public class WbfsDriveInfo : FileSystemInfo
  27. {
  28. //---------------------------------------------------------------------------------------------------
  29. //
  30. //---------------------------------------------------------------------------------------------------
  31. private static HashSet<uint> FatWbfsDrives = new HashSet<uint>();
  32. private static WbfsDriveInfo[] Drives = new WbfsDriveInfo[26];
  33. //---------------------------------------------------------------------------------------------------
  34. //
  35. //---------------------------------------------------------------------------------------------------
  36. protected String name;
  37. protected String label;
  38. protected uint serial;
  39. protected bool largeFiles;
  40. protected long size;
  41. protected long used;
  42. protected long free;
  43. protected bool isReadOnly;
  44. protected bool isSparse;
  45. protected bool isFixed;
  46. protected bool isCd;
  47. protected bool isWbfs;
  48. protected bool isFatWbfs;
  49. protected bool isReady;
  50. protected bool isGame;
  51. protected int error;
  52. //---------------------------------------------------------------------------------------------------
  53. //
  54. //---------------------------------------------------------------------------------------------------
  55. public event DriveUpdatedDelegate DriveUpdated;
  56. public event DriveClosedDelegate DriveClosed;
  57. //---------------------------------------------------------------------------------------------------
  58. //
  59. //---------------------------------------------------------------------------------------------------
  60. public override String Name { get { return this.name; } }
  61. public override string FullName { get { return this.name; } }
  62. public String Label { get { return this.label; } set { SetLabel(value); } }
  63. public uint Serial { get { return this.serial; } }
  64. public Boolean LargeFiles { get { return this.largeFiles; } }
  65. public long Size { get { lock (this) { ParseSpace(); } return this.size; } }
  66. public long Used { get { lock (this) { ParseSpace(); } return this.used; } }
  67. public long Free { get { lock (this) { ParseSpace(); } return this.free; } }
  68. public Boolean IsReadOnly { get { return this.isReadOnly; } }
  69. public Boolean IsFatWbfs { get { return FatWbfsDrives.Contains(this.serial); } set { SetFatWbfs(value); } }
  70. public Boolean IsSparse { get { return this.isSparse; } }
  71. public Boolean IsFixed { get { return this.isFixed; } }
  72. public Boolean IsWbfs { get { return this.isWbfs; } }
  73. public Boolean IsCd { get { return this.isCd; } }
  74. public Boolean IsReady { get { return this.isReady; } }
  75. public Boolean IsGame { get { return this.isGame; } }
  76. public override bool Exists { get { return true; } }
  77. public Boolean IsValid { get { return this.error != 0; } }
  78. public int Error { get { return this.error; } }
  79. //---------------------------------------------------------------------------------------------------
  80. //
  81. //---------------------------------------------------------------------------------------------------
  82. public static void AddFatWbfsSN(uint sn)
  83. {
  84. if (!FatWbfsDrives.Contains(sn))
  85. FatWbfsDrives.Add(sn);
  86. }
  87. //---------------------------------------------------------------------------------------------------
  88. //
  89. //---------------------------------------------------------------------------------------------------
  90. public static uint[] GetFatWbfsSNs()
  91. {
  92. return FatWbfsDrives.ToArray();
  93. }
  94. //---------------------------------------------------------------------------------------------------
  95. //
  96. //---------------------------------------------------------------------------------------------------
  97. public static WbfsError GetDrive(String path, out WbfsDriveInfo drive)
  98. {
  99. WbfsDriveInfo di;
  100. char letter;
  101. int error;
  102. drive = null;
  103. // Path verification
  104. if (String.IsNullOrEmpty(path))
  105. return WbfsError.DriveNotFound;
  106. // Get the drive letter
  107. letter = Path.GetFullPath(path).ToUpper()[0];
  108. // Return already created file
  109. di = Drives[(int)(letter - 'A')];
  110. if (di != null)
  111. {
  112. if ((error = (int)di.Update()) != 0)
  113. {
  114. drive = di;
  115. Drives[(int)(letter - 'A')] = null;
  116. return (WbfsError)error;
  117. }
  118. drive = di;
  119. return WbfsError.Ok;
  120. }
  121. // Create new instance of a drive info
  122. di = new WbfsDriveInfo();
  123. di.name = letter + ":\\";
  124. // Is drive type supported?
  125. if (di.ParseType() != 0)
  126. return WbfsError.DriveNotSupported;
  127. // Check for a known filesystem
  128. if ((error = di.ParseVolume()) == 0)
  129. {
  130. //Calculate space
  131. if ((error = di.ParseSpace()) != 0)
  132. return (WbfsError)error;
  133. }
  134. else if (!di.isCd) //CD Drives just sucks...
  135. {
  136. if (error == 1005)
  137. {
  138. //Maybe wbfs drive or game
  139. if (di.isCd)
  140. {
  141. if (di.isReady)
  142. {
  143. //Try build the DVD as a game
  144. }
  145. }
  146. else
  147. {
  148. //Try open a wbfs device
  149. WbfsDevice wdi;
  150. error = (int)WbfsDevice.Open(di.name,
  151. FileAccess.ReadWrite, false, out wdi);
  152. if (error == 0)
  153. {
  154. di = wdi;
  155. }
  156. }
  157. }
  158. else if (error != 21)
  159. {
  160. return (WbfsError)error;
  161. }
  162. }
  163. Drives[(int)(letter - 'A')] = di;
  164. drive = di;
  165. return WbfsError.Ok;
  166. }
  167. //---------------------------------------------------------------------------------------------------
  168. //
  169. //---------------------------------------------------------------------------------------------------
  170. internal static void InvalidateDrive(Char drive)
  171. {
  172. int old = (int)(Char.ToUpper(drive) - 'A');
  173. Drives[old].OnDriveClosed();
  174. Drives[old] = null;
  175. }
  176. //---------------------------------------------------------------------------------------------------
  177. //
  178. //---------------------------------------------------------------------------------------------------
  179. internal static void UpdateDrive(WbfsDriveInfo drive)
  180. {
  181. int old = (int)(Char.ToUpper(drive.name[0]) - 'A');
  182. drive.DriveClosed = Drives[old].DriveClosed;
  183. drive.DriveUpdated = Drives[old].DriveUpdated;
  184. Drives[old] = drive;
  185. drive.OnDriveUpdated(WbfsError.DriveReplace);
  186. }
  187. //---------------------------------------------------------------------------------------------------
  188. //
  189. //---------------------------------------------------------------------------------------------------
  190. protected int ParseType()
  191. {
  192. // Get the drive type
  193. uint type = WbfsNative.GetDriveType(this.name);
  194. switch (type)
  195. {
  196. case 2: //Removable
  197. this.isFixed = false;
  198. this.isCd = false;
  199. break;
  200. case 3: //Fixed
  201. this.isFixed = true;
  202. this.isCd = false;
  203. break;
  204. case 5: //CD
  205. this.isFixed = true;
  206. this.isCd = true;
  207. break;
  208. default: //Not Supported
  209. return -1;
  210. }
  211. return 0;
  212. }
  213. //---------------------------------------------------------------------------------------------------
  214. //
  215. //---------------------------------------------------------------------------------------------------
  216. private int ParseVolume()
  217. {
  218. // Get the volume information
  219. EFileSystemFeature volFeatures;
  220. StringBuilder volName = new StringBuilder(261);
  221. StringBuilder volFs = new StringBuilder(261);
  222. uint volSn;
  223. uint volMaxFile;
  224. this.isReady = WbfsNative.GetVolumeInformation(this.name, volName,
  225. 261, out volSn, out volMaxFile, out volFeatures, volFs, 261);
  226. if (this.isReady)
  227. {
  228. this.serial = volSn;
  229. this.label = volName.ToString();
  230. this.isSparse = volFeatures.HasFlag(EFileSystemFeature.SupportsSparseFiles);
  231. this.isReadOnly = volFeatures.HasFlag(EFileSystemFeature.ReadOnlyVolume);
  232. if ((volName.ToString() == "FAT32") || (volName.ToString() == "FAT"))
  233. this.largeFiles = false;
  234. else this.largeFiles = true;
  235. return 0;
  236. }
  237. else
  238. {
  239. return Marshal.GetLastWin32Error();
  240. }
  241. }
  242. //---------------------------------------------------------------------------------------------------
  243. //
  244. //---------------------------------------------------------------------------------------------------
  245. protected virtual int ParseSpace()
  246. {
  247. if (!this.isReady)
  248. return 0;
  249. ulong volFree, volTotal, volDummy;
  250. if (!WbfsNative.GetDiskFreeSpaceEx(this.name,
  251. out volFree, out volTotal, out volDummy))
  252. {
  253. return Marshal.GetLastWin32Error();
  254. }
  255. this.size = (long)volTotal;
  256. this.free = (long)volFree;
  257. this.used = (long)(volTotal - volFree);
  258. return 0;
  259. }
  260. //---------------------------------------------------------------------------------------------------
  261. //
  262. //---------------------------------------------------------------------------------------------------
  263. protected WbfsDriveInfo()
  264. {
  265. this.name = null;
  266. this.label = null;
  267. this.serial = 0;
  268. this.size = 0;
  269. this.used = 0;
  270. this.free = 0;
  271. this.isReadOnly = false;
  272. this.isSparse = false;
  273. this.isFixed = false;
  274. this.isCd = false;
  275. this.isWbfs = false;
  276. this.isFatWbfs = false;
  277. this.isReady = false;
  278. this.isGame = false;
  279. }
  280. //---------------------------------------------------------------------------------------------------
  281. //
  282. //---------------------------------------------------------------------------------------------------
  283. protected virtual void SetLabel(String value)
  284. {
  285. if (!WbfsNative.SetVolumeLabel(this.name, value))
  286. {
  287. int error = Marshal.GetLastWin32Error();
  288. switch (error)
  289. {
  290. default: throw new WbfsIOException(error);
  291. case 5: throw new UnauthorizedAccessException();
  292. }
  293. }
  294. else
  295. {
  296. this.label = value;
  297. }
  298. }
  299. //---------------------------------------------------------------------------------------------------
  300. //
  301. //---------------------------------------------------------------------------------------------------
  302. protected void SetFatWbfs(Boolean value)
  303. {
  304. if (this.isWbfs || this.isCd || !this.isReady)
  305. return;
  306. lock (FatWbfsDrives)
  307. {
  308. if (value) FatWbfsDrives.Add(this.serial);
  309. else FatWbfsDrives.Remove(this.serial);
  310. }
  311. }
  312. //---------------------------------------------------------------------------------------------------
  313. //
  314. //---------------------------------------------------------------------------------------------------
  315. public virtual WbfsError Update()
  316. {
  317. int error;
  318. lock (this)
  319. {
  320. if ((error = ParseVolume()) == 0)
  321. error = ParseSpace();
  322. }
  323. OnDriveUpdated((WbfsError)error);
  324. if (error != 0)
  325. {
  326. if (this.isCd || (error == 21) || (error == 1005))
  327. {
  328. this.isReady = false;
  329. return WbfsError.Ok;
  330. }
  331. else
  332. {
  333. OnDriveClosed();
  334. Drives[(int)(this.name[0] - 'A')] = null;
  335. }
  336. }
  337. else
  338. {
  339. this.isReady = true;
  340. }
  341. return (WbfsError)error;
  342. }
  343. //---------------------------------------------------------------------------------------------------
  344. //
  345. //---------------------------------------------------------------------------------------------------
  346. public new void Refresh()
  347. {
  348. Update();
  349. }
  350. //---------------------------------------------------------------------------------------------------
  351. //
  352. //---------------------------------------------------------------------------------------------------
  353. public virtual WbfsError Close()
  354. {
  355. return WbfsError.Ok;
  356. }
  357. //---------------------------------------------------------------------------------------------------
  358. //
  359. //---------------------------------------------------------------------------------------------------
  360. public override void Delete()
  361. {
  362. // Nops
  363. }
  364. //---------------------------------------------------------------------------------------------------
  365. //
  366. //---------------------------------------------------------------------------------------------------
  367. protected void OnDriveUpdated(WbfsError error)
  368. {
  369. if (this.DriveUpdated != null)
  370. this.DriveUpdated(this, error);
  371. }
  372. //---------------------------------------------------------------------------------------------------
  373. //
  374. //---------------------------------------------------------------------------------------------------
  375. protected void OnDriveClosed()
  376. {
  377. if (this.DriveClosed != null)
  378. this.DriveClosed(this);
  379. }
  380. }
  381. }