TOCBlock.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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.IO;
  9. using System.Collections.Generic;
  10. using System.Text;
  11. using Utilities;
  12. namespace DiskAccessLibrary.LogicalDiskManager
  13. {
  14. public class TOCBlock
  15. {
  16. public const int Length = 512;
  17. public const string TOCBlockSignature = "TOCBLOCK";
  18. public string Signature = TOCBlockSignature;
  19. //private uint Checksum; // sum of all bytes in sector excluding the 4 checksum bytes
  20. public ulong UpdateSequenceNumber; // The most recent TOCBlock has this value in sync with the Private Header's UpdateSequenceNumber
  21. // 16 zeros
  22. public List<TOCRegion> Regions = new List<TOCRegion>();
  23. private bool m_isChecksumValid;
  24. public TOCBlock(byte[] buffer)
  25. {
  26. Signature = ByteReader.ReadAnsiString(buffer, 0x00, 8);
  27. uint checksum = BigEndianConverter.ToUInt32(buffer, 0x08);
  28. UpdateSequenceNumber = BigEndianConverter.ToUInt64(buffer, 0x0C);
  29. // 16 zeros
  30. int offset = 0x24;
  31. // If the first character is not null (0x00), then there is a region defined
  32. while (buffer[offset] != 0)
  33. {
  34. TOCRegion region = new TOCRegion(buffer, offset);
  35. Regions.Add(region);
  36. offset += TOCRegion.Length;
  37. }
  38. BigEndianWriter.WriteUInt32(buffer, 0x08, (uint)0); // we exclude the checksum field from checksum calculations
  39. m_isChecksumValid = (checksum == PrivateHeader.CalculateChecksum(buffer));
  40. }
  41. public byte[] GetBytes()
  42. {
  43. byte[] buffer = new byte[Length];
  44. ByteWriter.WriteAnsiString(buffer, 0x00, Signature, 8);
  45. // we'll write checksum later
  46. BigEndianWriter.WriteUInt64(buffer, 0x0C, UpdateSequenceNumber);
  47. int offset = 0x24;
  48. foreach (TOCRegion region in Regions)
  49. {
  50. region.WriteBytes(buffer, offset);
  51. offset += TOCRegion.Length;
  52. }
  53. uint checksum = PrivateHeader.CalculateChecksum(buffer);
  54. BigEndianWriter.WriteUInt32(buffer, 0x08, checksum);
  55. return buffer;
  56. }
  57. public static TOCBlock ReadFromDisk(Disk disk, PrivateHeader privateHeader)
  58. {
  59. TOCBlock tocBlock = ReadFromDisk(disk, privateHeader, true);
  60. if (tocBlock == null)
  61. {
  62. tocBlock = ReadFromDisk(disk, privateHeader, false);
  63. }
  64. return tocBlock;
  65. }
  66. public static TOCBlock ReadFromDisk(Disk disk, PrivateHeader privateHeader, bool usePrimaryTOC)
  67. {
  68. ulong sectorIndex;
  69. if (usePrimaryTOC)
  70. {
  71. sectorIndex = privateHeader.PrivateRegionStartLBA + privateHeader.PrimaryTocLBA;
  72. }
  73. else
  74. {
  75. sectorIndex = privateHeader.PrivateRegionStartLBA + privateHeader.SecondaryTocLBA;
  76. }
  77. byte[] sector = disk.ReadSector((long)sectorIndex);
  78. string signature = ByteReader.ReadAnsiString(sector, 0x00, 8);
  79. if (signature == TOCBlockSignature)
  80. {
  81. TOCBlock tocBlock = new TOCBlock(sector);
  82. if (tocBlock.IsChecksumValid)
  83. {
  84. return tocBlock;
  85. }
  86. }
  87. return null;
  88. }
  89. /// <summary>
  90. /// This method will write privateHeader to disk as well
  91. /// </summary>
  92. public static void WriteToDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock)
  93. {
  94. privateHeader.UpdateSequenceNumber++;
  95. tocBlock.UpdateSequenceNumber++;
  96. byte[] bytes = tocBlock.GetBytes();
  97. disk.WriteSectors((long)(privateHeader.PrivateRegionStartLBA + privateHeader.PreviousPrimaryTocLBA), bytes);
  98. disk.WriteSectors((long)(privateHeader.PrivateRegionStartLBA + privateHeader.PreviousSecondaryTocLBA), bytes);
  99. privateHeader.PrimaryTocLBA = privateHeader.PreviousPrimaryTocLBA;
  100. privateHeader.SecondaryTocLBA = privateHeader.PreviousSecondaryTocLBA;
  101. PrivateHeader.WriteToDisk(disk, privateHeader);
  102. }
  103. public ulong ConfigStart
  104. {
  105. get
  106. {
  107. foreach (TOCRegion region in Regions)
  108. {
  109. if (region.Name == "config")
  110. {
  111. return region.StartLBA;
  112. }
  113. }
  114. throw new InvalidDataException("Config entry was not found");
  115. }
  116. }
  117. public ulong LogStart
  118. {
  119. get
  120. {
  121. foreach (TOCRegion region in Regions)
  122. {
  123. if (region.Name == "log")
  124. {
  125. return region.StartLBA;
  126. }
  127. }
  128. throw new InvalidDataException("Log entry was not found");
  129. }
  130. }
  131. public bool IsChecksumValid
  132. {
  133. get
  134. {
  135. return m_isChecksumValid;
  136. }
  137. }
  138. }
  139. }