ExtentRecord.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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. [Flags]
  14. public enum ExtentFlags : uint
  15. {
  16. Recover = 0x0008,
  17. KDetach = 0x0010,
  18. Relocate = 0x0020,
  19. BootExtended = 0x0040,
  20. OrigBoot = 0x0100,
  21. Volatile = 0x1000,
  22. }
  23. // a.k.a. subdisk
  24. public class ExtentRecord : DatabaseRecord
  25. {
  26. public ExtentFlags ExtentFlags;
  27. public ulong CommitTransactionID;
  28. public ulong DiskOffsetLBA; // extent location relative to DataStartLBA (from the private header)
  29. public ulong OffsetInColumnLBA; // the location of this extent in the column (for single column volumes this means the offset in the volume)
  30. public ulong SizeLBA; // PaddedVarUlong
  31. public ulong ComponentId;
  32. public ulong DiskId;
  33. public uint ColumnIndex; // On Striped / RAID-5 volumes, this is the interleave order, note that column can be comprised of one or more extents
  34. public ulong UnknownTransactionID;
  35. public uint Unknown1;
  36. public ulong HiddenCount; // PaddedVarUlong, Hidden sectors?
  37. public ExtentRecord()
  38. {
  39. this.RecordRevision = 3;
  40. this.RecordType = RecordType.Extent;
  41. }
  42. public ExtentRecord(List<DatabaseRecordFragment> fragments) : base(fragments)
  43. {
  44. // Data begins at 0x10 (VBLK header is at 0x00)
  45. int offset = 0x00; // relative to Data
  46. ReadCommonFields(this.Data, ref offset);
  47. if (RecordRevision != 3)
  48. {
  49. throw new NotImplementedException("Unsupported record revision");
  50. }
  51. ExtentFlags = (ExtentFlags)BigEndianReader.ReadUInt32(this.Data, ref offset);
  52. CommitTransactionID = BigEndianReader.ReadUInt64(this.Data, ref offset);
  53. DiskOffsetLBA = BigEndianReader.ReadUInt64(this.Data, ref offset);
  54. OffsetInColumnLBA = BigEndianReader.ReadUInt64(this.Data, ref offset);
  55. SizeLBA = ReadVarULong(this.Data, ref offset);
  56. ComponentId = ReadVarULong(this.Data, ref offset);
  57. DiskId = ReadVarULong(this.Data, ref offset);
  58. if (HasColumnIndexFlag)
  59. {
  60. ColumnIndex = ReadVarUInt(this.Data, ref offset);
  61. }
  62. if (HasUnknownTransactionIDFlag)
  63. {
  64. UnknownTransactionID = BigEndianReader.ReadUInt64(this.Data, ref offset);
  65. }
  66. if (HasUnknown1Flag)
  67. {
  68. Unknown1 = ReadVarUInt(this.Data, ref offset);
  69. }
  70. if (HasHiddenFlag)
  71. {
  72. HiddenCount = ReadVarULong(this.Data, ref offset);
  73. }
  74. }
  75. public override byte[] GetDataBytes()
  76. {
  77. int dataLength = 36; // fixed length components
  78. dataLength += VarULongSize(ExtentId);
  79. dataLength += Name.Length + 1;
  80. dataLength += PaddedVarULongSize(SizeLBA);
  81. dataLength += VarULongSize(ComponentId);
  82. dataLength += VarULongSize(DiskId);
  83. if (HasColumnIndexFlag)
  84. {
  85. dataLength += VarULongSize(ColumnIndex);
  86. }
  87. if (HasUnknownTransactionIDFlag)
  88. {
  89. dataLength += 8;
  90. }
  91. if (HasUnknown1Flag)
  92. {
  93. dataLength += VarULongSize(Unknown1);
  94. }
  95. if (HasHiddenFlag)
  96. {
  97. dataLength += PaddedVarULongSize(HiddenCount);
  98. }
  99. byte[] data = new byte[dataLength];
  100. int offset = 0x00;
  101. WriteCommonFields(data, ref offset);
  102. BigEndianWriter.WriteUInt32(data, ref offset, (uint)ExtentFlags);
  103. BigEndianWriter.WriteUInt64(data, ref offset, CommitTransactionID);
  104. BigEndianWriter.WriteUInt64(data, ref offset, DiskOffsetLBA);
  105. BigEndianWriter.WriteUInt64(data, ref offset, OffsetInColumnLBA);
  106. WritePaddedVarULong(data, ref offset, SizeLBA);
  107. WriteVarULong(data, ref offset, ComponentId);
  108. WriteVarULong(data, ref offset, DiskId);
  109. if (HasColumnIndexFlag)
  110. {
  111. WriteVarUInt(data, ref offset, ColumnIndex);
  112. }
  113. if (HasUnknownTransactionIDFlag)
  114. {
  115. BigEndianWriter.WriteUInt64(data, ref offset, UnknownTransactionID);
  116. }
  117. if (HasUnknown1Flag)
  118. {
  119. WriteVarUInt(data, ref offset, Unknown1);
  120. }
  121. if (HasHiddenFlag)
  122. {
  123. WritePaddedVarULong(data, ref offset, HiddenCount);
  124. }
  125. return data;
  126. }
  127. public ulong ExtentId
  128. {
  129. get
  130. {
  131. return this.Id;
  132. }
  133. }
  134. /// <summary>
  135. /// Hidden sectors?
  136. /// </summary>
  137. public bool HasHiddenFlag
  138. {
  139. get
  140. {
  141. return ((Flags & 0x02) != 0);
  142. }
  143. }
  144. public bool HasColumnIndexFlag
  145. {
  146. get
  147. {
  148. return ((Flags & 0x08) != 0);
  149. }
  150. set
  151. {
  152. if (value)
  153. {
  154. this.Flags = 0x08;
  155. }
  156. else
  157. {
  158. this.Flags &= 0xF7;
  159. }
  160. }
  161. }
  162. public bool HasUnknownTransactionIDFlag
  163. {
  164. get
  165. {
  166. return ((Flags & 0x20) != 0);
  167. }
  168. }
  169. /// <summary>
  170. /// Windows Vista and newer set this flag by default, earlier versions do not
  171. /// </summary>
  172. public bool HasUnknown1Flag
  173. {
  174. get
  175. {
  176. return ((Flags & 0x40) != 0);
  177. }
  178. }
  179. }
  180. }