Skip to content

Commit c171115

Browse files
小更新:增加了坏簇检测和丢弃功能。
1 parent 4275f1f commit c171115

14 files changed

Lines changed: 625 additions & 35 deletions

Filerestore_CLI/Filerestore_CLI.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@
196196
<ClCompile Include="src\fileRestore\MFTReader.cpp" />
197197
<ClCompile Include="src\fileRestore\OverwriteDetectionThreadPool.cpp" />
198198
<ClCompile Include="src\fileRestore\OverwriteDetector.cpp" />
199+
<ClCompile Include="src\fileRestore\ClusterFilteredReader.cpp" />
199200
<ClCompile Include="src\fileRestore\PathResolver.cpp" />
200201
<ClCompile Include="src\utils\ProgressBar.cpp" />
201202
<ClCompile Include="src\fileRestore\SignatureScanThreadPool.cpp" />
@@ -250,6 +251,7 @@
250251
<ClInclude Include="src\fileRestore\MFTStructures.h" />
251252
<ClInclude Include="src\fileRestore\OverwriteDetectionThreadPool.h" />
252253
<ClInclude Include="src\fileRestore\OverwriteDetector.h" />
254+
<ClInclude Include="src\fileRestore\ClusterFilteredReader.h" />
253255
<ClInclude Include="src\fileRestore\PathResolver.h" />
254256
<ClInclude Include="src\utils\ProgressBar.h" />
255257
<ClInclude Include="src\fileRestore\SignatureScanThreadPool.h" />

Filerestore_CLI/Filerestore_CLI.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@
182182
<ClCompile Include="src\fileRestore\OverwriteDetectionThreadPool.cpp">
183183
<Filter>源文件\FileRestore\Detection</Filter>
184184
</ClCompile>
185+
<ClCompile Include="src\fileRestore\ClusterFilteredReader.cpp">
186+
<Filter>源文件\FileRestore\Detection</Filter>
187+
</ClCompile>
185188
<!-- FileRestore\ML - 机器学习 -->
186189
<ClCompile Include="src\fileRestore\MLClassifier.cpp">
187190
<Filter>源文件\FileRestore\ML</Filter>
@@ -358,6 +361,9 @@
358361
<ClInclude Include="src\fileRestore\OverwriteDetectionThreadPool.h">
359362
<Filter>头文件\FileRestore\Detection</Filter>
360363
</ClInclude>
364+
<ClInclude Include="src\fileRestore\ClusterFilteredReader.h">
365+
<Filter>头文件\FileRestore\Detection</Filter>
366+
</ClInclude>
361367
<!-- FileRestore\ML - 机器学习 -->
362368
<ClInclude Include="src\fileRestore\MLClassifier.h">
363369
<Filter>头文件\FileRestore\ML</Filter>

Filerestore_CLI/src/commands/CarveCommands.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,10 @@ void CarveCommand::Execute(string command) {
384384
auto result = recovery.RecoverZipWithEOCDScan(info.startLCN, outputPath, config);
385385
if (result.success) {
386386
recoveredCount++;
387-
} else if (recovery.RecoverCarvedFile(info, outputPath)) {
387+
} else if (recovery.RecoverCarvedFile(info, outputPath, nullptr)) {
388388
recoveredCount++;
389389
}
390-
} else if (recovery.RecoverCarvedFile(info, outputPath)) {
390+
} else if (recovery.RecoverCarvedFile(info, outputPath, nullptr)) {
391391
recoveredCount++;
392392
}
393393

