Upload FastSeekWpf/Core/MftReader.cs
Browse files- FastSeekWpf/Core/MftReader.cs +10 -21
FastSeekWpf/Core/MftReader.cs
CHANGED
|
@@ -9,7 +9,6 @@ namespace FastSeekWpf.Core;
|
|
| 9 |
|
| 10 |
public class MftReader : IDisposable
|
| 11 |
{
|
| 12 |
-
// Volume handle — used for boot sector read and FSCTL fallback
|
| 13 |
private readonly IntPtr _volumeHandle;
|
| 14 |
private readonly NtfsDrive _drive;
|
| 15 |
private bool _disposed;
|
|
@@ -38,12 +37,8 @@ public class MftReader : IDisposable
|
|
| 38 |
}
|
| 39 |
}
|
| 40 |
|
| 41 |
-
// ------------------------------------------------------------------
|
| 42 |
-
// Primary: direct $MFT file read (falls back to FSCTL if fails)
|
| 43 |
-
// ------------------------------------------------------------------
|
| 44 |
-
|
| 45 |
/// <summary>
|
| 46 |
-
///
|
| 47 |
/// Matches Rust scan_direct() exactly.
|
| 48 |
/// </summary>
|
| 49 |
public ScanResult? ScanDirect()
|
|
@@ -53,7 +48,7 @@ public class MftReader : IDisposable
|
|
| 53 |
|
| 54 |
string mftPath = $"{_drive.Root}$MFT";
|
| 55 |
|
| 56 |
-
// Open
|
| 57 |
IntPtr mftHandle = Win32Api.CreateFileW(
|
| 58 |
mftPath,
|
| 59 |
Win32Api.GENERIC_READ,
|
|
@@ -76,8 +71,10 @@ public class MftReader : IDisposable
|
|
| 76 |
|
| 77 |
while (true)
|
| 78 |
{
|
|
|
|
|
|
|
| 79 |
bool ok = Win32Api.ReadFile(
|
| 80 |
-
mftHandle, buffer, (uint)(buffer.Length - leftover), out uint bytesRead, IntPtr.Zero);
|
| 81 |
if (!ok || bytesRead == 0)
|
| 82 |
break;
|
| 83 |
|
|
@@ -113,10 +110,9 @@ public class MftReader : IDisposable
|
|
| 113 |
}
|
| 114 |
}
|
| 115 |
|
| 116 |
-
//
|
| 117 |
-
//
|
| 118 |
-
//
|
| 119 |
-
|
| 120 |
public ScanResult Scan()
|
| 121 |
{
|
| 122 |
var records = new List<CompactRecord>();
|
|
@@ -228,13 +224,8 @@ public class MftReader : IDisposable
|
|
| 228 |
// NTFS helpers
|
| 229 |
// ------------------------------------------------------------------
|
| 230 |
|
| 231 |
-
/// <summary>
|
| 232 |
-
/// Read MFT record size from NTFS boot sector via volume handle.
|
| 233 |
-
/// Matches Rust read_mft_record_size().
|
| 234 |
-
/// </summary>
|
| 235 |
private int? ReadMftRecordSize()
|
| 236 |
{
|
| 237 |
-
// Seek to beginning of volume
|
| 238 |
Win32Api.SetFilePointerEx(_volumeHandle, 0, out _, 0);
|
| 239 |
|
| 240 |
byte[] boot = new byte[512];
|
|
@@ -257,8 +248,7 @@ public class MftReader : IDisposable
|
|
| 257 |
}
|
| 258 |
|
| 259 |
/// <summary>
|
| 260 |
-
/// Apply NTFS multi-sector fixup.
|
| 261 |
-
/// CRITICAL: Restores the original bytes from the fixup array back to sector ends.
|
| 262 |
/// Matches Rust apply_fixup() exactly.
|
| 263 |
/// </summary>
|
| 264 |
private static bool ApplyFixup(byte[] record, int offset, int recordSize)
|
|
@@ -293,8 +283,7 @@ public class MftReader : IDisposable
|
|
| 293 |
}
|
| 294 |
|
| 295 |
/// <summary>
|
| 296 |
-
/// Parse one MFT FILE record
|
| 297 |
-
/// Matches Rust parse_file_record() exactly.
|
| 298 |
/// </summary>
|
| 299 |
private static void ParseFileRecord(
|
| 300 |
ReadOnlySpan<byte> record,
|
|
|
|
| 9 |
|
| 10 |
public class MftReader : IDisposable
|
| 11 |
{
|
|
|
|
| 12 |
private readonly IntPtr _volumeHandle;
|
| 13 |
private readonly NtfsDrive _drive;
|
| 14 |
private bool _disposed;
|
|
|
|
| 37 |
}
|
| 38 |
}
|
| 39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
/// <summary>
|
| 41 |
+
/// Primary: direct $MFT file read. Returns null if unavailable.
|
| 42 |
/// Matches Rust scan_direct() exactly.
|
| 43 |
/// </summary>
|
| 44 |
public ScanResult? ScanDirect()
|
|
|
|
| 48 |
|
| 49 |
string mftPath = $"{_drive.Root}$MFT";
|
| 50 |
|
| 51 |
+
// Open $MFT as a normal file (not the volume device)
|
| 52 |
IntPtr mftHandle = Win32Api.CreateFileW(
|
| 53 |
mftPath,
|
| 54 |
Win32Api.GENERIC_READ,
|
|
|
|
| 71 |
|
| 72 |
while (true)
|
| 73 |
{
|
| 74 |
+
// CRITICAL: read into buffer starting at 'leftover', not at 0
|
| 75 |
+
// This matches Rust: ReadFile(mft_handle, &mut buffer[leftover..])
|
| 76 |
bool ok = Win32Api.ReadFile(
|
| 77 |
+
mftHandle, buffer, leftover, (uint)(buffer.Length - leftover), out uint bytesRead, IntPtr.Zero);
|
| 78 |
if (!ok || bytesRead == 0)
|
| 79 |
break;
|
| 80 |
|
|
|
|
| 110 |
}
|
| 111 |
}
|
| 112 |
|
| 113 |
+
/// <summary>
|
| 114 |
+
/// Fallback: FSCTL_ENUM_USN_DATA (4 MB buffer)
|
| 115 |
+
/// </summary>
|
|
|
|
| 116 |
public ScanResult Scan()
|
| 117 |
{
|
| 118 |
var records = new List<CompactRecord>();
|
|
|
|
| 224 |
// NTFS helpers
|
| 225 |
// ------------------------------------------------------------------
|
| 226 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 227 |
private int? ReadMftRecordSize()
|
| 228 |
{
|
|
|
|
| 229 |
Win32Api.SetFilePointerEx(_volumeHandle, 0, out _, 0);
|
| 230 |
|
| 231 |
byte[] boot = new byte[512];
|
|
|
|
| 248 |
}
|
| 249 |
|
| 250 |
/// <summary>
|
| 251 |
+
/// Apply NTFS multi-sector fixup. RESTORES bytes from fixup array.
|
|
|
|
| 252 |
/// Matches Rust apply_fixup() exactly.
|
| 253 |
/// </summary>
|
| 254 |
private static bool ApplyFixup(byte[] record, int offset, int recordSize)
|
|
|
|
| 283 |
}
|
| 284 |
|
| 285 |
/// <summary>
|
| 286 |
+
/// Parse one MFT FILE record. Matches Rust parse_file_record() exactly.
|
|
|
|
| 287 |
/// </summary>
|
| 288 |
private static void ParseFileRecord(
|
| 289 |
ReadOnlySpan<byte> record,
|