VirtualMachineDisk.cs 5.6 KB

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