Skip to content

Commit 2eec024

Browse files
committed
Added detection for dynamic disks.
Adjusted logging in TestClass.
1 parent bf1729c commit 2eec024

File tree

7 files changed

+121
-59
lines changed

7 files changed

+121
-59
lines changed

ConsoleOutputTest/TestClass.cs

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -88,25 +88,33 @@ static void LogData(Storage storage)
8888
lock (_LogDataLock)
8989
{
9090
Log($"Storage '{storage.Model}':");
91-
Log($" -> {nameof(storage.Partitions)}:");
9291

93-
foreach (var partition in storage.Partitions)
92+
if (!storage.IsDynamicDisk)
9493
{
95-
Log($" + {nameof(Partition)} #{partition.PartitionNumber}:");
94+
Log($" -> {nameof(storage.Partitions)}:");
9695

97-
if (partition.DriveLetter != null)
96+
foreach (var partition in storage.Partitions)
9897
{
99-
Log($" # {nameof(partition.DriveLetter ),Padding} = {partition.DriveLetter }");
100-
}
98+
Log($" + {nameof(Partition)} #{partition.PartitionNumber}:");
10199

102-
if (partition.AvailableFreeSpace != null)
103-
{
104-
Log($" # {nameof(partition.AvailableFreeSpace),Padding} = {partition.AvailableFreeSpace}");
105-
}
100+
if (partition.DriveLetter != null)
101+
{
102+
Log($" # {nameof(partition.DriveLetter ),Padding} = {partition.DriveLetter }");
103+
}
104+
105+
if (partition.AvailableFreeSpace != null)
106+
{
107+
Log($" # {nameof(partition.AvailableFreeSpace),Padding} = {partition.AvailableFreeSpace}");
108+
}
106109

107-
Log($" # {nameof(partition.PartitionStyle ),Padding} = {partition.PartitionStyle }");
108-
Log($" # {nameof(partition.StartingOffset ),Padding} = {partition.StartingOffset }");
109-
Log($" # {nameof(partition.PartitionLength),Padding} = {partition.PartitionLength}");
110+
Log($" # {nameof(partition.PartitionStyle ),Padding} = {partition.PartitionStyle }");
111+
Log($" # {nameof(partition.StartingOffset ),Padding} = {partition.StartingOffset }");
112+
Log($" # {nameof(partition.PartitionLength),Padding} = {partition.PartitionLength}");
113+
}
114+
}
115+
else
116+
{
117+
Log($" -> {nameof(storage.Partitions)} not being logged due to {nameof(storage.IsDynamicDisk)}");
110118
}
111119

112120
Log();
@@ -144,17 +152,29 @@ static void LogData(Storage storage)
144152
Log($" -> {nameof(storage.Model ),Padding} = {storage.Model }");
145153
Log($" -> {nameof(storage.PhysicalPath ),Padding} = {storage.PhysicalPath }");
146154

147-
if (storage.ProductID.HasValue)
155+
if (storage.ProductID != null)
148156
{
149157
Log($" -> {nameof(storage.ProductID ),Padding} = {storage.ProductID }");
150158
}
151159

152160
Log($" -> {nameof(storage.SerialNumber ),Padding} = {storage.SerialNumber }");
153161
Log($" -> {nameof(storage.StorageController ),Padding} = {storage.StorageController }");
154162
Log($" -> {nameof(storage.StorageControllerType ),Padding} = {storage.StorageControllerType }");
163+
164+
Log($" -> {nameof(storage.IsDynamicDisk ),Padding} = {storage.IsDynamicDisk }");
165+
166+
if (!storage.IsDynamicDisk)
167+
{
168+
var totalFreeSize = storage.TotalFreeSize;
169+
170+
var percentFree = totalFreeSize == 0 ? 0 : 100M * totalFreeSize / storage.TotalSize;
171+
172+
Log($" -> {nameof(totalFreeSize ),Padding} = {totalFreeSize } ({percentFree:F2}%)");
173+
}
174+
155175
Log($" -> {nameof(storage.TotalSize ),Padding} = {storage.TotalSize }");
156176

157-
if (storage.VendorID.HasValue)
177+
if (storage.VendorID != null)
158178
{
159179
Log($" -> {nameof(storage.VendorID ),Padding} = {storage.VendorID } ({storage.VendorID:X4})");
160180
}
@@ -165,41 +185,55 @@ static void LogData(Storage storage)
165185
{
166186
Log($" -> {nameof(storage.Smart)}:");
167187

188+
Log($" + {nameof(storage.Smart.DiskStatus ),Padding} = {storage.Smart.DiskStatus }");
189+
168190
if (storage.Smart.Temperature != null)
169191
{
170-
Log($" + {nameof(storage.Smart.Temperature ),Padding} = {storage.Smart.Temperature}°C");
192+
Log($" + {nameof(storage.Smart.Temperature ),Padding} = {storage.Smart.Temperature }°C");
171193
}
172194

173195
if (storage.Smart.TemperatureWarning != null)
174196
{
175-
Log($" + {nameof(storage.Smart.TemperatureWarning ),Padding} = {storage.Smart.TemperatureWarning}°C");
197+
Log($" + {nameof(storage.Smart.TemperatureWarning ),Padding} = {storage.Smart.TemperatureWarning }°C");
176198
}
177199

178200
if (storage.Smart.TemperatureCritical != null)
179201
{
180-
Log($" + {nameof(storage.Smart.TemperatureCritical ),Padding} = {storage.Smart.TemperatureCritical}°C");
202+
Log($" + {nameof(storage.Smart.TemperatureCritical ),Padding} = {storage.Smart.TemperatureCritical }°C");
203+
}
204+
205+
if (storage.Smart.Life != null)
206+
{
207+
Log($" + {nameof(storage.Smart.Life ),Padding} = {storage.Smart.Life }%");
208+
}
209+
210+
if (storage.Smart.HostReads != null)
211+
{
212+
Log($" + {nameof(storage.Smart.HostReads ),Padding} = {storage.Smart.HostReads }");
213+
}
214+
215+
if (storage.Smart.HostWrites != null)
216+
{
217+
Log($" + {nameof(storage.Smart.HostWrites ),Padding} = {storage.Smart.HostWrites }");
181218
}
182219

183-
Log($" + {nameof(storage.Smart.Life ),Padding} = {storage.Smart.Life}%");
184-
Log($" + {nameof(storage.Smart.HostReads ),Padding} = {storage.Smart.HostReads }");
185-
Log($" + {nameof(storage.Smart.HostWrites ),Padding} = {storage.Smart.HostWrites }");
186220
Log($" + {nameof(storage.Smart.PowerOnCount ),Padding} = {storage.Smart.PowerOnCount }");
187221
Log($" + {nameof(storage.Smart.MeasuredPowerOnHours),Padding} = {storage.Smart.MeasuredPowerOnHours}h");
188222
Log($" + {nameof(storage.Smart.DetectedPowerOnHours),Padding} = {storage.Smart.DetectedPowerOnHours}h");
189223

190-
if (storage.Smart.NandWrites.HasValue)
224+
if (storage.Smart.NandWrites != null)
191225
{
192-
Log($" + {nameof(storage.Smart.NandWrites ),Padding} = {storage.Smart.NandWrites }");
226+
Log($" + {nameof(storage.Smart.NandWrites ),Padding} = {storage.Smart.NandWrites }");
193227
}
194228

195-
if (storage.Smart.GBytesErased.HasValue)
229+
if (storage.Smart.GBytesErased != null)
196230
{
197-
Log($" + {nameof(storage.Smart.GBytesErased ),Padding} = {storage.Smart.GBytesErased }");
231+
Log($" + {nameof(storage.Smart.GBytesErased ),Padding} = {storage.Smart.GBytesErased }");
198232
}
199233

200-
if (storage.Smart.WearLevelingCount.HasValue)
234+
if (storage.Smart.WearLevelingCount != null)
201235
{
202-
Log($" + {nameof(storage.Smart.WearLevelingCount ),Padding} = {storage.Smart.WearLevelingCount}");
236+
Log($" + {nameof(storage.Smart.WearLevelingCount ),Padding} = {storage.Smart.WearLevelingCount }");
203237
}
204238

205239
Log();

DiskInfoToolkit.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution
1515
ProjectSection(SolutionItems) = preProject
1616
LICENSE = LICENSE
1717
README.md = README.md
18+
THIRD-PARTY-NOTICES = THIRD-PARTY-NOTICES
1819
EndProjectSection
1920
EndProject
2021
Global

DiskInfoToolkit/DiskInfoToolkit.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
<RepositoryUrl>https://github.com/Blacktempel/DiskInfoToolkit</RepositoryUrl>
1515
<PackageTags>disk; device; nvme; ssd; hdd; toolkit; thermal; sensor; thermal sensor; smart; s.m.a.r.t.; data; monitoring; system; disk info</PackageTags>
1616
<PackageLicenseExpression>MPL-2.0</PackageLicenseExpression>
17-
<AssemblyVersion>1.0.0</AssemblyVersion>
18-
<FileVersion>1.0.0</FileVersion>
17+
<AssemblyVersion>1.0.1</AssemblyVersion>
18+
<FileVersion>1.0.1</FileVersion>
1919
<Version>$(AssemblyVersion)</Version>
2020
<PackageIcon>packageicon.png</PackageIcon>
2121
<PackageReadmeFile>README.md</PackageReadmeFile>

DiskInfoToolkit/Partition.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
using DiskInfoToolkit.Interop.Structures;
1616
using DiskInfoToolkit.Structures.Interop;
1717
using System.Runtime.InteropServices;
18-
using System.Text;
1918

2019
namespace DiskInfoToolkit
2120
{
@@ -26,8 +25,13 @@ public class Partition
2625
{
2726
#region Fields
2827

28+
const int PARTITION_LDM = 0x42;
29+
2930
static Guid GUID_DEVINTERFACE_VOLUME = new Guid("53f5630d-b6bf-11d0-94f2-00a0c91efb8b");
3031

32+
static readonly Guid PARTITION_LDM_METADATA_GUID = new Guid("5808c8aa-7e8f-42e0-85d2-e1e90434cfb3");
33+
static readonly Guid PARTITION_LDM_DATA_GUID = new Guid("af9b60a0-1431-4f62-bc68-3311714a69ad");
34+
3135
#endregion
3236

3337
#region Properties
@@ -45,7 +49,7 @@ public class Partition
4549
/// <summary>
4650
/// Starting offset of this partition.
4751
/// </summary>
48-
public long StartingOffset { get; internal set; }
52+
public long StartingOffset { get; internal set; }
4953

5054
/// <summary>
5155
/// Length of this partition.
@@ -68,6 +72,14 @@ public class Partition
6872
/// </summary>
6973
public ulong? AvailableFreeSpace { get; internal set; }
7074

75+
/// <summary>
76+
/// Identifies if this partition is on a dynamic disk (Windows).
77+
/// </summary>
78+
public bool IsDynamicDiskPartition { get; internal set; }
79+
80+
/// <summary>
81+
/// Volume path which is being used for <see cref="Kernel32.GetDiskFreeSpaceEx"/>.
82+
/// </summary>
7183
internal string VolumePath { get; set; }
7284

7385
#endregion
@@ -140,6 +152,18 @@ static bool ReadPartitions(IntPtr handle, out List<Partition> partitions)
140152
PartitionNumber = partitionInformation.PartitionNumber,
141153
};
142154

155+
switch (partition.PartitionStyle)
156+
{
157+
case PartitionStyle.PartitionStyleMBR:
158+
partition.IsDynamicDiskPartition = partitionInformation.Layout.Mbr.PartitionType == PARTITION_LDM;
159+
break;
160+
case PartitionStyle.PartitionStyleGPT:
161+
partition.IsDynamicDiskPartition =
162+
partitionInformation.Layout.Gpt.PartitionType == PARTITION_LDM_METADATA_GUID
163+
|| partitionInformation.Layout.Gpt.PartitionType == PARTITION_LDM_DATA_GUID;
164+
break;
165+
}
166+
143167
partitions.Add(partition);
144168
}
145169

DiskInfoToolkit/Storage.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,16 @@ internal Storage(string storageController, StorageDevice sdi)
235235

236236
#region Volatile
237237

238+
/// <summary>
239+
/// Identifies if this device is a dynamic disk (Windows).
240+
/// </summary>
241+
public bool IsDynamicDisk => Partitions.Any(p => p.IsDynamicDiskPartition);
242+
238243
/// <summary>
239244
/// Gets the total free size of storage space on a drive, in bytes.
240245
/// </summary>
241-
/// <remarks>Calculation (all <see cref="Partitions"/>): <see cref="TotalSize"/> - <see cref="Partition.PartitionLength"/> + <see cref="Partition.AvailableFreeSpace"/>.</remarks>
246+
/// <remarks>Calculation (all <see cref="Partitions"/>): <see cref="TotalSize"/> - <see cref="Partition.PartitionLength"/> + <see cref="Partition.AvailableFreeSpace"/>.<br/>
247+
/// This will not return reliable data if this device is a dynamic disk (check <see cref="IsDynamicDisk"/>).</remarks>
242248
public ulong TotalFreeSize => GetTotalFreeSize();
243249

244250
/// <summary>
@@ -249,6 +255,7 @@ internal Storage(string storageController, StorageDevice sdi)
249255
/// <summary>
250256
/// List of all partitions on drive.
251257
/// </summary>
258+
/// <remarks>Partitions do not reflect partitions on a dynamic disk (Windows) - check <see cref="IsDynamicDisk"/>.</remarks>
252259
public List<Partition> Partitions { get; private set; } = new();
253260

254261
#endregion

LICENSE

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
Copyright (c) 2025 Florian K.
2-
31
Mozilla Public License Version 2.0
42
==================================
53

@@ -373,28 +371,3 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice
373371

374372
This Source Code Form is "Incompatible With Secondary Licenses", as
375373
defined by the Mozilla Public License, v. 2.0.
376-
377-
######################################################################
378-
379-
A big part of of this code was ported from CrystalDiskInfo, therefore:
380-
MIT License
381-
382-
Copyright (c) 2008-2023 hiyohiyo
383-
384-
Permission is hereby granted, free of charge, to any person obtaining a copy
385-
of this software and associated documentation files (the "Software"), to deal
386-
in the Software without restriction, including without limitation the rights
387-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
388-
copies of the Software, and to permit persons to whom the Software is
389-
furnished to do so, subject to the following conditions:
390-
391-
The above copyright notice and this permission notice shall be included in all
392-
copies or substantial portions of the Software.
393-
394-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
395-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
396-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
397-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
398-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
399-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
400-
SOFTWARE.

THIRD-PARTY-NOTICES

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
A big part of of this code was ported from CrystalDiskInfo, therefore:
2+
3+
MIT License
4+
5+
Copyright (c) 2008-2023 hiyohiyo
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.

0 commit comments

Comments
 (0)