diff options
| author | JosJuice <josjuice@gmail.com> | 2026-06-10 17:38:48 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-06-10 17:38:48 +0200 |
| commit | 1bc93fd16d5a452bedcc5437923abd0d9fcb8c52 (patch) | |
| tree | 875365d0871e6b6b6cd9f48cf4f6fd3041e33730 | |
| parent | aabea5b1e3f13177aa302f99b435a70ad6a9b0b1 (diff) | |
| parent | 29f1bc4d4c079610b3c9c83930733df856c6f61f (diff) | |
Merge pull request #14672 from AdmiralCurtiss/recursive-nand
NANDImporter: Abort extraction if a NAND FST entry is visited more than once
| -rw-r--r-- | Source/Core/DiscIO/NANDImporter.cpp | 15 | ||||
| -rw-r--r-- | Source/Core/DiscIO/NANDImporter.h | 7 |
2 files changed, 17 insertions, 5 deletions
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<FSTEntryCount> 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<FSTEntryCount>* 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 <array> +#include <bitset> #include <functional> #include <memory> #include <string> @@ -59,13 +60,14 @@ public: }; static_assert(sizeof(NANDFSTEntry) == 0x20, "Wrong size"); + static constexpr u16 FSTEntryCount = 0x17FF; struct NANDSuperblock { std::array<char, 4> magic; // "SFFS" Common::BigEndianValue<u32> version; Common::BigEndianValue<u32> unknown; std::array<Common::BigEndianValue<u16>, 0x8000> fat; - std::array<NANDFSTEntry, 0x17FF> fst; + std::array<NANDFSTEntry, FSTEntryCount> fst; std::array<u8, 0x14> 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<FSTEntryCount>* visited); std::vector<u8> GetEntryData(const NANDFSTEntry& entry) const; void ExportKeys(); |
