NTFSBootRecord.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* Copyright (C) 2014-2016 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.FileSystems.NTFS
  12. {
  13. public class NTFSBootRecord
  14. {
  15. public const string ValidSignature = "NTFS ";
  16. public byte[] Jump = new byte[3];
  17. public string OEMID = String.Empty;
  18. // BIOS parameter block:
  19. public ushort BytesPerSector = 512; // provides default until actual values are read
  20. public byte SectorsPerCluster = 8; // provides default until actual values are read
  21. // public ushort ReservedSectors // always 0
  22. // public byte NumberOfFATs // always 0
  23. // public ushort MaxRootDirectoryEntries // always 0 for NTFS
  24. // public ushort SmallSectorsCount // always 0 for NTFS
  25. public byte MediaDescriptor = 0xF8; // always F8 (Fixed Disk)
  26. // public ushort SectorsPerFAT // always 0 for NTFS
  27. public ushort SectorsPerTrack;
  28. public ushort NumberOfHeads;
  29. public uint NumberOfHiddenSectors; // Offset to the start of the partition relative to the disk in sectors
  30. //public uint LargeSectorsCount; // always 0 for NTFS
  31. // Extended BIOS parameter block:
  32. public byte PhysicalDriveNumber = 0x80; // 0x00 floppy, 0x80 hard disk
  33. // public byte CurrentHead; // always 0
  34. public byte ExtendedBootSignature = 0x80; // always set to 0x80
  35. public ulong TotalSectors; // Excluding backup boot sector at the end of the volume.
  36. public ulong MftStartLCN;
  37. public ulong MftMirrorStartLCN;
  38. public sbyte RawClustersPerFileRecordSegment; // signed
  39. public sbyte RawClustersPerIndexBlock; // signed
  40. public ulong VolumeSerialNumber;
  41. public uint Checksum;
  42. public byte[] Code = new byte[428]; // 512 - 0x54
  43. /// <summary>
  44. /// boot record is the first sector of the partition (not to be confused with the master boot record which is the first sector of the disk)
  45. /// </summary>
  46. public NTFSBootRecord(byte[] buffer)
  47. {
  48. Array.Copy(buffer, 0x00, Jump, 0, 3);
  49. OEMID = ASCIIEncoding.ASCII.GetString(buffer, 0x03, 8);
  50. BytesPerSector = LittleEndianConverter.ToUInt16(buffer, 0x0B);
  51. SectorsPerCluster = buffer[0x0D];
  52. MediaDescriptor = buffer[0x15];
  53. SectorsPerTrack = LittleEndianConverter.ToUInt16(buffer, 0x18);
  54. NumberOfHeads = LittleEndianConverter.ToUInt16(buffer, 0x1A);
  55. NumberOfHiddenSectors = LittleEndianConverter.ToUInt32(buffer, 0x1C);
  56. PhysicalDriveNumber = buffer[0x24];
  57. ExtendedBootSignature = buffer[0x26];
  58. TotalSectors = LittleEndianConverter.ToUInt64(buffer, 0x28);
  59. MftStartLCN = LittleEndianConverter.ToUInt64(buffer, 0x30);
  60. MftMirrorStartLCN = LittleEndianConverter.ToUInt64(buffer, 0x38);
  61. RawClustersPerFileRecordSegment = (sbyte)buffer[0x40];
  62. RawClustersPerIndexBlock = (sbyte)buffer[0x44];
  63. VolumeSerialNumber = LittleEndianConverter.ToUInt64(buffer, 0x48);
  64. Checksum = LittleEndianConverter.ToUInt32(buffer, 0x50);
  65. Array.Copy(buffer, 0x54, Code, 0, Code.Length);
  66. }
  67. public byte[] GetBytes()
  68. {
  69. byte[] buffer = new byte[BytesPerSector];
  70. Array.Copy(Jump, 0, buffer, 0x00, 3);
  71. Array.Copy(ASCIIEncoding.ASCII.GetBytes(OEMID), 0, buffer, 0x03, Math.Min(8, OEMID.Length));
  72. Array.Copy(LittleEndianConverter.GetBytes(BytesPerSector), 0, buffer, 0x0B, 2);
  73. buffer[0x0D] = SectorsPerCluster;
  74. buffer[0x15] = MediaDescriptor;
  75. Array.Copy(LittleEndianConverter.GetBytes(SectorsPerTrack), 0, buffer, 0x18, 2);
  76. Array.Copy(LittleEndianConverter.GetBytes(NumberOfHeads), 0, buffer, 0x1A, 2);
  77. Array.Copy(LittleEndianConverter.GetBytes(NumberOfHiddenSectors), 0, buffer, 0x1C, 4);
  78. buffer[0x24] = PhysicalDriveNumber;
  79. buffer[0x26] = ExtendedBootSignature;
  80. Array.Copy(LittleEndianConverter.GetBytes(TotalSectors), 0, buffer, 0x28, 8);
  81. Array.Copy(LittleEndianConverter.GetBytes(MftStartLCN), 0, buffer, 0x30, 8);
  82. Array.Copy(LittleEndianConverter.GetBytes(MftMirrorStartLCN), 0, buffer, 0x38, 8);
  83. buffer[0x40] = (byte)RawClustersPerFileRecordSegment;
  84. buffer[0x44] = (byte)RawClustersPerIndexBlock;
  85. Array.Copy(LittleEndianConverter.GetBytes(VolumeSerialNumber), 0, buffer, 0x48, 8);
  86. Array.Copy(LittleEndianConverter.GetBytes(Checksum), 0, buffer, 0x50, 4);
  87. Array.Copy(Code, 0, buffer, 0x54, Code.Length);
  88. return buffer;
  89. }
  90. public int BytesPerCluster
  91. {
  92. get
  93. {
  94. int clusterSize = SectorsPerCluster * BytesPerSector;
  95. return clusterSize;
  96. }
  97. }
  98. public int FileRecordSegmentLength // Size in bytes
  99. {
  100. get
  101. {
  102. return CalcRecordSize(RawClustersPerFileRecordSegment);
  103. }
  104. }
  105. public bool IsValid
  106. {
  107. get
  108. {
  109. return String.Equals(OEMID, ValidSignature);
  110. }
  111. }
  112. /// <summary>
  113. /// File record segment length is a multiple of BytesPerSector
  114. /// </summary>
  115. public int SectorsPerFileRecordSegment
  116. {
  117. get
  118. {
  119. return this.FileRecordSegmentLength / BytesPerSector;
  120. }
  121. }
  122. internal int CalcRecordSize(int rawClustersPerFileRecord)
  123. {
  124. if (rawClustersPerFileRecord < 0)
  125. {
  126. return 1 << (-rawClustersPerFileRecord);
  127. }
  128. else
  129. {
  130. return rawClustersPerFileRecord * SectorsPerCluster * BytesPerSector;
  131. }
  132. }
  133. public static NTFSBootRecord ReadRecord(byte[] buffer)
  134. {
  135. string OEMID = ASCIIEncoding.ASCII.GetString(buffer, 0x03, 8);
  136. bool isValid = String.Equals(OEMID, ValidSignature);
  137. if (isValid)
  138. {
  139. return new NTFSBootRecord(buffer);
  140. }
  141. else
  142. {
  143. return null;
  144. }
  145. }
  146. }
  147. }