RawDiskImage.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using System.Text;
  11. using Utilities;
  12. namespace DiskAccessLibrary
  13. {
  14. public partial class RawDiskImage : DiskImage
  15. {
  16. const FileOptions FILE_FLAG_NO_BUFFERING = (FileOptions)0x20000000;
  17. private bool m_isExclusiveLock;
  18. private FileStream m_stream;
  19. public RawDiskImage(string rawDiskImagePath) : base(rawDiskImagePath)
  20. {
  21. }
  22. public override bool ExclusiveLock()
  23. {
  24. if (!m_isExclusiveLock)
  25. {
  26. m_isExclusiveLock = true;
  27. FileAccess fileAccess = IsReadOnly ? FileAccess.Read : FileAccess.ReadWrite;
  28. // We should use noncached I/O operations to avoid excessive RAM usage.
  29. // Note: KB99794 provides information about FILE_FLAG_WRITE_THROUGH and FILE_FLAG_NO_BUFFERING.
  30. m_stream = new FileStream(this.Path, FileMode.Open, fileAccess, FileShare.Read, 0x1000, FILE_FLAG_NO_BUFFERING | FileOptions.WriteThrough);
  31. return true;
  32. }
  33. else
  34. {
  35. return false;
  36. }
  37. }
  38. public override bool ReleaseLock()
  39. {
  40. if (m_isExclusiveLock)
  41. {
  42. m_isExclusiveLock = false;
  43. m_stream.Close();
  44. return true;
  45. }
  46. else
  47. {
  48. return false;
  49. }
  50. }
  51. /// <summary>
  52. /// Sector refers to physical disk sector, we can only read complete sectors
  53. /// </summary>
  54. public override byte[] ReadSectors(long sectorIndex, int sectorCount)
  55. {
  56. CheckBoundaries(sectorIndex, sectorCount);
  57. if (!m_isExclusiveLock)
  58. {
  59. // We should use noncached I/O operations to avoid excessive RAM usage.
  60. // Note: KB99794 provides information about FILE_FLAG_WRITE_THROUGH and FILE_FLAG_NO_BUFFERING.
  61. m_stream = new FileStream(this.Path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x1000, FILE_FLAG_NO_BUFFERING | FileOptions.WriteThrough);
  62. }
  63. long offset = sectorIndex * BytesPerSector;
  64. m_stream.Seek(offset, SeekOrigin.Begin);
  65. byte[] result = new byte[BytesPerSector * sectorCount];
  66. m_stream.Read(result, 0, BytesPerSector * sectorCount);
  67. if (!m_isExclusiveLock)
  68. {
  69. m_stream.Close();
  70. }
  71. return result;
  72. }
  73. public override void WriteSectors(long sectorIndex, byte[] data)
  74. {
  75. if (IsReadOnly)
  76. {
  77. throw new UnauthorizedAccessException("Attempted to perform write on a readonly disk");
  78. }
  79. CheckBoundaries(sectorIndex, data.Length / this.BytesPerSector);
  80. if (!m_isExclusiveLock)
  81. {
  82. // We should use noncached I/O operations to avoid excessive RAM usage.
  83. // We must avoid using buffered writes, using it will negatively affect the performance and reliability.
  84. // Note: once the file system write buffer is filled, Windows may delay any (buffer-dependent) pending write operations, which will create a deadlock.
  85. m_stream = new FileStream(this.Path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 0x1000, FILE_FLAG_NO_BUFFERING | FileOptions.WriteThrough);
  86. }
  87. long offset = sectorIndex * BytesPerSector;
  88. m_stream.Seek(offset, SeekOrigin.Begin);
  89. m_stream.Write(data, 0, data.Length);
  90. if (!m_isExclusiveLock)
  91. {
  92. m_stream.Close();
  93. }
  94. }
  95. public override void Extend(long additionalNumberOfBytes)
  96. {
  97. if (additionalNumberOfBytes % this.BytesPerSector > 0)
  98. {
  99. throw new ArgumentException("additionalNumberOfBytes must be a multiple of BytesPerSector");
  100. }
  101. long length = this.Size;
  102. if (!m_isExclusiveLock)
  103. {
  104. m_stream = new FileStream(this.Path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 0x1000, FILE_FLAG_NO_BUFFERING | FileOptions.WriteThrough);
  105. }
  106. m_stream.SetLength(length + additionalNumberOfBytes);
  107. if (m_isExclusiveLock)
  108. {
  109. m_stream.Close();
  110. }
  111. }
  112. public override int BytesPerSector
  113. {
  114. get
  115. {
  116. FileInfo info = new FileInfo(this.Path);
  117. string[] components = info.Name.Split('.');
  118. if (components.Length >= 3) // file.512.img
  119. {
  120. string bytesPerSectorString = components[components.Length - 2];
  121. int bytesPerSector = Conversion.ToInt32(bytesPerSectorString, BytesPerDiskImageSector);
  122. return bytesPerSector;
  123. }
  124. else
  125. {
  126. return BytesPerDiskImageSector;
  127. }
  128. }
  129. }
  130. public override long Size
  131. {
  132. get
  133. {
  134. FileInfo info = new FileInfo(this.Path);
  135. return info.Length;
  136. }
  137. }
  138. }
  139. }