VolumeManagerDatabaseHeader.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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.LogicalDiskManager
  12. {
  13. public class VolumeManagerDatabaseHeader // VMDB
  14. {
  15. public const int Length = 512;
  16. public const string VolumeManagerDatabaseSignature = "VMDB";
  17. public string Signature = VolumeManagerDatabaseSignature;
  18. public uint NumberOfVBlks; // Number of VBLK blocks in the database (This number includes the VMDB, which counts as 4 blocks)
  19. public uint BlockSize; // VBLK block size
  20. public uint HeaderSize;
  21. public DatabaseHeaderUpdateStatus UpdateStatus;
  22. // Versions: 4.10 for Windows XP \ Server 2003 \ Windows 7 \ Server 2008
  23. // 4.10 for Veritas Storage Foundation 4.0 (Windows Disk Management compatible group checked)
  24. // 4.12 for Veritas Storage Foundation 4.0 (Windows Disk Management compatible group unchecked)
  25. public ushort MajorVersion;
  26. public ushort MinorVersion;
  27. public string DiskGroupName = String.Empty;
  28. public string DiskGroupGuidString = String.Empty;
  29. public ulong CommitTransactionID; // ID of last commit transaction
  30. public ulong PendingTransactionID; // ID of transaction to be committed (should be equal to CommitTransactionID unless an update is taking place)
  31. public uint CommittedTotalNumberOfVolumeRecords; // Total number of Volume records already committed (before pending changes)
  32. public uint CommittedTotalNumberOfComponentRecords; // see above
  33. public uint CommittedTotalNumberOfExtentRecords; // see above
  34. public uint CommittedTotalNumberOfDiskRecords; // see above
  35. public uint CommittedTotalNumberOfDiskAccessRecords; // DMDiag reports this as nda (number of 'da', which use to represents disk access records in other Veritas products)
  36. // Unused 8 bytes
  37. public uint PendingTotalNumberOfVolumeRecords; // Total number of Volume records after pending changes
  38. public uint PendingTotalNumberOfComponentRecords; // see above
  39. public uint PendingTotalNumberOfExtentRecords; // see above
  40. public uint PendingTotalNumberOfDiskRecords; // see above
  41. public uint PendingTotalNumberOfDiskAccessRecords; // see above
  42. // Unused 8 bytes
  43. public DateTime LastModificationDT;
  44. public VolumeManagerDatabaseHeader(byte[] buffer)
  45. {
  46. Signature = ByteReader.ReadAnsiString(buffer, 0x00, 4);
  47. NumberOfVBlks = BigEndianConverter.ToUInt32(buffer, 0x04);
  48. BlockSize = BigEndianConverter.ToUInt32(buffer, 0x08);
  49. HeaderSize = BigEndianConverter.ToUInt32(buffer, 0x0C);
  50. UpdateStatus = (DatabaseHeaderUpdateStatus)BigEndianConverter.ToUInt16(buffer, 0x10);
  51. MajorVersion = BigEndianConverter.ToUInt16(buffer, 0x12);
  52. MinorVersion = BigEndianConverter.ToUInt16(buffer, 0x14);
  53. DiskGroupName = ByteReader.ReadAnsiString(buffer, 0x16, 31).Trim('\0');
  54. DiskGroupGuidString = ByteReader.ReadAnsiString(buffer, 0x35, 64).Trim('\0');
  55. CommitTransactionID = BigEndianConverter.ToUInt64(buffer, 0x75);
  56. PendingTransactionID = BigEndianConverter.ToUInt64(buffer, 0x7D);
  57. CommittedTotalNumberOfVolumeRecords = BigEndianConverter.ToUInt32(buffer, 0x85);
  58. CommittedTotalNumberOfComponentRecords = BigEndianConverter.ToUInt32(buffer, 0x89);
  59. CommittedTotalNumberOfExtentRecords = BigEndianConverter.ToUInt32(buffer, 0x8D);
  60. CommittedTotalNumberOfDiskRecords = BigEndianConverter.ToUInt32(buffer, 0x91);
  61. CommittedTotalNumberOfDiskAccessRecords = BigEndianConverter.ToUInt32(buffer, 0x95);
  62. // Unused 8 bytes
  63. PendingTotalNumberOfVolumeRecords = BigEndianConverter.ToUInt32(buffer, 0xA1);
  64. PendingTotalNumberOfComponentRecords = BigEndianConverter.ToUInt32(buffer, 0xA5);
  65. PendingTotalNumberOfExtentRecords = BigEndianConverter.ToUInt32(buffer, 0xA9);
  66. PendingTotalNumberOfDiskRecords = BigEndianConverter.ToUInt32(buffer, 0xAD);
  67. PendingTotalNumberOfDiskAccessRecords = BigEndianConverter.ToUInt32(buffer, 0xB1);
  68. // Unused 8 bytes
  69. LastModificationDT = DateTime.FromFileTimeUtc(BigEndianConverter.ToInt64(buffer, 0xBD));
  70. }
  71. /// <summary>
  72. /// VBLKs may reside in the same sector as the VMDB header.
  73. /// </summary>
  74. public byte[] GetBytes()
  75. {
  76. byte[] buffer = new byte[Length];
  77. ByteWriter.WriteAnsiString(buffer, 0x00, Signature, 4);
  78. BigEndianWriter.WriteUInt32(buffer, 0x04, NumberOfVBlks);
  79. BigEndianWriter.WriteUInt32(buffer, 0x08, BlockSize);
  80. BigEndianWriter.WriteUInt32(buffer, 0x0C, HeaderSize);
  81. BigEndianWriter.WriteUInt16(buffer, 0x10, (ushort)UpdateStatus);
  82. BigEndianWriter.WriteUInt16(buffer, 0x12, MajorVersion);
  83. BigEndianWriter.WriteUInt16(buffer, 0x14, MinorVersion);
  84. ByteWriter.WriteAnsiString(buffer, 0x16, DiskGroupName, 31);
  85. ByteWriter.WriteAnsiString(buffer, 0x35, DiskGroupGuidString, 64);
  86. BigEndianWriter.WriteUInt64(buffer, 0x75, CommitTransactionID);
  87. BigEndianWriter.WriteUInt64(buffer, 0x7D, PendingTransactionID);
  88. BigEndianWriter.WriteUInt32(buffer, 0x85, CommittedTotalNumberOfVolumeRecords);
  89. BigEndianWriter.WriteUInt32(buffer, 0x89, CommittedTotalNumberOfComponentRecords);
  90. BigEndianWriter.WriteUInt32(buffer, 0x8D, CommittedTotalNumberOfExtentRecords);
  91. BigEndianWriter.WriteUInt32(buffer, 0x91, CommittedTotalNumberOfDiskRecords);
  92. BigEndianWriter.WriteUInt32(buffer, 0x95, CommittedTotalNumberOfDiskAccessRecords);
  93. BigEndianWriter.WriteUInt32(buffer, 0xA1, PendingTotalNumberOfVolumeRecords);
  94. BigEndianWriter.WriteUInt32(buffer, 0xA5, PendingTotalNumberOfComponentRecords);
  95. BigEndianWriter.WriteUInt32(buffer, 0xA9, PendingTotalNumberOfExtentRecords);
  96. BigEndianWriter.WriteUInt32(buffer, 0xAD, PendingTotalNumberOfDiskRecords);
  97. BigEndianWriter.WriteUInt32(buffer, 0xB1, PendingTotalNumberOfDiskAccessRecords);
  98. BigEndianWriter.WriteInt64(buffer, 0xBD, LastModificationDT.ToFileTimeUtc());
  99. return buffer;
  100. }
  101. public Guid DiskGroupGuid
  102. {
  103. get
  104. {
  105. return new Guid(DiskGroupGuidString);
  106. }
  107. set
  108. {
  109. DiskGroupGuidString = value.ToString();
  110. }
  111. }
  112. public static VolumeManagerDatabaseHeader ReadFromDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock)
  113. {
  114. ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart;
  115. byte[] sector = disk.ReadSector((long)sectorIndex);
  116. string signature = ByteReader.ReadAnsiString(sector, 0x00, 4);
  117. if (signature == VolumeManagerDatabaseSignature)
  118. {
  119. return new VolumeManagerDatabaseHeader(sector);
  120. }
  121. else
  122. {
  123. return null;
  124. }
  125. }
  126. public static void WriteToDisk(DynamicDisk disk, VolumeManagerDatabaseHeader header)
  127. {
  128. WriteToDisk(disk.Disk, disk.PrivateHeader, disk.TOCBlock, header);
  129. }
  130. public static void WriteToDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock, VolumeManagerDatabaseHeader header)
  131. {
  132. ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart;
  133. byte[] headerBytes = header.GetBytes();
  134. if (disk.BytesPerSector > Length)
  135. {
  136. byte[] sectorBytes = disk.ReadSector((long)sectorIndex);
  137. ByteWriter.WriteBytes(sectorBytes, 0, headerBytes);
  138. disk.WriteSectors((long)sectorIndex, sectorBytes);
  139. }
  140. else
  141. {
  142. disk.WriteSectors((long)sectorIndex, headerBytes);
  143. }
  144. }
  145. }
  146. }