anshdadhich commited on
Commit
f4192b6
·
verified ·
1 Parent(s): b299dd7

Upload FastSeekWpf/Core/MftReader.cs

Browse files
Files changed (1) hide show
  1. FastSeekWpf/Core/MftReader.cs +29 -49
FastSeekWpf/Core/MftReader.cs CHANGED
@@ -21,25 +21,14 @@ public class MftReader : IDisposable
21
  public MftReader(NtfsDrive drive)
22
  {
23
  _drive = drive;
24
-
25
- // Open volume device for boot sector read (matches Rust MftReader::open exactly)
26
- var pathBytes = System.Text.Encoding.Unicode.GetBytes(drive.DevicePath + '\0');
27
- GCHandle pathHandle = GCHandle.Alloc(pathBytes, GCHandleType.Pinned);
28
- try
29
- {
30
- _volumeHandle = Win32Api.CreateFileW(
31
- drive.DevicePath,
32
- Win32Api.GENERIC_READ,
33
- Win32Api.FILE_SHARE_READ | Win32Api.FILE_SHARE_WRITE | Win32Api.FILE_SHARE_DELETE,
34
- IntPtr.Zero,
35
- Win32Api.OPEN_EXISTING,
36
- Win32Api.FILE_FLAG_BACKUP_SEMANTICS,
37
- IntPtr.Zero);
38
- }
39
- finally
40
- {
41
- pathHandle.Free();
42
- }
43
 
44
  if (_volumeHandle == new IntPtr(-1))
45
  {
@@ -49,9 +38,14 @@ public class MftReader : IDisposable
49
  }
50
 
51
  // ------------------------------------------------------------------
52
- // Primary: direct $MFT file read (matches Rust scan_direct exactly)
 
53
  // ------------------------------------------------------------------
54
 
 
 
 
 
55
  public ScanResult? ScanDirect()
56
  {
57
  int? recordSize = ReadMftRecordSize();
@@ -60,19 +54,19 @@ public class MftReader : IDisposable
60
  string mftPath = $"{_drive.Root}$MFT";
61
  Logger.Log($"[{Drive.Letter}] Opening $MFT: {mftPath}");
62
 
63
- IntPtr mftHandle = OpenMftFile(mftPath);
64
- if (mftHandle == new IntPtr(-1))
65
- {
66
- // Try extended-length path prefix as fallback
67
- string extendedPath = $"\\\\?\\{mftPath}";
68
- Logger.Log($"[{Drive.Letter}] Retrying with extended path: {extendedPath}");
69
- mftHandle = OpenMftFile(extendedPath);
70
- }
71
 
72
  if (mftHandle == new IntPtr(-1))
73
  {
74
  int err = Marshal.GetLastWin32Error();
75
- Logger.Log($"[{Drive.Letter}] CreateFileW($MFT) failed: {Win32Error(err)} (code={err})");
76
  return null;
77
  }
78
 
@@ -90,7 +84,7 @@ public class MftReader : IDisposable
90
  bool ok = Win32Api.ReadFile(
91
  mftHandle, buffer, leftover, (uint)(buffer.Length - leftover), out bytesRead, IntPtr.Zero);
92
 
93
- if (!ok || bytesRead == 0)
94
  break;
95
 
96
  int total = leftover + (int)bytesRead;
@@ -112,7 +106,7 @@ public class MftReader : IDisposable
112
  offset += recordSize.Value;
113
  }
114
 
115
- // Align down to record boundary (matches Rust: offset = total - (total % record_size))
116
  offset = total - (total % recordSize.Value);
117
 
118
  leftover = total - offset;
@@ -132,20 +126,9 @@ public class MftReader : IDisposable
132
  }
133
  }
134
 
135
- private static IntPtr OpenMftFile(string path)
136
- {
137
- return Win32Api.CreateFileW(
138
- path,
139
- Win32Api.GENERIC_READ,
140
- Win32Api.FILE_SHARE_READ | Win32Api.FILE_SHARE_WRITE | Win32Api.FILE_SHARE_DELETE,
141
- IntPtr.Zero,
142
- Win32Api.OPEN_EXISTING,
143
- Win32Api.FILE_FLAG_BACKUP_SEMANTICS | Win32Api.FILE_FLAG_SEQUENTIAL_SCAN,
144
- IntPtr.Zero);
145
- }
146
-
147
  // ------------------------------------------------------------------
148
- // Fallback: FSCTL_ENUM_USN_DATA (matches Rust scan exactly)
 
149
  // ------------------------------------------------------------------
150
 
151
  public ScanResult Scan()
@@ -196,7 +179,7 @@ public class MftReader : IDisposable
196
  }
197
  if (error == 122) // ERROR_INSUFFICIENT_BUFFER
198
  {
199
- Logger.Log($"[{Drive.Letter}] FSCTL buffer too small, retrying with {buffer.Length * 2}");
200
  buffer = new byte[buffer.Length * 2];
201
  continue;
202
  }
