RamStorage.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace SvdCli.Storage.Implements
  4. {
  5. public class UnmanagedGigabyteRamDisk : ISvdStorage
  6. {
  7. private readonly IntPtr[] _blocks;
  8. private bool _isInit;
  9. public string ProductId { get; } = "Svd RamDisk";
  10. public string ProductVersion { get; } = "1.0";
  11. public uint BlockSize { get; } = 512;
  12. public ulong BlockCount { get; }
  13. public uint MaxTransferLength { get; } = 64 * CapacityUnits.KiloByte;
  14. public bool SupportTrim { get; } = false;
  15. public bool WriteProtect { get; set; }
  16. public Guid Guid { get; } = Guid.NewGuid();
  17. public event EventHandler Mounted;
  18. public UnmanagedGigabyteRamDisk(int sizeInGigabyte)
  19. {
  20. _blocks = new IntPtr[sizeInGigabyte];
  21. var size = (ulong)sizeInGigabyte * CapacityUnits.Gigabyte;
  22. BlockCount = size / BlockSize;
  23. }
  24. public void Init()
  25. {
  26. if (_isInit) return;
  27. try
  28. {
  29. for (var i = 0; i < _blocks.Length; i++)
  30. {
  31. _blocks[i] = Marshal.AllocHGlobal(CapacityUnits.Gigabyte);
  32. }
  33. _isInit = true;
  34. }
  35. catch (OutOfMemoryException)
  36. {
  37. Exit();
  38. throw;
  39. }
  40. }
  41. public void Exit()
  42. {
  43. foreach (var block in _blocks)
  44. {
  45. if (block != IntPtr.Zero) Marshal.FreeHGlobal(block);
  46. }
  47. GC.Collect();
  48. GC.WaitForPendingFinalizers();
  49. _isInit = false;
  50. }
  51. private void ReadInternal(byte[] buffer, int offset, int count, int gigabyteIndex, int gigabyteOffset)
  52. {
  53. Marshal.Copy(_blocks[gigabyteIndex] + gigabyteOffset, buffer, offset, count);
  54. }
  55. private void WriteInternal(byte[] buffer, int offset, int count, int gigabyteIndex, int gigabyteOffset)
  56. {
  57. Marshal.Copy(buffer, offset, _blocks[gigabyteIndex] + gigabyteOffset, count);
  58. }
  59. public void ReadBlocks(byte[] buffer, ulong blockIndex, uint blockCount)
  60. {
  61. var rawOffset = blockIndex * BlockSize;
  62. var rawSize = blockCount * BlockSize;
  63. for (var i = 0; i < rawSize;)
  64. {
  65. var gigabyteIndex = (int)(rawOffset / CapacityUnits.Gigabyte);
  66. var gigabyteOffset = (int)(rawOffset % CapacityUnits.Gigabyte);
  67. var bytesToRead = CapacityUnits.Gigabyte - gigabyteOffset;
  68. if (i + bytesToRead > rawSize)
  69. {
  70. bytesToRead = (int)(rawSize - i);
  71. }
  72. ReadInternal(buffer, i, bytesToRead, gigabyteIndex, gigabyteOffset);
  73. i += bytesToRead;
  74. rawOffset += (ulong)bytesToRead;
  75. }
  76. }
  77. public void WriteBlocks(byte[] buffer, ulong blockIndex, uint blockCount)
  78. {
  79. var rawOffset = blockIndex * BlockSize;
  80. var rawSize = (int)(blockCount * BlockSize);
  81. for (var i = 0; i < rawSize;)
  82. {
  83. var gigabyteIndex = (int)(rawOffset / CapacityUnits.Gigabyte);
  84. var gigabyteOffset = (int)(rawOffset % CapacityUnits.Gigabyte);
  85. var bytesToWrite = CapacityUnits.Gigabyte - gigabyteOffset;
  86. if (i + bytesToWrite > rawSize)
  87. {
  88. bytesToWrite = rawSize - i;
  89. }
  90. WriteInternal(buffer, i, bytesToWrite, gigabyteIndex, gigabyteOffset);
  91. i += bytesToWrite;
  92. rawOffset += (ulong)bytesToWrite;
  93. }
  94. }
  95. public int Read(byte[] buffer, long offset, int index, int count)
  96. {
  97. for (var i = 0; i < count;)
  98. {
  99. var gigabyteIndex = (int)(offset / CapacityUnits.Gigabyte);
  100. var gigabyteOffset = (int)(offset % CapacityUnits.Gigabyte);
  101. var bytesToRead = CapacityUnits.Gigabyte - gigabyteOffset;
  102. if (i + bytesToRead > count)
  103. {
  104. bytesToRead = (count - i);
  105. }
  106. ReadInternal(buffer, i, bytesToRead, gigabyteIndex, gigabyteOffset);
  107. i += bytesToRead;
  108. offset += bytesToRead;
  109. }
  110. return count;
  111. }
  112. public void Write(byte[] buffer, long offset, int index, int count)
  113. {
  114. for (var i = 0; i < count;)
  115. {
  116. var gigabyteIndex = (int)(offset / CapacityUnits.Gigabyte);
  117. var gigabyteOffset = (int)(offset % CapacityUnits.Gigabyte);
  118. var bytesToWrite = CapacityUnits.Gigabyte - gigabyteOffset;
  119. if (i + bytesToWrite > count)
  120. {
  121. bytesToWrite = count - i;
  122. }
  123. WriteInternal(buffer, i, bytesToWrite, gigabyteIndex, gigabyteOffset);
  124. i += bytesToWrite;
  125. offset += bytesToWrite;
  126. }
  127. }
  128. public void Flush()
  129. {
  130. }
  131. public void Trim(params TrimDescriptor[] descriptors)
  132. {
  133. }
  134. public void FireMountedEvent()
  135. {
  136. Mounted?.Invoke(this, EventArgs.Empty);
  137. }
  138. }
  139. }