diff --git a/Source/Core/DiscIO/NANDImporter.cpp b/Source/Core/DiscIO/NANDImporter.cpp index 4477621984..5ef1d68c4b 100644 --- a/Source/Core/DiscIO/NANDImporter.cpp +++ b/Source/Core/DiscIO/NANDImporter.cpp @@ -129,7 +129,8 @@ bool NANDImporter::ExtractFiles() constexpr u16 CLUSTER_CHAIN_END = 0xFFFB; m_progress_cur = 0; m_progress_max = std::ranges::count(m_superblock->fat, CLUSTER_CHAIN_END); - return ProcessEntry(0, ""); + std::bitset visited; + return ProcessEntry(0, "", &visited); } std::string NANDImporter::GetPath(const NANDFSTEntry& entry, const std::string& parent_path) @@ -138,7 +139,8 @@ std::string NANDImporter::GetPath(const NANDFSTEntry& entry, const std::string& return parent_path + '/' + Common::EscapeFileName(name); } -bool NANDImporter::ProcessEntry(u16 entry_number, const std::string& parent_path) +bool NANDImporter::ProcessEntry(u16 entry_number, const std::string& parent_path, + std::bitset* visited) { while (entry_number != 0xffff) { @@ -148,6 +150,13 @@ bool NANDImporter::ProcessEntry(u16 entry_number, const std::string& parent_path return false; } + if ((*visited)[entry_number]) + { + ERROR_LOG_FMT(DISCIO, "FST entry number {} visited multiple times", entry_number); + return false; + } + + (*visited)[entry_number] = true; const NANDFSTEntry entry = m_superblock->fst[entry_number]; const std::string path = entry_number == 0 ? parent_path : GetPath(entry, parent_path); @@ -165,7 +174,7 @@ bool NANDImporter::ProcessEntry(u16 entry_number, const std::string& parent_path else if (type == Type::Directory) { File::CreateDir(m_nand_root + path); - if (!ProcessEntry(entry.sub, path)) + if (!ProcessEntry(entry.sub, path, visited)) return false; } else diff --git a/Source/Core/DiscIO/NANDImporter.h b/Source/Core/DiscIO/NANDImporter.h index f22f043709..6851466f66 100644 --- a/Source/Core/DiscIO/NANDImporter.h +++ b/Source/Core/DiscIO/NANDImporter.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include #include @@ -59,13 +60,14 @@ public: }; static_assert(sizeof(NANDFSTEntry) == 0x20, "Wrong size"); + static constexpr u16 FSTEntryCount = 0x17FF; struct NANDSuperblock { std::array magic; // "SFFS" Common::BigEndianValue version; Common::BigEndianValue unknown; std::array, 0x8000> fat; - std::array fst; + std::array fst; std::array pad; }; static_assert(sizeof(NANDSuperblock) == 0x40000, "Wrong size"); @@ -78,7 +80,8 @@ private: bool ExtractFiles(); std::string GetPath(const NANDFSTEntry& entry, const std::string& parent_path); std::string FormatDebugString(const NANDFSTEntry& entry); - bool ProcessEntry(u16 entry_number, const std::string& parent_path); + bool ProcessEntry(u16 entry_number, const std::string& parent_path, + std::bitset* visited); std::vector GetEntryData(const NANDFSTEntry& entry) const; void ExportKeys();