DataRunSequence.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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.IO;
  10. using System.Text;
  11. using Utilities;
  12. namespace DiskAccessLibrary.FileSystems.NTFS
  13. {
  14. public class DataRunSequence : List<DataRun>
  15. {
  16. public DataRunSequence() : base()
  17. {
  18. }
  19. /// <param name="startClusterOffset">Distance from LowestVCN</param>
  20. public KeyValuePairList<long, int> TranslateToLCN(long startClusterOffset, int clusterCount)
  21. {
  22. KeyValuePairList<long, int> result = new KeyValuePairList<long, int>();
  23. long previousLCN = 0;
  24. long clusterOffset = startClusterOffset;
  25. int clustersLeftToTranslate = clusterCount;
  26. bool translating = false;
  27. for(int index = 0; index < this.Count; index++)
  28. {
  29. DataRun run = this[index];
  30. long lcn = previousLCN + run.RunOffset;
  31. if (!translating) // still searching for startClusterVCN
  32. {
  33. if (clusterOffset >= run.RunLength) // startClusterVCN is not in this run, check in the next run
  34. {
  35. clusterOffset -= run.RunLength;
  36. }
  37. else
  38. {
  39. translating = true;
  40. long startClusterLCN = lcn + clusterOffset;
  41. long clustersLeftInRun = run.RunLength - clusterOffset; // how many clusters can be read from this run
  42. int clustersTranslated = (int)Math.Min(clustersLeftToTranslate, clustersLeftInRun);
  43. result.Add(startClusterLCN, clustersTranslated);
  44. clustersLeftToTranslate -= clustersTranslated;
  45. if (clustersLeftToTranslate == 0)
  46. {
  47. break;
  48. }
  49. }
  50. }
  51. else
  52. {
  53. int clustersTranslated = (int)Math.Min(clustersLeftToTranslate, run.RunLength);
  54. result.Add(lcn, clustersTranslated);
  55. clustersLeftToTranslate -= clustersTranslated;
  56. if (clustersLeftToTranslate == 0)
  57. {
  58. break;
  59. }
  60. }
  61. previousLCN = lcn;
  62. }
  63. return result;
  64. }
  65. public long GetDataClusterLCN(long clusterVCN)
  66. {
  67. long previousLCN = 0;
  68. long clusterOffset = clusterVCN;
  69. foreach (DataRun run in this)
  70. {
  71. long lcn = previousLCN + run.RunOffset;
  72. if (clusterOffset >= run.RunLength) // not in this run, check in the next run
  73. {
  74. clusterOffset = clusterOffset - run.RunLength;
  75. }
  76. else
  77. {
  78. return lcn + clusterOffset;
  79. }
  80. previousLCN = lcn;
  81. }
  82. throw new InvalidDataException("Invalid cluster VCN");
  83. }
  84. public override string ToString()
  85. {
  86. StringBuilder builder = new StringBuilder();
  87. long vcn = 0;
  88. for(int index = 0; index < this.Count; index++)
  89. {
  90. DataRun run = this[index];
  91. long absoluteLCN = GetDataClusterLCN(vcn);
  92. builder.AppendFormat("Data Run Number {0}: Absolute LCN: {1}, Length: {2}\n", index, absoluteLCN, run.RunLength);
  93. vcn += run.RunLength;
  94. }
  95. builder.AppendFormat("Number of clusters in sequence: {0}\n", DataClusterCount);
  96. return builder.ToString();
  97. }
  98. public long FirstDataRunLCN
  99. {
  100. get
  101. {
  102. if (this.Count > 0)
  103. {
  104. return this[0].RunOffset;
  105. }
  106. else
  107. {
  108. return -1;
  109. }
  110. }
  111. }
  112. /// <summary>
  113. /// LCN of the first cluster in the last data run
  114. /// </summary>
  115. public long LastDataRunStartLCN
  116. {
  117. get
  118. {
  119. if (this.Count > 0)
  120. {
  121. long clusterIndex = 0;
  122. for (int index = 0; index < this.Count - 1; index++)
  123. {
  124. DataRun run = this[index];
  125. clusterIndex += run.RunLength;
  126. }
  127. return GetDataClusterLCN(clusterIndex);
  128. }
  129. else
  130. {
  131. return -1;
  132. }
  133. }
  134. }
  135. /// <summary>
  136. /// LCN of the last cluster in the last data run
  137. /// </summary>
  138. public long DataLastLCN
  139. {
  140. get
  141. {
  142. return GetDataClusterLCN(this.DataClusterCount - 1);
  143. }
  144. }
  145. // The maximum NTFS file size is 2^64 bytes, so total number of file clusters can be represented using long
  146. // http://technet.microsoft.com/en-us/library/cc938937.aspx
  147. public long DataClusterCount
  148. {
  149. get
  150. {
  151. long result = 0;
  152. foreach (DataRun run in this)
  153. {
  154. result += run.RunLength;
  155. }
  156. return result;
  157. }
  158. }
  159. public int RecordLength
  160. {
  161. get
  162. {
  163. int dataRunRecordSequenceLength = 0;
  164. foreach (DataRun run in this)
  165. {
  166. dataRunRecordSequenceLength += run.RecordLength;
  167. }
  168. dataRunRecordSequenceLength += 1; // Null Termination
  169. return dataRunRecordSequenceLength;
  170. }
  171. }
  172. }
  173. }