NTFSFile.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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 NTFSFile
  14. {
  15. NTFSVolume m_volume;
  16. FileRecord m_fileRecord;
  17. public NTFSFile(NTFSVolume volume, long baseSegmentNumber)
  18. {
  19. m_volume = volume;
  20. m_fileRecord = m_volume.MasterFileTable.GetFileRecord(baseSegmentNumber);
  21. }
  22. public NTFSFile(NTFSVolume volume, FileRecord fileRecord)
  23. {
  24. m_volume = volume;
  25. m_fileRecord = fileRecord;
  26. }
  27. public byte[] ReadFromFile(ulong offset, int length)
  28. {
  29. if (offset >= this.Length)
  30. {
  31. return new byte[0];
  32. }
  33. long clusterVCN = (long)offset / m_volume.BytesPerCluster;
  34. int offsetInCluster = (int)(offset % (uint)m_volume.BytesPerCluster);
  35. int clusterCount = (int)Math.Ceiling((double)(offsetInCluster + length) / m_volume.BytesPerCluster);
  36. byte[] clustersBytes = m_fileRecord.DataRecord.ReadDataClusters(m_volume, clusterVCN, clusterCount);
  37. int readLength = clustersBytes.Length - offsetInCluster;
  38. if (readLength < length)
  39. {
  40. length = readLength;
  41. }
  42. byte[] result = new byte[length];
  43. Array.Copy(clustersBytes, offsetInCluster, result, 0, length);
  44. return result;
  45. }
  46. public void WriteToFile(ulong offset, byte[] bytes)
  47. {
  48. ulong currentSize = m_fileRecord.DataRecord.DataRealSize;
  49. if (offset + (uint)bytes.Length > currentSize)
  50. {
  51. // file needs to be extended
  52. ulong additionalLength = offset + (uint)bytes.Length - currentSize;
  53. ExtendFile(additionalLength);
  54. }
  55. int position = 0;
  56. long clusterVCN = (long)(offset / (uint)m_volume.BytesPerCluster);
  57. int offsetInCluster = (int)(offset % (uint)m_volume.BytesPerCluster);
  58. if (offsetInCluster > 0)
  59. {
  60. int bytesLeftInCluster = m_volume.BytesPerCluster - offsetInCluster;
  61. int numberOfBytesToCopy = Math.Min(bytesLeftInCluster, bytes.Length);
  62. // Note: it's safe to send 'bytes' to ModifyCluster(), because it will ignore additional bytes after the first cluster
  63. ModifyCluster(clusterVCN, offsetInCluster, bytes);
  64. position += numberOfBytesToCopy;
  65. clusterVCN++;
  66. }
  67. while (position < bytes.Length)
  68. {
  69. int bytesLeft = bytes.Length - position;
  70. int numberOfBytesToCopy = Math.Min(m_volume.BytesPerCluster, bytesLeft);
  71. byte[] clusterBytes = new byte[numberOfBytesToCopy];
  72. Array.Copy(bytes, position, clusterBytes, 0, numberOfBytesToCopy);
  73. if (numberOfBytesToCopy < m_volume.BytesPerCluster)
  74. {
  75. ModifyCluster(clusterVCN, 0, clusterBytes);
  76. }
  77. else
  78. {
  79. FileRecord.DataRecord.WriteDataCluster(m_volume, clusterVCN, clusterBytes);
  80. }
  81. clusterVCN++;
  82. position += clusterBytes.Length;
  83. }
  84. m_volume.MasterFileTable.UpdateFileRecord(m_fileRecord);
  85. }
  86. /// <summary>
  87. /// Will read cluster and then modify the given bytes
  88. /// </summary>
  89. private void ModifyCluster(long clusterVCN, int offsetInCluster, byte[] bytes)
  90. {
  91. int bytesLeftInCluster = m_volume.BytesPerCluster - offsetInCluster;
  92. int numberOfBytesToCopy = Math.Min(bytesLeftInCluster, bytes.Length);
  93. byte[] clusterBytes = m_fileRecord.DataRecord.ReadDataCluster(m_volume, clusterVCN);
  94. // last cluster could be partial
  95. if (clusterBytes.Length < offsetInCluster + numberOfBytesToCopy)
  96. {
  97. byte[] temp = new byte[offsetInCluster + numberOfBytesToCopy];
  98. Array.Copy(clusterBytes, temp, clusterBytes.Length);
  99. clusterBytes = temp;
  100. }
  101. Array.Copy(bytes, 0, clusterBytes, offsetInCluster, numberOfBytesToCopy);
  102. FileRecord.DataRecord.WriteDataCluster(m_volume, clusterVCN, clusterBytes);
  103. }
  104. /// <param name="additionalLength">In bytes</param>
  105. public void ExtendFile(ulong additionalLength)
  106. {
  107. m_fileRecord.DataRecord.ExtendRecord(m_volume, additionalLength);
  108. if (m_fileRecord.LongFileNameRecord != null)
  109. {
  110. m_fileRecord.LongFileNameRecord.AllocatedSize = m_fileRecord.DataRecord.GetDataAllocatedSize(m_volume.BytesPerCluster);
  111. m_fileRecord.LongFileNameRecord.RealSize = m_fileRecord.DataRecord.DataRealSize;
  112. }
  113. if (m_fileRecord.ShortFileNameRecord != null)
  114. {
  115. m_fileRecord.ShortFileNameRecord.AllocatedSize = m_fileRecord.DataRecord.GetDataAllocatedSize(m_volume.BytesPerCluster);
  116. m_fileRecord.ShortFileNameRecord.RealSize = m_fileRecord.DataRecord.DataRealSize;
  117. }
  118. m_volume.MasterFileTable.UpdateFileRecord(m_fileRecord);
  119. }
  120. public NTFSVolume Volume
  121. {
  122. get
  123. {
  124. return m_volume;
  125. }
  126. }
  127. public FileRecord FileRecord
  128. {
  129. get
  130. {
  131. return m_fileRecord;
  132. }
  133. }
  134. public ulong Length
  135. {
  136. get
  137. {
  138. return m_fileRecord.DataRecord.DataRealSize;
  139. }
  140. }
  141. }
  142. }