VirtualMachineDisk.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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. using DiskAccessLibrary.VMDK;
  13. namespace DiskAccessLibrary
  14. {
  15. public partial class VirtualMachineDisk : DiskImage, IDiskGeometry
  16. {
  17. private const uint BaseDiskParentCID = 0xffffffff;
  18. private string m_descriptorPath;
  19. private VirtualMachineDiskDescriptor m_descriptor;
  20. private DiskImage m_extent;
  21. /// <exception cref="System.IO.IOException"></exception>
  22. /// <exception cref="System.IO.InvalidDataException"></exception>
  23. /// <exception cref="System.NotImplementedException"></exception>
  24. /// <exception cref="System.UnauthorizedAccessException"></exception>
  25. public VirtualMachineDisk(string descriptorPath) : base(descriptorPath)
  26. {
  27. m_descriptorPath = descriptorPath;
  28. m_descriptor = VirtualMachineDiskDescriptor.ReadFromFile(m_descriptorPath);
  29. bool isDescriptorEmbedded = false;
  30. if (m_descriptor == null)
  31. {
  32. SparseExtent sparse = new SparseExtent(m_descriptorPath);
  33. if (sparse.Descriptor != null)
  34. {
  35. isDescriptorEmbedded = true;
  36. m_descriptor = sparse.Descriptor;
  37. m_extent = sparse;
  38. }
  39. else
  40. {
  41. throw new InvalidDataException("Missing VMDK descriptor");
  42. }
  43. }
  44. if (m_descriptor.Version != 1)
  45. {
  46. throw new NotImplementedException("Unsupported VMDK descriptor version");
  47. }
  48. if (m_descriptor.ParentContentID != BaseDiskParentCID)
  49. {
  50. throw new InvalidDataException("VMDK descriptor ParentContentID does not match BaseDiskParentCID");
  51. }
  52. if (!isDescriptorEmbedded && m_descriptor.DiskType != VirtualMachineDiskType.MonolithicFlat)
  53. {
  54. throw new NotImplementedException("Unsupported VMDK disk type");
  55. }
  56. if (isDescriptorEmbedded && m_descriptor.DiskType != VirtualMachineDiskType.MonolithicSparse)
  57. {
  58. throw new NotImplementedException("Unsupported VMDK disk type");
  59. }
  60. foreach (VirtualMachineDiskExtentEntry extentEntry in m_descriptor.ExtentEntries)
  61. {
  62. if (!isDescriptorEmbedded && extentEntry.ExtentType != ExtentType.Flat)
  63. {
  64. throw new NotImplementedException("Unsupported VMDK extent type");
  65. }
  66. if (isDescriptorEmbedded && extentEntry.ExtentType != ExtentType.Sparse)
  67. {
  68. throw new NotImplementedException("Unsupported VMDK extent type");
  69. }
  70. }
  71. if (m_descriptor.ExtentEntries.Count != 1)
  72. {
  73. throw new NotImplementedException("Unsupported number of VMDK extents");
  74. }
  75. if (m_descriptor.DiskType == VirtualMachineDiskType.MonolithicFlat)
  76. {
  77. VirtualMachineDiskExtentEntry entry = m_descriptor.ExtentEntries[0];
  78. string directory = System.IO.Path.GetDirectoryName(descriptorPath);
  79. DiskImage extent = new RawDiskImage(directory + @"\" + entry.FileName);
  80. m_extent = extent;
  81. }
  82. }
  83. public override bool ExclusiveLock()
  84. {
  85. return m_extent.ExclusiveLock();
  86. }
  87. public override bool ReleaseLock()
  88. {
  89. return m_extent.ReleaseLock();
  90. }
  91. public override byte[] ReadSectors(long sectorIndex, int sectorCount)
  92. {
  93. return m_extent.ReadSectors(sectorIndex, sectorCount);
  94. }
  95. public override void WriteSectors(long sectorIndex, byte[] data)
  96. {
  97. if (IsReadOnly)
  98. {
  99. throw new UnauthorizedAccessException("Attempted to perform write on a readonly disk");
  100. }
  101. m_extent.WriteSectors(sectorIndex, data);
  102. }
  103. public override void Extend(long additionalNumberOfBytes)
  104. {
  105. if (m_descriptor.DiskType == VirtualMachineDiskType.MonolithicFlat)
  106. {
  107. // Add updated extent entries
  108. List<string> lines = VirtualMachineDiskDescriptor.ReadASCIITextLines(m_descriptorPath);
  109. m_descriptor.ExtentEntries[0].SizeInSectors += additionalNumberOfBytes / this.BytesPerSector;
  110. m_descriptor.UpdateExtentEntries(lines);
  111. File.WriteAllLines(m_descriptorPath, lines.ToArray(), Encoding.ASCII);
  112. ((DiskImage)m_extent).Extend(additionalNumberOfBytes);
  113. }
  114. else
  115. {
  116. throw new NotImplementedException("Extending a monolithic sparse is not supported");
  117. }
  118. }
  119. public override int BytesPerSector
  120. {
  121. get
  122. {
  123. return DiskImage.BytesPerDiskImageSector;
  124. }
  125. }
  126. public override long Size
  127. {
  128. get
  129. {
  130. return m_extent.Size;
  131. }
  132. }
  133. public long Cylinders
  134. {
  135. get
  136. {
  137. return m_descriptor.Cylinders;
  138. }
  139. }
  140. public int TracksPerCylinder
  141. {
  142. get
  143. {
  144. return m_descriptor.TracksPerCylinder;
  145. }
  146. }
  147. public int SectorsPerTrack
  148. {
  149. get
  150. {
  151. return m_descriptor.SectorsPerTrack;
  152. }
  153. }
  154. }
  155. }