Upload FastSeekWpf/App.xaml.cs
Browse files- FastSeekWpf/App.xaml.cs +87 -54
FastSeekWpf/App.xaml.cs
CHANGED
|
@@ -115,6 +115,22 @@ public partial class App : Application
|
|
| 115 |
PrintHeader("FastSeek CLI");
|
| 116 |
Console.WriteLine();
|
| 117 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
// 1. Drives
|
| 119 |
var drives = DriveDiscovery.GetNtfsDrives();
|
| 120 |
PrintLine(ConsoleColor.Cyan, "Drives", $"{drives.Count} NTFS found");
|
|
@@ -123,12 +139,20 @@ public partial class App : Application
|
|
| 123 |
|
| 124 |
if (drives.Count == 0)
|
| 125 |
{
|
| 126 |
-
PrintError("No NTFS drives
|
|
|
|
|
|
|
| 127 |
WaitExit();
|
| 128 |
return;
|
| 129 |
}
|
| 130 |
|
| 131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
PrintLine(ConsoleColor.Cyan, "Scan", "Reading MFT...");
|
| 133 |
var index = new IndexStore();
|
| 134 |
long totalRecords = 0;
|
|
@@ -138,13 +162,11 @@ public partial class App : Application
|
|
| 138 |
{
|
| 139 |
ScanResult? scan = null;
|
| 140 |
string method = "none";
|
| 141 |
-
string? errorMsg = null;
|
| 142 |
|
| 143 |
try
|
| 144 |
{
|
| 145 |
using var reader = new MftReader(drive);
|
| 146 |
|
| 147 |
-
// Try direct first (matches Rust: reader.scan_direct())
|
| 148 |
scan = reader.ScanDirect();
|
| 149 |
if (scan != null)
|
| 150 |
{
|
|
@@ -154,11 +176,6 @@ public partial class App : Application
|
|
| 154 |
else
|
| 155 |
{
|
| 156 |
Logger.Log($"Direct scan unavailable for {drive.Letter}, trying fallback");
|
| 157 |
-
}
|
| 158 |
-
|
| 159 |
-
// Fallback
|
| 160 |
-
if (scan == null || scan.Records.Count == 0)
|
| 161 |
-
{
|
| 162 |
scan = reader.Scan();
|
| 163 |
if (scan != null && scan.Records.Count > 0)
|
| 164 |
{
|
|
@@ -175,7 +192,9 @@ public partial class App : Application
|
|
| 175 |
}
|
| 176 |
else
|
| 177 |
{
|
| 178 |
-
PrintError($" {drive.Letter}: 0 records
|
|
|
|
|
|
|
| 179 |
}
|
| 180 |
}
|
| 181 |
catch (Exception ex)
|
|
@@ -243,61 +262,75 @@ public partial class App : Application
|
|
| 243 |
if (index.Count == 0)
|
| 244 |
{
|
| 245 |
PrintError("INDEX IS EMPTY β GUI will show no results.");
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
Console.WriteLine();
|
| 252 |
}
|
| 253 |
|
| 254 |
// 5. Interactive search
|
| 255 |
-
|
| 256 |
-
Console.WriteLine();
|
| 257 |
-
|
| 258 |
-
while (true)
|
| 259 |
{
|
| 260 |
-
|
| 261 |
-
Console.
|
| 262 |
-
Console.ResetColor();
|
| 263 |
-
var query = Console.ReadLine()?.Trim();
|
| 264 |
-
if (string.IsNullOrEmpty(query)) continue;
|
| 265 |
-
if (query.Equals("exit", StringComparison.OrdinalIgnoreCase)) break;
|
| 266 |
-
|
| 267 |
-
var searchSw = Stopwatch.StartNew();
|
| 268 |
-
var exclusions = CacheManager.LoadExclusions();
|
| 269 |
-
var results = SearchEngine.Search(index, query, 20, false, exclusions);
|
| 270 |
-
searchSw.Stop();
|
| 271 |
-
|
| 272 |
-
Console.ForegroundColor = ConsoleColor.DarkGray;
|
| 273 |
-
Console.WriteLine($" {results.Count} results | {searchSw.Elapsed.TotalMilliseconds:F3}ms");
|
| 274 |
-
Console.ResetColor();
|
| 275 |
|
| 276 |
-
|
| 277 |
{
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
ResultKind.App => ConsoleColor.Green,
|
| 281 |
-
ResultKind.Document => ConsoleColor.Yellow,
|
| 282 |
-
ResultKind.Image => ConsoleColor.Magenta,
|
| 283 |
-
ResultKind.Video => ConsoleColor.Red,
|
| 284 |
-
ResultKind.Audio => ConsoleColor.Blue,
|
| 285 |
-
ResultKind.Archive => ConsoleColor.DarkYellow,
|
| 286 |
-
ResultKind.Folder => ConsoleColor.Cyan,
|
| 287 |
-
_ => ConsoleColor.Gray
|
| 288 |
-
};
|
| 289 |
-
Console.ForegroundColor = color;
|
| 290 |
-
Console.Write($" [{GetBadgeLabel(r.Kind),-4}] ");
|
| 291 |
Console.ResetColor();
|
| 292 |
-
Console.
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
Console.ForegroundColor = ConsoleColor.DarkGray;
|
| 297 |
-
Console.WriteLine($"
|
| 298 |
Console.ResetColor();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
}
|
| 300 |
-
Console.WriteLine();
|
| 301 |
}
|
| 302 |
|
| 303 |
WaitExit();
|
|
|
|
| 115 |
PrintHeader("FastSeek CLI");
|
| 116 |
Console.WriteLine();
|
| 117 |
|
| 118 |
+
// ββ Elevation check ββ
|
| 119 |
+
bool elevated = Elevation.IsElevated();
|
| 120 |
+
if (elevated)
|
| 121 |
+
{
|
| 122 |
+
PrintLine(ConsoleColor.Green, "Elevation", "Administrator β");
|
| 123 |
+
}
|
| 124 |
+
else
|
| 125 |
+
{
|
| 126 |
+
PrintLine(ConsoleColor.Red, "Elevation", $"{Elevation.StatusText()} β");
|
| 127 |
+
PrintError("NOT RUNNING AS ADMINISTRATOR β MFT read will fail.");
|
| 128 |
+
PrintInfo("To fix: Build the project, then run the compiled .exe:");
|
| 129 |
+
PrintDetail(" dotnet publish -c Release -r win-x64");
|
| 130 |
+
PrintDetail(" .\\bin\\Release\\net8.0-windows\\win-x64\\FastSeekWpf.exe --cli");
|
| 131 |
+
Console.WriteLine();
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
// 1. Drives
|
| 135 |
var drives = DriveDiscovery.GetNtfsDrives();
|
| 136 |
PrintLine(ConsoleColor.Cyan, "Drives", $"{drives.Count} NTFS found");
|
|
|
|
| 139 |
|
| 140 |
if (drives.Count == 0)
|
| 141 |
{
|
| 142 |
+
PrintError("No NTFS drives found.");
|
| 143 |
+
if (!elevated)
|
| 144 |
+
PrintInfo("This is likely because you are not elevated. Try running as Administrator.");
|
| 145 |
WaitExit();
|
| 146 |
return;
|
| 147 |
}
|
| 148 |
|
| 149 |
+
if (!elevated)
|
| 150 |
+
{
|
| 151 |
+
// Still try scanning so user sees the exact error messages in log
|
| 152 |
+
PrintInfo("Attempting scan anyway (will likely fail without elevation)...");
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
// 2. Scan
|
| 156 |
PrintLine(ConsoleColor.Cyan, "Scan", "Reading MFT...");
|
| 157 |
var index = new IndexStore();
|
| 158 |
long totalRecords = 0;
|
|
|
|
| 162 |
{
|
| 163 |
ScanResult? scan = null;
|
| 164 |
string method = "none";
|
|
|
|
| 165 |
|
| 166 |
try
|
| 167 |
{
|
| 168 |
using var reader = new MftReader(drive);
|
| 169 |
|
|
|
|
| 170 |
scan = reader.ScanDirect();
|
| 171 |
if (scan != null)
|
| 172 |
{
|
|
|
|
| 176 |
else
|
| 177 |
{
|
| 178 |
Logger.Log($"Direct scan unavailable for {drive.Letter}, trying fallback");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
scan = reader.Scan();
|
| 180 |
if (scan != null && scan.Records.Count > 0)
|
| 181 |
{
|
|
|
|
| 192 |
}
|
| 193 |
else
|
| 194 |
{
|
| 195 |
+
PrintError($" {drive.Letter}: 0 records");
|
| 196 |
+
if (!elevated)
|
| 197 |
+
PrintInfo(" β This error is expected when not running as Administrator.");
|
| 198 |
}
|
| 199 |
}
|
| 200 |
catch (Exception ex)
|
|
|
|
| 262 |
if (index.Count == 0)
|
| 263 |
{
|
| 264 |
PrintError("INDEX IS EMPTY β GUI will show no results.");
|
| 265 |
+
if (!elevated)
|
| 266 |
+
{
|
| 267 |
+
PrintInfo("ROOT CAUSE: You must run the COMPILED .exe as Administrator.");
|
| 268 |
+
PrintInfo("'dotnet run' does NOT trigger UAC elevation.");
|
| 269 |
+
PrintInfo("Steps:");
|
| 270 |
+
PrintDetail(" 1. dotnet publish -c Release -r win-x64");
|
| 271 |
+
PrintDetail(" 2. .\\bin\\Release\\net8.0-windows\\win-x64\\FastSeekWpf.exe --cli");
|
| 272 |
+
PrintDetail(" 3. Accept the UAC prompt");
|
| 273 |
+
}
|
| 274 |
+
else
|
| 275 |
+
{
|
| 276 |
+
PrintInfo("Possible causes:");
|
| 277 |
+
PrintDetail(" β’ MFT direct read blocked by antivirus/EDR");
|
| 278 |
+
PrintDetail(" β’ Volume is ReFS/BitLocker/VM shared folder");
|
| 279 |
+
PrintDetail(" β’ chkdsk / Windows Update holding volume lock");
|
| 280 |
+
}
|
| 281 |
Console.WriteLine();
|
| 282 |
}
|
| 283 |
|
| 284 |
// 5. Interactive search
|
| 285 |
+
if (index.Count > 0)
|
|
|
|
|
|
|
|
|
|
| 286 |
{
|
| 287 |
+
PrintHeader("Interactive Search (type 'exit' to quit)");
|
| 288 |
+
Console.WriteLine();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
|
| 290 |
+
while (true)
|
| 291 |
{
|
| 292 |
+
Console.ForegroundColor = ConsoleColor.DarkGray;
|
| 293 |
+
Console.Write("> ");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
Console.ResetColor();
|
| 295 |
+
var query = Console.ReadLine()?.Trim();
|
| 296 |
+
if (string.IsNullOrEmpty(query)) continue;
|
| 297 |
+
if (query.Equals("exit", StringComparison.OrdinalIgnoreCase)) break;
|
| 298 |
+
|
| 299 |
+
var searchSw = Stopwatch.StartNew();
|
| 300 |
+
var exclusions = CacheManager.LoadExclusions();
|
| 301 |
+
var results = SearchEngine.Search(index, query, 20, false, exclusions);
|
| 302 |
+
searchSw.Stop();
|
| 303 |
+
|
| 304 |
Console.ForegroundColor = ConsoleColor.DarkGray;
|
| 305 |
+
Console.WriteLine($" {results.Count} results | {searchSw.Elapsed.TotalMilliseconds:F3}ms");
|
| 306 |
Console.ResetColor();
|
| 307 |
+
|
| 308 |
+
foreach (var r in results.Take(10))
|
| 309 |
+
{
|
| 310 |
+
var color = r.Kind switch
|
| 311 |
+
{
|
| 312 |
+
ResultKind.App => ConsoleColor.Green,
|
| 313 |
+
ResultKind.Document => ConsoleColor.Yellow,
|
| 314 |
+
ResultKind.Image => ConsoleColor.Magenta,
|
| 315 |
+
ResultKind.Video => ConsoleColor.Red,
|
| 316 |
+
ResultKind.Audio => ConsoleColor.Blue,
|
| 317 |
+
ResultKind.Archive => ConsoleColor.DarkYellow,
|
| 318 |
+
ResultKind.Folder => ConsoleColor.Cyan,
|
| 319 |
+
_ => ConsoleColor.Gray
|
| 320 |
+
};
|
| 321 |
+
Console.ForegroundColor = color;
|
| 322 |
+
Console.Write($" [{GetBadgeLabel(r.Kind),-4}] ");
|
| 323 |
+
Console.ResetColor();
|
| 324 |
+
Console.WriteLine($"{r.Name} β {r.FullPath}");
|
| 325 |
+
}
|
| 326 |
+
if (results.Count > 10)
|
| 327 |
+
{
|
| 328 |
+
Console.ForegroundColor = ConsoleColor.DarkGray;
|
| 329 |
+
Console.WriteLine($" ... and {results.Count - 10} more");
|
| 330 |
+
Console.ResetColor();
|
| 331 |
+
}
|
| 332 |
+
Console.WriteLine();
|
| 333 |
}
|
|
|
|
| 334 |
}
|
| 335 |
|
| 336 |
WaitExit();
|