VHDFooter.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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.Text;
  10. using Utilities;
  11. namespace DiskAccessLibrary.VHD
  12. {
  13. public class VHDFooter
  14. {
  15. public const int Length = 512;
  16. public const string VirtualHardDiskCookie = "conectix";
  17. public string Cookie; // 8 bytes
  18. public uint Features = 0x2;
  19. public uint FileFormatVersion;
  20. public ulong DataOffset; // The documentation says 0xFFFFFFFF, but all programs use 0xFFFFFFFFFFFFFFFF
  21. public uint TimeStamp; // Number of seconds since January 1, 2000 12:00:00 AM in UTC
  22. public string CreatorApplication;
  23. public uint CreatorVersion;
  24. public uint CreatorHostOS; // Windows
  25. public ulong OriginalSize;
  26. public ulong CurrentSize;
  27. public uint DiskGeometry;
  28. public VirtualHardDiskType DiskType;
  29. //public uint Checksum;
  30. public Guid UniqueId;
  31. public byte SavedState;
  32. private bool m_isValid = true;
  33. public VHDFooter()
  34. {
  35. Cookie = VirtualHardDiskCookie;
  36. FileFormatVersion = 0x00010000;
  37. DataOffset = 0xFFFFFFFFFFFFFFFF;
  38. CreatorApplication = "DXSL"; // Disk Access Library
  39. CreatorHostOS = 0x5769326B;
  40. DiskType = VirtualHardDiskType.Fixed;
  41. UniqueId = Guid.NewGuid();
  42. }
  43. public VHDFooter(byte[] buffer)
  44. {
  45. Cookie = ByteReader.ReadAnsiString(buffer, 0x00, 8);
  46. Features = BigEndianConverter.ToUInt32(buffer, 0x08);
  47. FileFormatVersion = BigEndianConverter.ToUInt32(buffer, 0x0C);
  48. DataOffset = BigEndianConverter.ToUInt64(buffer, 0x10);
  49. TimeStamp = BigEndianConverter.ToUInt32(buffer, 0x18);
  50. CreatorApplication = ByteReader.ReadAnsiString(buffer, 0x1C, 4);
  51. CreatorVersion = BigEndianConverter.ToUInt32(buffer, 0x20);
  52. CreatorHostOS = BigEndianConverter.ToUInt32(buffer, 0x24);
  53. OriginalSize = BigEndianConverter.ToUInt64(buffer, 0x28);
  54. CurrentSize = BigEndianConverter.ToUInt64(buffer, 0x30);
  55. DiskGeometry = BigEndianConverter.ToUInt32(buffer, 0x38);
  56. DiskType = (VirtualHardDiskType)BigEndianConverter.ToUInt32(buffer, 0x3C);
  57. uint checksum = BigEndianConverter.ToUInt32(buffer, 0x40);
  58. UniqueId = BigEndianConverter.ToGuid(buffer, 0x44);
  59. SavedState = ByteReader.ReadByte(buffer, 0x54);
  60. byte[] temp = (byte[])buffer.Clone();
  61. BigEndianWriter.WriteInt32(temp, 0x40, 0);
  62. uint expectedChecksum = CalculateChecksum(temp);
  63. m_isValid = String.Equals(Cookie, VirtualHardDiskCookie) && (checksum == expectedChecksum) && (FileFormatVersion == 0x00010000);
  64. }
  65. public void SetCurrentTimeStamp()
  66. {
  67. TimeSpan since2000 = DateTime.UtcNow - new DateTime(2000, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
  68. TimeStamp = (uint)since2000.TotalSeconds;
  69. }
  70. public void SetDiskGeometry(ulong totalSectors)
  71. {
  72. byte heads;
  73. byte sectorsPerTrack;
  74. ushort cylinders;
  75. VirtualHardDisk.GetDiskGeometry(totalSectors, out heads, out sectorsPerTrack, out cylinders);
  76. DiskGeometry = (uint)cylinders << 16;
  77. DiskGeometry |= (uint)heads << 8;
  78. DiskGeometry |= sectorsPerTrack;
  79. }
  80. public byte[] GetBytes()
  81. {
  82. byte[] buffer = new byte[Length];
  83. ByteWriter.WriteAnsiString(buffer, 0x00, Cookie, 8);
  84. BigEndianWriter.WriteUInt32(buffer, 0x08, Features);
  85. BigEndianWriter.WriteUInt32(buffer, 0x0C, FileFormatVersion);
  86. BigEndianWriter.WriteUInt64(buffer, 0x10, DataOffset);
  87. BigEndianWriter.WriteUInt32(buffer, 0x18, TimeStamp);
  88. ByteWriter.WriteAnsiString(buffer, 0x1C, CreatorApplication, 4);
  89. BigEndianWriter.WriteUInt32(buffer, 0x20, CreatorVersion);
  90. BigEndianWriter.WriteUInt32(buffer, 0x24, CreatorHostOS);
  91. BigEndianWriter.WriteUInt64(buffer, 0x28, OriginalSize);
  92. BigEndianWriter.WriteUInt64(buffer, 0x30, CurrentSize);
  93. BigEndianWriter.WriteUInt32(buffer, 0x38, DiskGeometry);
  94. BigEndianWriter.WriteUInt32(buffer, 0x3C, (uint)DiskType);
  95. // We'll write the checksum later
  96. BigEndianWriter.WriteGuidBytes(buffer, 0x44, UniqueId);
  97. ByteWriter.WriteByte(buffer, 0x54, SavedState);
  98. uint checksum = CalculateChecksum(buffer);
  99. BigEndianWriter.WriteUInt32(buffer, 0x40, checksum);
  100. return buffer;
  101. }
  102. public bool IsValid
  103. {
  104. get
  105. {
  106. return m_isValid;
  107. }
  108. }
  109. public static uint CalculateChecksum(byte[] buffer)
  110. {
  111. uint checksum = 0;
  112. for (int index = 0; index < Length; index++)
  113. {
  114. checksum += buffer[index];
  115. }
  116. checksum = ~checksum;
  117. return checksum;
  118. }
  119. }
  120. }