@@ -609,10 +609,15 @@ void CarveRecoverCommand::Execute(string command) {
609609
// 普通恢复模式
610610
cout << "Using standard recovery mode..." << endl;
611611

612-
if (recovery.RecoverCarvedFile(info, outputPath)) {
612+
ClusterHealthReport carveHealth;
613+
if (recovery.RecoverCarvedFile(info, outputPath, &carveHealth)) {
613614
success = true;
614615
cout << "\n=== Recovery Successful ===" << endl;
615616
cout << "File saved to: " << outputPath << endl;
617+
if (carveHealth.overwrittenClusters > 0) {
618+
cout << "Cluster health: " << fixed << setprecision(1)
619+
<< carveHealth.healthPercentage << "% healthy" << endl;
620+
}
616621

617622
// 如果是 ZIP 且启用了 CRC 验证
618623
if (info.extension == "zip" && verifyCRC) {
@@ -1960,22 +1965,33 @@ void CarveRecoverPageCommand::Execute(string command) {
19601965
pageRecovered++;
19611966
} else {
19621967
// EOCD扫描失败,回退到普通恢复
1963-
if (recovery.RecoverCarvedFile(info, outputPath)) {
1964-
cout << " [" << pageIdx << "] Recovered (fallback): " << filename << " [NO EOCD]" << endl;
1968+
ClusterHealthReport batchHealth;
1969+
if (recovery.RecoverCarvedFile(info, outputPath, &batchHealth)) {
1970+
cout << " [" << pageIdx << "] Recovered (fallback): " << filename << " [NO EOCD]";
1971+
if (batchHealth.overwrittenClusters > 0) {
1972+
cout << " [" << fixed << setprecision(1) << batchHealth.healthPercentage << "% healthy]";
1973+
}
1974+
cout << endl;
19651975
pageRecovered++;
19661976
} else {
19671977
cout << " [" << pageIdx << "] FAILED to recover" << endl;
19681978
}
19691979
}
1970-
} else if (recovery.RecoverCarvedFile(info, outputPath)) {
1971-
cout << " [" << pageIdx << "] Recovered: " << filename;
1972-
if (forceMode && info.confidence < 0.5) {
1973-
cout << " [FORCED]";
1974-
}
1975-
cout << endl;
1976-
pageRecovered++;
19771980
} else {
1978-
cout << " [" << pageIdx << "] FAILED to recover" << endl;
1981+
ClusterHealthReport batchHealth;
1982+
if (recovery.RecoverCarvedFile(info, outputPath, &batchHealth)) {
1983+
cout << " [" << pageIdx << "] Recovered: " << filename;
1984+
if (forceMode && info.confidence < 0.5) {
1985+
cout << " [FORCED]";
1986+
}
1987+
if (batchHealth.overwrittenClusters > 0) {
1988+
cout << " [" << fixed << setprecision(1) << batchHealth.healthPercentage << "% healthy]";
1989+
}
1990+
cout << endl;
1991+
pageRecovered++;
1992+
} else {
1993+
cout << " [" << pageIdx << "] FAILED to recover" << endl;
1994+
}
19791995
}
19801996
}
19811997

Filerestore_CLI/src/commands/UsnRecoverCommands.cpp

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -771,12 +771,27 @@ void RecoverCommand::Execute(string command) {
771771
recResult.status == UsnRecoveryStatus::RESIDENT_DATA ||
772772
recResult.status == UsnRecoveryStatus::PARTIAL_RECOVERY) {
773773
string path = UsnTargetedRecovery::WideToNarrow(recResult.recoveredPath);
774-
cout << "\n=== 恢复成功 ===" << endl;
774+
if (recResult.usedClusterFiltering && recResult.clusterHealth.overwrittenClusters > 0) {
775+
cout << "\n=== 部分恢复 ===" << endl;
776+
} else {
777+
cout << "\n=== 恢复成功 ===" << endl;
778+
}
775779
cout << "文件大小: " << recResult.recoveredSize << " bytes" << endl;
776780
cout << "已保存到: " << path << endl;
777781
if (recResult.signatureMatched) {
778782
cout << "签名验证: 通过 (" << recResult.detectedType << ")" << endl;
779783
}
784+
if (recResult.usedClusterFiltering && recResult.clusterHealth.overwrittenClusters > 0) {
785+
cout << "簇健康: " << recResult.clusterHealth.goodClusters << "/"
786+
<< recResult.clusterHealth.totalClusters << " ("
787+
<< fixed << setprecision(1) << recResult.clusterHealth.healthPercentage
788+
<< "%) | 覆写簇: " << recResult.clusterHealth.overwrittenClusters
789+
<< " | 检测: " << fixed << setprecision(1)
790+
<< recResult.clusterHealth.detectionTimeMs << "ms" << endl;
791+
if (recResult.clusterHealth.formatTruncated) {
792+
cout << "格式截断: 移除了 " << recResult.clusterHealth.truncatedBytes << " bytes" << endl;
793+
}
794+
}
780795
return;
781796
} else {
782797
cout << "\nMFT 直接恢复失败: " << recResult.statusMessage << endl;
@@ -807,9 +822,21 @@ void RecoverCommand::Execute(string command) {
807822
recResult.status == UsnRecoveryStatus::RESIDENT_DATA ||
808823
recResult.status == UsnRecoveryStatus::PARTIAL_RECOVERY) {
809824
string path = UsnTargetedRecovery::WideToNarrow(recResult.recoveredPath);
810-
cout << "\n=== 恢复成功 ===" << endl;
825+
if (recResult.usedClusterFiltering && recResult.clusterHealth.overwrittenClusters > 0) {
826+
cout << "\n=== 部分恢复 ===" << endl;
827+
} else {
828+
cout << "\n=== 恢复成功 ===" << endl;
829+
}
811830
cout << "文件大小: " << recResult.recoveredSize << " bytes" << endl;
812831
cout << "已保存到: " << path << endl;
832+
if (recResult.usedClusterFiltering && recResult.clusterHealth.overwrittenClusters > 0) {
833+
cout << "簇健康: " << recResult.clusterHealth.goodClusters << "/"
834+
<< recResult.clusterHealth.totalClusters << " ("
835+
<< fixed << setprecision(1) << recResult.clusterHealth.healthPercentage
836+
<< "%) | 覆写簇: " << recResult.clusterHealth.overwrittenClusters
837+
<< " | 检测: " << fixed << setprecision(1)
838+
<< recResult.clusterHealth.detectionTimeMs << "ms" << endl;
839+
}
813840
return;
814841
}
815842

@@ -1099,16 +1126,26 @@ void RecoverCommand::Execute(string command) {
10991126
cout << "CRC校验: " << (result.crcValid ? "通过" : "警告") << endl;
11001127
} else {
11011128
// 回退到普通恢复
1102-
recovered = carveRecovery.RecoverCarvedFile(selected.carveInfo, outputPath);
1129+
ClusterHealthReport carveHealth;
1130+
recovered = carveRecovery.RecoverCarvedFile(selected.carveInfo, outputPath, &carveHealth);
11031131
if (recovered) {
11041132
cout << "恢复成功 (无EOCD,使用估算大小)" << endl;
1133+
if (carveHealth.overwrittenClusters > 0) {
1134+
cout << "簇健康: " << fixed << setprecision(1)
1135+
<< carveHealth.healthPercentage << "%" << endl;
1136+
}
11051137
}
11061138
}
11071139
} else {
1108-
recovered = carveRecovery.RecoverCarvedFile(selected.carveInfo, outputPath);
1140+
ClusterHealthReport carveHealth;
1141+
recovered = carveRecovery.RecoverCarvedFile(selected.carveInfo, outputPath, &carveHealth);
11091142
if (recovered) {
11101143
cout << "恢复成功!" << endl;
11111144
cout << "文件大小: " << selected.carveInfo.fileSize << " bytes" << endl;
1145+
if (carveHealth.overwrittenClusters > 0) {
1146+
cout << "簇健康: " << fixed << setprecision(1)
1147+
<< carveHealth.healthPercentage << "%" << endl;
1148+
}
11121149
}
11131150
}
11141151

@@ -1161,16 +1198,26 @@ void RecoverCommand::Execute(string command) {
11611198
cout << "文件大小: " << result.actualSize << " bytes" << endl;
11621199
cout << "CRC校验: " << (result.crcValid ? "通过" : "警告") << endl;
11631200
} else {
1164-
recovered = carveRecovery.RecoverCarvedFile(best.carveInfo, outputPath);
1201+
ClusterHealthReport carveHealth;
1202+
recovered = carveRecovery.RecoverCarvedFile(best.carveInfo, outputPath, &carveHealth);
11651203
if (recovered) {
11661204
cout << "恢复成功 (无EOCD,使用估算大小)" << endl;
1205+
if (carveHealth.overwrittenClusters > 0) {
1206+
cout << "簇健康: " << fixed << setprecision(1)
1207+
<< carveHealth.healthPercentage << "%" << endl;
1208+
}
11671209
}
11681210
}
11691211
} else {
1170-
recovered = carveRecovery.RecoverCarvedFile(best.carveInfo, outputPath);
1212+
ClusterHealthReport carveHealth;
1213+
recovered = carveRecovery.RecoverCarvedFile(best.carveInfo, outputPath, &carveHealth);
11711214
if (recovered) {
11721215
cout << "恢复成功!" << endl;
11731216
cout << "文件大小: " << best.carveInfo.fileSize << " bytes" << endl;
1217+
if (carveHealth.overwrittenClusters > 0) {
1218+
cout << "簇健康: " << fixed << setprecision(1)
1219+
<< carveHealth.healthPercentage << "%" << endl;
1220+
}
11741221
}
11751222
}
11761223

Filerestore_CLI/src/core/FileRestoreAPI.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "FileCarver.h"
88
#include "OverwriteDetector.h"
99
#include "CarvedFileTypes.h"
10+
#include "ClusterFilteredReader.h"
1011
#include <Windows.h>
1112
#include <sstream>
1213
#include <iomanip>
@@ -521,12 +522,15 @@ Result<RecoveryResult> FileRestoreAPI::RecoverCarvedFile(
521522
);
522523
}
523524

524-
// 读取文件数据
525-
ULONGLONG bytesPerCluster = pImpl->reader->GetBytesPerCluster();
526-
ULONGLONG clustersNeeded = (file.fileSize + file.offsetInCluster + bytesPerCluster - 1) / bytesPerCluster;
525+
// 使用 ClusterFilteredReader 进行过滤读取
526+
ClusterFilteredReader filteredReader(pImpl->reader.get());
527+
ClusterHealthReport health;
528+
std::wstring wExt(file.extension.begin(), file.extension.end());
529+
std::wstring wFileName = L"file." + wExt;
527530

528-
std::vector<BYTE> buffer;
529-
if (!pImpl->reader->ReadClusters(file.startCluster, clustersNeeded, buffer)) {
531+
std::vector<BYTE> fileData;
532+
if (!filteredReader.ReadContiguous(file.startCluster, file.offsetInCluster,
533+
file.fileSize, wFileName, fileData, health)) {
530534
return Result<RecoveryResult>::Failure(
531535
ErrorCode::IOReadFailed,
532536
"Failed to read file data"
@@ -557,15 +561,15 @@ Result<RecoveryResult> FileRestoreAPI::RecoverCarvedFile(
557561
DWORD bytesWritten;
558562
BOOL writeSuccess = WriteFile(
559563
hFile,
560-
buffer.data() + file.offsetInCluster,
561-
(DWORD)file.fileSize,
564+
fileData.data(),
565+
(DWORD)fileData.size(),
562566
&bytesWritten,
563567
NULL
564568
);
565569

566570
CloseHandle(hFile);
567571

568-
if (!writeSuccess || bytesWritten != file.fileSize) {
572+
if (!writeSuccess || bytesWritten != fileData.size()) {
569573
return Result<RecoveryResult>::Failure(
570574
ErrorCode::IOWriteFailed,
571575
"Failed to write file data"
@@ -575,8 +579,9 @@ Result<RecoveryResult> FileRestoreAPI::RecoverCarvedFile(
575579
RecoveryResult result;
576580
result.success = true;
577581
result.outputPath = outputPath;
578-
result.bytesRecovered = file.fileSize;
579-
result.overwritePercentage = 0.0;
582+
result.bytesRecovered = fileData.size();
583+
result.clusterHealthPercentage = health.healthPercentage;
584+
result.overwritePercentage = 100.0 - health.healthPercentage;
580585

581586
return Result<RecoveryResult>::Success(std::move(result));
582587
}

Filerestore_CLI/src/core/FileRestoreAPI.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,11 @@ struct RecoveryResult {
131131
std::string outputPath; // 输出文件路径
132132
FileSize bytesRecovered; // 恢复的字节数
133133
double overwritePercentage; // 覆盖百分比
134+
double clusterHealthPercentage; // 簇健康百分比
134135

135136
RecoveryResult()
136137
: success(false), bytesRecovered(0), overwritePercentage(0.0)
138+
, clusterHealthPercentage(100.0)
137139
{}
138140
};
139141

0 commit comments

Comments
 (0)