AttributeRecord.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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.FileSystems.NTFS
  12. {
  13. /// <summary>
  14. /// ATTRIBUTE_RECORD_HEADER: http://msdn.microsoft.com/en-us/library/bb470039%28v=vs.85%29.aspx
  15. /// </summary>
  16. public abstract class AttributeRecord
  17. {
  18. public const int AttributeRecordHeaderLength = 16; // The part that is common to both resident and non-resident attributes
  19. /* Start of header */
  20. private AttributeType m_type;
  21. public uint StoredRecordLength;
  22. private byte m_nonResidentFlag; // a.k.a. FormCode
  23. private byte m_nameLength; // number of characters
  24. // ushort NameOffset;
  25. public ushort Flags;
  26. public ushort AttributeID; // a.k.a. Instance
  27. /* End of header */
  28. public string Name = String.Empty;
  29. protected AttributeRecord(byte[] buffer, int offset)
  30. {
  31. m_type = (AttributeType)LittleEndianConverter.ToUInt32(buffer, offset + 0x00);
  32. StoredRecordLength = LittleEndianConverter.ToUInt32(buffer, offset + 0x04);
  33. m_nonResidentFlag = buffer[offset + 0x08];
  34. m_nameLength = buffer[offset + 0x09];
  35. ushort nameOffset = LittleEndianConverter.ToUInt16(buffer, offset + 0x0A);
  36. Flags = LittleEndianConverter.ToUInt16(buffer, offset + 0x0C);
  37. AttributeID = LittleEndianConverter.ToUInt16(buffer, offset + 0x0E);
  38. if (m_nameLength > 0)
  39. {
  40. Name = UnicodeEncoding.Unicode.GetString(buffer, offset + nameOffset, m_nameLength * 2);
  41. }
  42. }
  43. public abstract byte[] GetBytes(int bytesPerCluster);
  44. public void WriteHeader(byte[] buffer, ushort nameOffset)
  45. {
  46. m_nameLength = (byte)(Name.Length * 2);
  47. buffer[0x00] = (byte)m_type;
  48. LittleEndianWriter.WriteUInt32(buffer, 0x04, this.RecordLength);
  49. buffer[0x08] = m_nonResidentFlag;
  50. buffer[0x09] = m_nameLength;
  51. LittleEndianWriter.WriteUInt16(buffer, 0x0A, nameOffset);
  52. LittleEndianWriter.WriteUInt16(buffer, 0x0C, Flags);
  53. LittleEndianWriter.WriteUInt16(buffer, 0x0E, AttributeID);
  54. if (m_nameLength > 0)
  55. {
  56. Array.Copy(UnicodeEncoding.Unicode.GetBytes(Name), 0, buffer, nameOffset, m_nameLength);
  57. }
  58. }
  59. public abstract byte[] GetData(NTFSVolume volume);
  60. public AttributeType AttributeType
  61. {
  62. get
  63. {
  64. return m_type;
  65. }
  66. }
  67. public bool IsResidentRecord
  68. {
  69. get
  70. {
  71. return (m_nonResidentFlag == 0x00);
  72. }
  73. }
  74. public static AttributeRecord FromBytes(byte[] buffer, int offset)
  75. {
  76. byte nonResidentFlag = buffer[offset + 0x08];
  77. AttributeType attributeType = (AttributeType)LittleEndianConverter.ToUInt32(buffer, offset + 0x00);
  78. if (nonResidentFlag == 0x00) // resident
  79. {
  80. if (attributeType == AttributeType.StandardInformation)
  81. {
  82. return new StandardInformationRecord(buffer, offset);
  83. }
  84. else if (attributeType == AttributeType.FileName)
  85. {
  86. return new FileNameAttributeRecord(buffer, offset);
  87. }
  88. else if (attributeType == AttributeType.VolumeInformation)
  89. {
  90. return new VolumeInformationRecord(buffer, offset);
  91. }
  92. else if (attributeType == AttributeType.IndexRoot)
  93. {
  94. return new IndexRootRecord(buffer, offset);
  95. }
  96. else
  97. {
  98. return new ResidentAttributeRecord(buffer, offset);
  99. }
  100. }
  101. else // non-resident
  102. {
  103. if (attributeType == AttributeType.IndexAllocation)
  104. {
  105. return new IndexAllocationRecord(buffer, offset);
  106. }
  107. else
  108. {
  109. return new NonResidentAttributeRecord(buffer, offset);
  110. }
  111. }
  112. }
  113. /// <summary>
  114. /// When reading attributes, they may contain additional padding,
  115. /// so we should use StoredRecordLength to advance the buffer position instead.
  116. /// </summary>
  117. public abstract uint RecordLength
  118. {
  119. get;
  120. }
  121. }
  122. }