Skip to content
API Documentation
BastionGuard™
FilesystemRecovery Class Reference

#include <filesystem_recovery.hpp>

Static Public Member Functions

static bool recover_supported_filesystems (DiskReader &reader, const ScanReport &report, const std::string &output_dir, std::vector< RecoveredFileRecord > &recovered, std::vector< std::string > &logs, std::string &error)

Detailed Description

Definition at line 18 of file filesystem_recovery.hpp.

Member Function Documentation

◆ recover_supported_filesystems()

bool FilesystemRecovery::recover_supported_filesystems ( DiskReader & reader,
const ScanReport & report,
const std::string & output_dir,
std::vector< RecoveredFileRecord > & recovered,
std::vector< std::string > & logs,
std::string & error )
static

Definition at line 831 of file filesystem_recovery.cpp.

836 {
837 std::set<uint64_t> ntfs_offsets;
838 std::set<uint64_t> fat32_offsets;
839 std::set<uint64_t> exfat_offsets;
840 std::set<uint64_t> ext4_offsets;
841 std::set<uint64_t> btrfs_offsets;
842 std::set<uint64_t> xfs_offsets;
843 std::set<uint64_t> hfs_offsets;
844 for (const auto& r : report.results) {
845 if (r.type == "NTFS volume" || r.type == "Lost NTFS partition candidate" || r.type == "NTFS candidate") ntfs_offsets.insert(r.offset_bytes);
846 if (r.type == "FAT32 volume" || r.type == "Lost FAT32 partition candidate") fat32_offsets.insert(r.offset_bytes);
847 if (r.type == "exFAT volume" || r.type == "Lost exFAT partition candidate") exfat_offsets.insert(r.offset_bytes);
848 if (r.type == "ext4 volume" || r.type == "Lost ext4 partition candidate" || r.type == "ext4 candidate") ext4_offsets.insert(r.offset_bytes);
849 if (r.type == "Btrfs volume" || r.type == "Lost Btrfs partition candidate" || r.type == "Btrfs candidate") btrfs_offsets.insert(r.offset_bytes);
850 if (r.type == "XFS volume" || r.type == "Lost XFS partition candidate") xfs_offsets.insert(r.offset_bytes);
851 if (r.type == "HFS+ volume" || r.type == "HFSX volume" || r.type == "Lost HFS+ partition candidate") hfs_offsets.insert(r.offset_bytes);
852 }
853
854 try {
855 fs::create_directories(fs::path(output_dir) / "filesystem_recovered" / "ntfs");
856 fs::create_directories(fs::path(output_dir) / "filesystem_recovered" / "fat32");
857 fs::create_directories(fs::path(output_dir) / "filesystem_recovered" / "exfat");
858 fs::create_directories(fs::path(output_dir) / "filesystem_recovered" / "ext4");
859 fs::create_directories(fs::path(output_dir) / "filesystem_recovered" / "btrfs");
860 fs::create_directories(fs::path(output_dir) / "filesystem_recovered" / "xfs");
861 fs::create_directories(fs::path(output_dir) / "filesystem_recovered" / "hfs");
862 } catch (const std::exception& ex) {
863 error = ex.what();
864 return false;
865 }
866
867
868 for (uint64_t offset : ntfs_offsets) {
869 NtfsRecovery ntfs(reader);
870 std::string local_error;
871 if (!ntfs.recover(offset, output_dir, recovered, logs, local_error)) {
872 logs.push_back(trs("NTFS recovery skipped or failed at offset") + std::string(" ") + std::to_string(offset) + ": " + local_error);
873 }
874 }
875
876 for (uint64_t offset : fat32_offsets) {
877 Fat32Recovery fat32(reader);
878 const fs::path out_root = fs::path(output_dir) / "filesystem_recovered" / "fat32" / ("offset_" + std::to_string(offset));
879 std::string local_error;
880 if (!fat32.recover(offset, out_root, recovered, logs, local_error)) {
881 logs.push_back(trs("FAT32 recovery skipped or failed at offset") + std::string(" ") + std::to_string(offset) + ": " + local_error);
882 }
883 }
884
885 for (uint64_t offset : exfat_offsets) {
886 ExfatRecovery exfat(reader);
887 const fs::path out_root = fs::path(output_dir) / "filesystem_recovered" / "exfat" / ("offset_" + std::to_string(offset));
888 std::string local_error;
889 if (!exfat.recover(offset, out_root, recovered, logs, local_error)) {
890 logs.push_back(trs("exFAT recovery skipped or failed at offset") + std::string(" ") + std::to_string(offset) + ": " + local_error);
891 }
892 }
893
894 for (uint64_t offset : ext4_offsets) {
895 Ext4Recovery ext4(reader);
896 std::string local_error;
897 if (!ext4.recover(offset, output_dir, recovered, logs, local_error)) {
898 logs.push_back(trs("ext4 recovery skipped or failed at offset") + std::string(" ") + std::to_string(offset) + ": " + local_error);
899 }
900 }
901
902 for (uint64_t offset : btrfs_offsets) {
903 BtrfsRecovery btrfs(reader);
904 std::string local_error;
905 if (!btrfs.recover(offset, output_dir, recovered, logs, local_error)) {
906 logs.push_back(trs("Btrfs recovery skipped or failed at offset") + std::string(" ") + std::to_string(offset) + ": " + local_error);
907 }
908 }
909
910 for (uint64_t offset : xfs_offsets) {
911 XfsRecovery xfs(reader);
912 std::string local_error;
913 if (!xfs.recover(offset, output_dir, recovered, logs, local_error)) {
914 logs.push_back(trs("XFS recovery skipped or failed at offset") + std::string(" ") + std::to_string(offset) + ": " + local_error);
915 }
916 }
917
918 for (uint64_t offset : hfs_offsets) {
919 HfsRecovery hfs(reader);
920 std::string local_error;
921 if (!hfs.recover(offset, output_dir, recovered, logs, local_error)) {
922 logs.push_back(trs("HFS+ recovery skipped or failed at offset") + std::string(" ") + std::to_string(offset) + ": " + local_error);
923 }
924 }
925
926 // ---- Optional file carving pass ----
927 //
928 // Carving is opt-in via environment variable BASTIONGUARD_CARVING=1.
929 // It runs AFTER all filesystem-specific recovery has been tried,
930 // so it complements (not replaces) the per-FS results. The carving
931 // pass is filesystem-agnostic: it recognises file content directly
932 // by magic-byte signatures and is the right tool for cases where
933 // filesystem metadata (MFT/inode table/catalog) is destroyed but
934 // content blocks remain intact. It also recovers files with any
935 // FS where deletion zeros the metadata but not the data.
936 //
937 // We make it opt-in (rather than always-on) because:
938 // * On a healthy disk, every file is also recovered by FS-aware
939 // recovery -- carving would produce duplicates.
940 // * Carving has a non-zero false-positive rate.
941 // * Carving is slow on big disks (full sequential scan).
942 {
943 const char* env = std::getenv("BASTIONGUARD_CARVING");
944 if (env != nullptr && env[0] == '1') {
945 carving::CarvingOptions opts;
946 // Defaults are reasonable (16 GiB scan limit, 500 MiB per
947 // file). The user can override these by editing the source
948 // for now; a CLI flag is a future addition.
949 std::string carve_err;
950 const size_t before = recovered.size();
951 carving::run_carving(reader, output_dir, opts, recovered,
952 logs, carve_err);
953 const size_t carved = recovered.size() - before;
954 if (!carve_err.empty()) {
955 logs.push_back(trs("Carving error: ") + carve_err);
956 }
957 logs.push_back(trs("Carving pass added ") +
958 std::to_string(carved) + trs(" file(s)"));
959 }
960 }
961
962 return true;
963}
std::string trs(const char *msgid)
Definition i18n.cpp:22
bool run_carving(DiskReader &reader, const std::string &output_dir, const CarvingOptions &opts, std::vector< RecoveredFileRecord > &recovered, std::vector< std::string > &logs, std::string &error)
Definition carving.cpp:954
std::vector< ScanResult > results
Definition models.hpp:40

References BtrfsRecovery::recover(), Ext4Recovery::recover(), NtfsRecovery::recover(), ScanReport::results, carving::run_carving(), and trs().

Referenced by RecoveryExporter::export_results_and_carve().


The documentation for this class was generated from the following files: