Skip to content

Commit 7ba593a

Browse files
committed
feat: free space wipe with SSD/HDD auto-detection via WMI MediaType
1 parent ea7eb55 commit 7ba593a

1 file changed

Lines changed: 77 additions & 0 deletions

File tree

src/DeepPurge.Core/Safety/SecureDelete.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
using System.Management;
12
using System.Security.Cryptography;
3+
using DeepPurge.Core.Diagnostics;
24

35
namespace DeepPurge.Core.Safety;
46

@@ -104,4 +106,79 @@ public static bool WipeDirectory(string path)
104106
return false;
105107
}
106108
}
109+
110+
public static async Task<long> WipeFreeSpaceAsync(
111+
string drivePath,
112+
IProgress<string>? progress = null,
113+
CancellationToken ct = default)
114+
{
115+
var driveRoot = Path.GetPathRoot(drivePath) ?? @"C:\";
116+
var isSsd = DetectSsd(driveRoot);
117+
progress?.Report(isSsd ? $"SSD detected on {driveRoot} — single-pass fill" : $"HDD detected on {driveRoot} — single-pass fill");
118+
119+
var tempDir = Path.Combine(driveRoot, ".deeppurge_wipe_" + Guid.NewGuid().ToString("N")[..8]);
120+
long totalWritten = 0;
121+
try
122+
{
123+
Directory.CreateDirectory(tempDir);
124+
var fillBuffer = new byte[1024 * 1024];
125+
int fileIndex = 0;
126+
127+
while (true)
128+
{
129+
ct.ThrowIfCancellationRequested();
130+
var filePath = Path.Combine(tempDir, $"wipe_{fileIndex++}.tmp");
131+
try
132+
{
133+
using var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, fillBuffer.Length, FileOptions.WriteThrough);
134+
while (true)
135+
{
136+
ct.ThrowIfCancellationRequested();
137+
RandomNumberGenerator.Fill(fillBuffer);
138+
fs.Write(fillBuffer, 0, fillBuffer.Length);
139+
totalWritten += fillBuffer.Length;
140+
if (totalWritten % (100L * 1024 * 1024) == 0)
141+
progress?.Report($"Filling free space: {totalWritten / (1024 * 1024)} MB written...");
142+
}
143+
}
144+
catch (IOException)
145+
{
146+
break;
147+
}
148+
}
149+
}
150+
catch (OperationCanceledException) { throw; }
151+
catch (Exception ex) { Log.Warn($"WipeFreeSpace: {ex.Message}"); }
152+
finally
153+
{
154+
try
155+
{
156+
if (Directory.Exists(tempDir))
157+
Directory.Delete(tempDir, recursive: true);
158+
}
159+
catch { }
160+
}
161+
162+
progress?.Report($"Free space wipe complete: {totalWritten / (1024 * 1024)} MB overwritten");
163+
return totalWritten;
164+
}
165+
166+
private static bool DetectSsd(string driveRoot)
167+
{
168+
try
169+
{
170+
var driveLetter = driveRoot.TrimEnd('\\').TrimEnd(':');
171+
using var searcher = new ManagementObjectSearcher(
172+
$"SELECT MediaType FROM MSFT_PhysicalDisk WHERE DeviceID IN " +
173+
$"(SELECT DiskNumber FROM MSFT_Partition WHERE DriveLetter='{driveLetter}')");
174+
searcher.Scope = new ManagementScope(@"\\.\ROOT\Microsoft\Windows\Storage");
175+
foreach (var obj in searcher.Get())
176+
{
177+
var mediaType = Convert.ToInt32(obj["MediaType"]);
178+
return mediaType == 4; // 4 = SSD, 3 = HDD
179+
}
180+
}
181+
catch { }
182+
return false;
183+
}
107184
}

0 commit comments

Comments
 (0)