Browse Source

Updated DiskAccessLibrary to v1.4.4

Tal Aloni 7 years ago
parent
commit
4df55a6964

+ 3 - 2
DiskAccessLibrary/FileSystems/NTFS/AttributeRecord/NonResidentAttributeRecord.cs

@@ -142,11 +142,12 @@ namespace DiskAccessLibrary.FileSystems.NTFS
                 bytesRead += clusters.Length;
             }
 
-            // If we have just read the last cluster, and it is only partially used, we must trim it
+            // If the last cluster is only partially used or we have been asked to read clusters beyond the last cluster, trim result.
+            // (Either of those cases could only be true if we have just read the last cluster).
             if (lastClusterVcnToRead == (long)HighestVCN)
             {
                 long bytesToUse = (long)(FileSize - (ulong)firstClusterVCN * (uint)volume.BytesPerCluster);
-                if (bytesToUse < bytesRead)
+                if (bytesToUse < result.Length)
                 {
                     byte[] resultTrimmed = new byte[bytesToUse];
                     Array.Copy(result, resultTrimmed, bytesToUse);

+ 4 - 0
DiskAccessLibrary/FileSystems/NTFS/NTFSFile.cs

@@ -30,6 +30,10 @@ namespace DiskAccessLibrary.FileSystems.NTFS
 
         public byte[] ReadFromFile(ulong offset, int length)
         {
+            if (offset >= this.Length)
+            {
+                return new byte[0];
+            }
             long clusterVCN = (long)offset / m_volume.BytesPerCluster;
             int offsetInCluster = (int)(offset % (uint)m_volume.BytesPerCluster);
             int clusterCount = (int)Math.Ceiling((double)(offsetInCluster + length) / m_volume.BytesPerCluster);

+ 1 - 1
DiskAccessLibrary/LogicalDiskManager/Helpers/DynamicDiskHelper.Extents.cs

@@ -83,7 +83,7 @@ namespace DiskAccessLibrary.LogicalDiskManager
 
         public static long GetMaxNewExtentLength(DynamicDisk disk)
         {
-            return GetMaxNewExtentLength(disk, 0);
+            return GetMaxNewExtentLength(disk, 1);
         }
 
         /// <returns>In bytes</returns>

+ 25 - 26
DiskAccessLibrary/LogicalDiskManager/Helpers/DynamicVolumeHelper.cs

@@ -1,4 +1,4 @@
-/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
+/* Copyright (C) 2014-2016 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  * 
  * You can redistribute this program and/or modify it under the terms of
  * the GNU Lesser Public License as published by the Free Software Foundation,
@@ -40,13 +40,13 @@ namespace DiskAccessLibrary.LogicalDiskManager
         public static List<DynamicVolume> GetDynamicVolumes(List<DynamicDisk> disks)
         {
             List<DynamicVolume> result = new List<DynamicVolume>();
-            
+
             List<DiskGroupDatabase> diskGroupDatabases = DiskGroupDatabase.ReadFromDisks(disks);
             foreach (DiskGroupDatabase database in diskGroupDatabases)
             {
                 foreach (VolumeRecord volumeRecord in database.VolumeRecords)
                 {
-                    DynamicVolume volume = GetVolume(disks, database, volumeRecord);
+                    DynamicVolume volume = GetVolume(database, volumeRecord);
                     result.Add(volume);
                 }
             }
@@ -54,20 +54,19 @@ namespace DiskAccessLibrary.LogicalDiskManager
             return result;
         }
 
-        public static DynamicVolume GetVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, VolumeRecord volumeRecord)
+        public static DynamicVolume GetVolume(DiskGroupDatabase database, VolumeRecord volumeRecord)
         {
             List<ComponentRecord> componentRecords = database.FindComponentsByVolumeID(volumeRecord.VolumeId);
             if (volumeRecord.NumberOfComponents != (ulong)componentRecords.Count || componentRecords.Count == 0)
-            { 
+            {
                 // database record is invalid
                 throw new InvalidDataException("Number of components in volume record does not match actual number of component records");
             }
-            
+
             if (componentRecords.Count == 1)
             {
                 ComponentRecord componentRecord = componentRecords[0];
-                return GetVolume(disks, database, volumeRecord, componentRecord);
-                
+                return GetVolume(database, volumeRecord, componentRecord);
             }
             else // Mirrored volume
             {
@@ -76,7 +75,7 @@ namespace DiskAccessLibrary.LogicalDiskManager
                 List<DynamicVolume> volumes = new List<DynamicVolume>();
                 foreach (ComponentRecord componentRecord in componentRecords)
                 {
-                    DynamicVolume volume = GetVolume(disks, database, volumeRecord, componentRecord);
+                    DynamicVolume volume = GetVolume(database, volumeRecord, componentRecord);
                     volumes.Add(volume);
                 }
 
@@ -87,31 +86,31 @@ namespace DiskAccessLibrary.LogicalDiskManager
             }
         }
 
-        private static DynamicVolume GetVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, VolumeRecord volumeRecord, ComponentRecord componentRecord)
+        private static DynamicVolume GetVolume(DiskGroupDatabase database, VolumeRecord volumeRecord, ComponentRecord componentRecord)
         {
             if (componentRecord.ExtentLayout == ExtentLayoutName.Concatenated)
             {
                 if (componentRecord.NumberOfExtents == 1)
                 {
                     // Simple volume
-                    return GetSimpleVolume(disks, database, componentRecord, volumeRecord); ;
+                    return GetSimpleVolume(database, componentRecord, volumeRecord); ;
                 }
                 else
                 {
                     // spanned volume
-                    SpannedVolume volume = GetSpannedVolume(disks, database, componentRecord, volumeRecord);
+                    SpannedVolume volume = GetSpannedVolume(database, componentRecord, volumeRecord);
                     return volume;
                 }
             }
             else if (componentRecord.ExtentLayout == ExtentLayoutName.Stripe)
             {
                 // striped volume
-                StripedVolume volume = GetStripedVolume(disks, database, componentRecord, volumeRecord);
+                StripedVolume volume = GetStripedVolume(database, componentRecord, volumeRecord);
                 return volume;
             }
             else if (componentRecord.ExtentLayout == ExtentLayoutName.RAID5)
             {
-                Raid5Volume volume = GetRAID5Volume(disks, database, componentRecord, volumeRecord);
+                Raid5Volume volume = GetRAID5Volume(database, componentRecord, volumeRecord);
                 return volume;
             }
             else
@@ -120,7 +119,7 @@ namespace DiskAccessLibrary.LogicalDiskManager
             }
         }
 
-        private static List<DynamicColumn> GetDynamicVolumeColumns(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
+        private static List<DynamicColumn> GetDynamicVolumeColumns(DiskGroupDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
         {
             // extentRecords are sorted by offset in column
             List<ExtentRecord> extentRecords = database.FindExtentsByComponentID(componentRecord.ComponentId);
@@ -130,12 +129,12 @@ namespace DiskAccessLibrary.LogicalDiskManager
                 throw new InvalidDataException("Number of extents in component record does not match actual number of extent records");
             }
 
-            SortedList<uint, List<DynamicDiskExtent>> columns = new SortedList<uint,List<DynamicDiskExtent>>();
+            SortedList<uint, List<DynamicDiskExtent>> columns = new SortedList<uint, List<DynamicDiskExtent>>();
 
             foreach (ExtentRecord extentRecord in extentRecords)
             {
                 DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId);
-                DynamicDisk disk = DynamicDiskHelper.FindDisk(disks, diskRecord.DiskGuid); // we add nulls as well
+                DynamicDisk disk = DynamicDiskHelper.FindDisk(database.Disks, diskRecord.DiskGuid); // we add nulls as well
                 DynamicDiskExtent extent = DynamicDiskExtentHelper.GetDiskExtent(disk, extentRecord);
 
                 if (columns.ContainsKey(extentRecord.ColumnIndex))
@@ -143,7 +142,7 @@ namespace DiskAccessLibrary.LogicalDiskManager
                     columns[extentRecord.ColumnIndex].Add(extent);
                 }
                 else
-                { 
+                {
                     List<DynamicDiskExtent> list = new List<DynamicDiskExtent>();
                     list.Add(extent);
                     columns.Add(extentRecord.ColumnIndex, list);
@@ -158,7 +157,7 @@ namespace DiskAccessLibrary.LogicalDiskManager
             return result;
         }
 
-        private static SimpleVolume GetSimpleVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
+        private static SimpleVolume GetSimpleVolume(DiskGroupDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
         {
             List<ExtentRecord> extentRecords = database.FindExtentsByComponentID(componentRecord.ComponentId);
             if (extentRecords.Count == 1)
@@ -166,7 +165,7 @@ namespace DiskAccessLibrary.LogicalDiskManager
                 ExtentRecord extentRecord = extentRecords[0];
 
                 DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId);
-                DynamicDisk disk = DynamicDiskHelper.FindDisk(disks, diskRecord.DiskGuid); // we add nulls as well
+                DynamicDisk disk = DynamicDiskHelper.FindDisk(database.Disks, diskRecord.DiskGuid); // we add nulls as well
                 DynamicDiskExtent extent = DynamicDiskExtentHelper.GetDiskExtent(disk, extentRecord);
 
                 SimpleVolume volume = new SimpleVolume(extent, volumeRecord.VolumeGuid, database.DiskGroupGuid);
@@ -182,9 +181,9 @@ namespace DiskAccessLibrary.LogicalDiskManager
             }
         }
 
-        private static Raid5Volume GetRAID5Volume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
+        private static Raid5Volume GetRAID5Volume(DiskGroupDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
         {
-            List<DynamicColumn> columns = GetDynamicVolumeColumns(disks, database, componentRecord, volumeRecord);
+            List<DynamicColumn> columns = GetDynamicVolumeColumns(database, componentRecord, volumeRecord);
             int bytesPerSector = DynamicVolume.GetBytesPerSector(columns, DynamicColumn.DefaultBytesPerSector);
             int sectorsPerStripe = (int)PublicRegionHelper.TranslateFromPublicRegionSizeLBA((int)componentRecord.StripeSizeLBA, bytesPerSector);
             Raid5Volume volume = new Raid5Volume(columns, sectorsPerStripe, volumeRecord.VolumeGuid, database.DiskGroupGuid);
@@ -194,9 +193,9 @@ namespace DiskAccessLibrary.LogicalDiskManager
             return volume;
         }
 
-        private static StripedVolume GetStripedVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
+        private static StripedVolume GetStripedVolume(DiskGroupDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
         {
-            List<DynamicColumn> columns = GetDynamicVolumeColumns(disks, database, componentRecord, volumeRecord);
+            List<DynamicColumn> columns = GetDynamicVolumeColumns(database, componentRecord, volumeRecord);
             int bytesPerSector = DynamicVolume.GetBytesPerSector(columns, DynamicColumn.DefaultBytesPerSector);
             int sectorsPerStripe = (int)PublicRegionHelper.TranslateFromPublicRegionSizeLBA((int)componentRecord.StripeSizeLBA, bytesPerSector);
             StripedVolume volume = new StripedVolume(columns, sectorsPerStripe, volumeRecord.VolumeGuid, database.DiskGroupGuid);
@@ -206,9 +205,9 @@ namespace DiskAccessLibrary.LogicalDiskManager
             return volume;
         }
 
-        private static SpannedVolume GetSpannedVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
+        private static SpannedVolume GetSpannedVolume(DiskGroupDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
         {
-            List<DynamicColumn> columns = GetDynamicVolumeColumns(disks, database, componentRecord, volumeRecord);
+            List<DynamicColumn> columns = GetDynamicVolumeColumns(database, componentRecord, volumeRecord);
 
             SpannedVolume volume = new SpannedVolume(columns[0], volumeRecord.VolumeGuid, database.DiskGroupGuid);
             volume.VolumeID = volumeRecord.VolumeId;

+ 8 - 3
DiskAccessLibrary/LogicalDiskManager/Helpers/RetainHelper.cs

@@ -22,10 +22,15 @@ namespace DiskAccessLibrary.LogicalDiskManager
             }
             else if (volume is MirroredVolume)
             {
-                DynamicVolume component = ((MirroredVolume)volume).Components[0];
-                if (component is SimpleVolume)
+                foreach (DynamicVolume component in ((MirroredVolume)volume).Components)
                 {
-                    return IsVolumeRetained((SimpleVolume)component, out isBootVolume);
+                    if (component.IsOperational && component is SimpleVolume)
+                    {
+                        if (IsVolumeRetained((SimpleVolume)component, out isBootVolume))
+                        {
+                            return true;
+                        }
+                    }
                 }
             }
 

+ 2 - 8
DiskAccessLibrary/LogicalDiskManager/VolumeManagerDatabase.cs

@@ -365,8 +365,7 @@ namespace DiskAccessLibrary.LogicalDiskManager
                 }
             }
 
-            result.Sort(CompareByOffsetInColumn);
-            //result.Sort(CompareByColumnIndex);
+            result.Sort(CompareOffsetInColumn);
             return result;
         }
 
@@ -508,12 +507,7 @@ namespace DiskAccessLibrary.LogicalDiskManager
             }
         }
 
-        private static int CompareByColumnIndex(ExtentRecord x, ExtentRecord y)
-        {
-            return x.ColumnIndex.CompareTo(y.ColumnIndex);
-        }
-
-        private static int CompareByOffsetInColumn(ExtentRecord x, ExtentRecord y)
+        private static int CompareOffsetInColumn(ExtentRecord x, ExtentRecord y)
         {
             return x.OffsetInColumnLBA.CompareTo(y.OffsetInColumnLBA);
         }

+ 2 - 2
DiskAccessLibrary/Properties/AssemblyInfo.cs

@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
 //
 // You can specify all the values or you can default the Revision and Build Numbers 
 // by using the '*' as shown below:
-[assembly: AssemblyVersion("1.4.3.0")]
-[assembly: AssemblyFileVersion("1.4.3.0")]
+[assembly: AssemblyVersion("1.4.4.0")]
+[assembly: AssemblyFileVersion("1.4.4.0")]

+ 7 - 0
DiskAccessLibrary/RevisionHistory.txt

@@ -88,3 +88,10 @@ Revision History:
 1.4.3 - Bugfix: MirroredVolume.BytesPerSector reported wrong number of bytes per sector when the first volume was not operational.
         Bugfix: DynamicDiskHelper.IsMoveLocationValid ignored allocated extents.
         API: Added DiskGroupGuid property to DynamicDisk.
+
+1.4.4 - Bugfix: DynamicVolumeHelper looked for volume extents outside of the disk group.
+        Bugfix: RetainHelper.IsVolumeRetained did not properly iterate components of mirrored volume.
+        NTFS: Properly trim result array when caller tries to read more bytes than the record contains.
+        NTFS: Return empty byte array when trying to read from offset larger than file length.
+        LockHelper.LockAllVolumesOrNone will attempt to lock only mounted volumes.
+        API improvements.

+ 18 - 8
DiskAccessLibrary/Win32/Helpers/DiskOfflineHelper.cs

@@ -14,9 +14,14 @@ namespace DiskAccessLibrary.LogicalDiskManager
     {
         public static bool IsDiskGroupOnlineAndWritable(Guid diskGroupGuid)
         {
-            List<DynamicDisk> disksToLock = WindowsDynamicDiskHelper.GetPhysicalDynamicDisks(diskGroupGuid);
+            List<DynamicDisk> diskGroup = WindowsDynamicDiskHelper.GetPhysicalDynamicDisks(diskGroupGuid);
+            return IsDiskGroupOnlineAndWritable(diskGroup);
+        }
+
+        public static bool IsDiskGroupOnlineAndWritable(List<DynamicDisk> diskGroup)
+        {
             List<PhysicalDisk> physicalDisks = new List<PhysicalDisk>();
-            foreach (DynamicDisk dynamicDisk in disksToLock)
+            foreach (DynamicDisk dynamicDisk in diskGroup)
             {
                 if (dynamicDisk.Disk is PhysicalDisk)
                 {
@@ -48,19 +53,16 @@ namespace DiskAccessLibrary.LogicalDiskManager
         public static void OnlineDiskGroup(Guid diskGroupGuid)
         {
             List<DynamicDisk> disksToOnline = WindowsDynamicDiskHelper.GetPhysicalDynamicDisks(diskGroupGuid);
-            foreach (DynamicDisk disk in disksToOnline)
-            {
-                ((PhysicalDisk)disk.Disk).SetOnlineStatus(true);
-            }
+            OnlineAll(disksToOnline);
         }
 
         /// <summary>
         /// Will not persist across reboots
         /// </summary>
-        public static bool OfflineAllOrNone(List<DynamicDisk> disksToLock)
+        public static bool OfflineAllOrNone(List<DynamicDisk> disksToOffline)
         {
             List<PhysicalDisk> physicalDisks = new List<PhysicalDisk>();
-            foreach (DynamicDisk dynamicDisk in disksToLock)
+            foreach (DynamicDisk dynamicDisk in disksToOffline)
             {
                 if (dynamicDisk.Disk is PhysicalDisk)
                 {
@@ -69,5 +71,13 @@ namespace DiskAccessLibrary.LogicalDiskManager
             }
             return PhysicalDiskHelper.OfflineAllOrNone(physicalDisks);
         }
+
+        public static void OnlineAll(List<DynamicDisk> disksToOnline)
+        {
+            foreach (DynamicDisk disk in disksToOnline)
+            {
+                ((PhysicalDisk)disk.Disk).SetOnlineStatus(true);
+            }
+        }
     }
 }

+ 7 - 3
DiskAccessLibrary/Win32/Helpers/LockHelper.cs

@@ -76,10 +76,14 @@ namespace DiskAccessLibrary
             int lockIndex;
             for (lockIndex = 0; lockIndex < volumeGuids.Count; lockIndex++)
             {
-                success = WindowsVolumeManager.ExclusiveLock(volumeGuids[lockIndex]);
-                if (!success)
+                Guid volumeGuid = volumeGuids[lockIndex];
+                if (WindowsVolumeManager.IsMounted(volumeGuid))
                 {
-                    break;
+                    success = WindowsVolumeManager.ExclusiveLock(volumeGuid);
+                    if (!success)
+                    {
+                        break;
+                    }
                 }
             }
 

+ 1 - 0
DiskAccessLibrary/Win32/Helpers/WindowsVolumeManager.cs

@@ -85,6 +85,7 @@ namespace DiskAccessLibrary
         /// If Windows Automount is turned off, then partitions on new disks are not mounted. (but can be locked).
         /// Failed dynamic volumes are not mounted as well. (and can't be locked).
         /// Note: A volume can have 0 mount points and still be mounted and access by Windows.
+        /// Note: The NTFS file system treats a locked volume as a dismounted volume.
         /// </summary>
         public static bool IsMounted(Guid windowsVolumeGuid)
         {

+ 5 - 0
DiskAccessLibrary/Win32/LogicalDiskManager/LockManager.cs

@@ -20,6 +20,11 @@ namespace DiskAccessLibrary.LogicalDiskManager
         public static LockStatus LockDynamicDiskGroup(Guid diskGroupGuid, bool lockAllDynamicVolumes)
         {
             List<DynamicDisk> disksToLock = WindowsDynamicDiskHelper.GetPhysicalDynamicDisks(diskGroupGuid);
+            return LockDynamicDiskGroup(disksToLock, lockAllDynamicVolumes);
+        }
+
+        public static LockStatus LockDynamicDiskGroup(List<DynamicDisk> disksToLock, bool lockAllDynamicVolumes)
+        {
             List<DynamicVolume> volumesToLock = new List<DynamicVolume>();
 
             if (lockAllDynamicVolumes)

+ 12 - 0
DiskAccessLibrary/Win32/Utilities/VolumeControl.cs

@@ -69,24 +69,36 @@ namespace DiskAccessLibrary
             return new List<string>();
         }
 
+        /// <summary>
+        /// Note: The NTFS file system treats a locked volume as a dismounted volume.
+        /// </summary>
         public static bool IsVolumeMounted(char driveLetter)
         {
             SafeFileHandle handle = HandleUtils.GetVolumeHandle(driveLetter, FileAccess.Read, ShareMode.ReadWrite);
             return IsVolumeMounted(handle);
         }
 
+        /// <summary>
+        /// Note: The NTFS file system treats a locked volume as a dismounted volume.
+        /// </summary>
         public static bool IsVolumeMounted(string path)
         {
             SafeFileHandle handle = HandleUtils.GetVolumeHandle(path, FileAccess.Read, ShareMode.ReadWrite);
             return IsVolumeMounted(handle);
         }
 
+        /// <summary>
+        /// Note: The NTFS file system treats a locked volume as a dismounted volume.
+        /// </summary>
         public static bool IsVolumeMounted(Guid volumeGuid)
         {
             SafeFileHandle handle = HandleUtils.GetVolumeHandle(volumeGuid, FileAccess.Read, ShareMode.ReadWrite);
             return IsVolumeMounted(handle);
         }
 
+        /// <summary>
+        /// Note: The NTFS file system treats a locked volume as a dismounted volume.
+        /// </summary>
         /// <param name="handle">When opening a volume, the dwShareMode parameter must have the FILE_SHARE_WRITE flag.</param>
         public static bool IsVolumeMounted(SafeFileHandle handle)
         {