@@ -205,10 +188,7 @@ public class MftReader : IDisposable
205
  }
206
 
207
  if (bytesReturned <= 8)
208
- {
209
- Logger.Log($"[{Drive.Letter}] FSCTL: {bytesReturned} bytes returned, stopping");
210
  break;
211
- }
212
 
213
  ulong nextRef = (ulong)Marshal.ReadInt64(bufferPtr);
214
  enumData.StartFileReferenceNumber = nextRef;
@@ -268,7 +248,7 @@ public class MftReader : IDisposable
268
 
269
  private int? ReadMftRecordSize()
270
  {
271
- // Seek to start of volume
272
  Win32Api.SetFilePointerEx(_volumeHandle, 0, out _, 0);
273
 
274
  byte[] boot = new byte[512];
 
21
  public MftReader(NtfsDrive drive)
22
  {
23
  _drive = drive;
24
+ _volumeHandle = Win32Api.CreateFileW(
25
+ drive.DevicePath,
26
+ Win32Api.GENERIC_READ,
27
+ Win32Api.FILE_SHARE_READ | Win32Api.FILE_SHARE_WRITE | Win32Api.FILE_SHARE_DELETE,
28
+ IntPtr.Zero,
29
+ Win32Api.OPEN_EXISTING,
30
+ Win32Api.FILE_FLAG_BACKUP_SEMANTICS,
31
+ IntPtr.Zero);
 
 
 
 
 
 
 
 
 
 
 
32
 
33
  if (_volumeHandle == new IntPtr(-1))
34
  {
 
38
  }
39
 
40
  // ------------------------------------------------------------------
41
+ // Primary: direct $MFT file read (falls back to FSCTL if fails)
42
+ // Matches Rust scan_direct() + scan() exactly.
43
  // ------------------------------------------------------------------
44
 
45
+ /// <summary>
46
+ /// Try direct sequential read of $MFT for maximum speed.
47
+ /// Returns null if direct access is unavailable (matches Rust .ok()?).
48
+ /// </summary>
49
  public ScanResult? ScanDirect()
50
  {
51
  int? recordSize = ReadMftRecordSize();
 
54
  string mftPath = $"{_drive.Root}$MFT";
55
  Logger.Log($"[{Drive.Letter}] Opening $MFT: {mftPath}");
56
 
57
+ IntPtr mftHandle = Win32Api.CreateFileW(
58
+ mftPath,
59
+ Win32Api.GENERIC_READ,
60
+ Win32Api.FILE_SHARE_READ | Win32Api.FILE_SHARE_WRITE | Win32Api.FILE_SHARE_DELETE,
61
+ IntPtr.Zero,
62
+ Win32Api.OPEN_EXISTING,
63
+ Win32Api.FILE_FLAG_BACKUP_SEMANTICS | Win32Api.FILE_FLAG_SEQUENTIAL_SCAN,
64
+ IntPtr.Zero);
65
 
66
  if (mftHandle == new IntPtr(-1))
67
  {
68
  int err = Marshal.GetLastWin32Error();
69
+ Logger.Log($"[{Drive.Letter}] CreateFileW({mftPath}) failed: {Win32Error(err)} (code={err})");
70
  return null;
71
  }
72
 
 
84
  bool ok = Win32Api.ReadFile(
85
  mftHandle, buffer, leftover, (uint)(buffer.Length - leftover), out bytesRead, IntPtr.Zero);
86
 
87
+ if (ok.is_err() || bytesRead == 0)
88
  break;
89
 
90
  int total = leftover + (int)bytesRead;
 
106
  offset += recordSize.Value;
107
  }
108
 
109
+ // Align offset down to record boundary (matches Rust: offset = total - (total % record_size))
110
  offset = total - (total % recordSize.Value);
111
 
112
  leftover = total - offset;
 
126
  }
127
  }
128
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  // ------------------------------------------------------------------
130
+ // Fallback: FSCTL_ENUM_USN_DATA (4 MB buffer)
131
+ // Matches Rust scan() exactly.
132
  // ------------------------------------------------------------------
133
 
134
  public ScanResult Scan()
 
179
  }
180
  if (error == 122) // ERROR_INSUFFICIENT_BUFFER
181
  {
182
+ Logger.Log($"[{Drive.Letter}] FSCTL buffer too small ({buffer.Length}), retrying");
183
  buffer = new byte[buffer.Length * 2];
184
  continue;
185
  }
 
188
  }
189
 
190
  if (bytesReturned <= 8)
 
 
191
  break;
 
192
 
193
  ulong nextRef = (ulong)Marshal.ReadInt64(bufferPtr);
194
  enumData.StartFileReferenceNumber = nextRef;
 
248
 
249
  private int? ReadMftRecordSize()
250
  {
251
+ // Seek to beginning of volume
252
  Win32Api.SetFilePointerEx(_volumeHandle, 0, out _, 0);
253
 
254
  byte[] boot = new byte[512];