NTFSVolume.Extend.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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 partial class NTFSVolume : IExtendableFileSystem
  14. {
  15. public long GetMaximumSizeToExtend()
  16. {
  17. // The sector following the NTFS volume is a backup to the boot sector, we want to leave room for a new backup boot sector
  18. return m_volume.Size - (this.Size + m_volume.BytesPerSector);
  19. }
  20. public void Extend(long numberOfAdditionalSectors)
  21. {
  22. Extend((ulong)numberOfAdditionalSectors);
  23. }
  24. public void Extend(ulong numberOfAdditionalSectors)
  25. {
  26. ulong originalNumberOfSectors = m_bootRecord.TotalSectors;
  27. ulong currentNumberOfClusters = m_bootRecord.TotalSectors / m_bootRecord.SectorsPerCluster;
  28. ulong numberOfAdditionalClusters = numberOfAdditionalSectors / m_bootRecord.SectorsPerCluster;
  29. Extend(currentNumberOfClusters, numberOfAdditionalClusters);
  30. // We set TotalSectors only after extending the File system, or otherwise the $bitmap size will mismatch
  31. m_bootRecord.TotalSectors += numberOfAdditionalClusters * m_bootRecord.SectorsPerCluster; // we only add usable sectors
  32. // update boot sector
  33. byte[] bootRecordBytes = m_bootRecord.GetBytes();
  34. WriteSectors(0, bootRecordBytes);
  35. // recreate the backup boot sector at the new end of the raw volume
  36. // Note: The backup boot sector does not count as part of the NTFS volume
  37. long backupBootSectorIndex = (long)(originalNumberOfSectors + numberOfAdditionalSectors);
  38. WriteSectors(backupBootSectorIndex, bootRecordBytes);
  39. }
  40. // Note: there could be up to 2^64 clusters ( http://technet.microsoft.com/en-us/library/cc938432.aspx )
  41. private void Extend(ulong currentNumberOfClusters, ulong numberOfAdditionalClusters)
  42. {
  43. // Each bit in the $Bitmap file represents a cluster.
  44. // The size of the $Bitmap file is always a multiple of 8 bytes, extra bits are always set to 1.
  45. //
  46. // Note:
  47. // 1TB of additional allocation will result in a bitmap of 32 MB (assuming 4KB clusters)
  48. // 128TB of additional allocation will result in a bitmap of 512 MB (assuming 8KB clusters)
  49. byte[] bitmap;
  50. ulong nextClusterIndexInBitmap = 0; // the next cluster that will be allocated
  51. ulong writeOffset = m_bitmap.Length;
  52. if (currentNumberOfClusters % 64 > 0)
  53. {
  54. ulong numberOfClustersToAllocate = numberOfAdditionalClusters - (64 - (currentNumberOfClusters % 64));
  55. ulong numberOfBytesToAllocate = (ulong)Math.Ceiling((double)numberOfClustersToAllocate / 8);
  56. numberOfBytesToAllocate = (ulong)Math.Ceiling((double)numberOfBytesToAllocate / 8) * 8;
  57. // The last 8 bytes may contain extra bits that were previously set as used, and now have to be free.
  58. // We extend the file before reading the last 8 bytes of the bitmap, because it's possible that during the extension,
  59. // clusters will be allocated from the last 8 bytes of the $bitmap file. for this reason, we must first extend the file, and then read the bitmap
  60. m_bitmap.ExtendFile(numberOfBytesToAllocate);
  61. bitmap = new byte[8 + numberOfBytesToAllocate];
  62. // We have to modify the last 8 bytes in the current bitmap (which will be the first in 'bitmap')
  63. writeOffset = writeOffset - 8;
  64. byte[] temp = m_bitmap.ReadFromFile(writeOffset, 8);
  65. Array.Copy(temp, bitmap, 8);
  66. nextClusterIndexInBitmap = currentNumberOfClusters % 64;
  67. while (nextClusterIndexInBitmap < 64)
  68. {
  69. ClusterUsageBitmap.UpdateClusterStatus(bitmap, nextClusterIndexInBitmap, false);
  70. nextClusterIndexInBitmap++;
  71. }
  72. nextClusterIndexInBitmap += numberOfClustersToAllocate;
  73. }
  74. else
  75. {
  76. ulong numberOfAdditionalBytes = (ulong)Math.Ceiling((double)numberOfAdditionalClusters / 8);
  77. numberOfAdditionalBytes = (ulong)Math.Ceiling((double)numberOfAdditionalBytes / 8) * 8;
  78. bitmap = new byte[numberOfAdditionalBytes];
  79. nextClusterIndexInBitmap = numberOfAdditionalClusters;
  80. }
  81. // mark extra bits as used:
  82. while (nextClusterIndexInBitmap < (ulong)bitmap.Length * 8)
  83. {
  84. ClusterUsageBitmap.UpdateClusterStatus(bitmap, nextClusterIndexInBitmap, true);
  85. nextClusterIndexInBitmap++;
  86. }
  87. m_bitmap.WriteToFile(writeOffset, bitmap);
  88. }
  89. }
  90. }