NTFSFile.cs 5.8 KB

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