summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2026-06-10 17:38:48 +0200
committerGitHub <noreply@github.com>2026-06-10 17:38:48 +0200
commit1bc93fd16d5a452bedcc5437923abd0d9fcb8c52 (patch)
tree875365d0871e6b6b6cd9f48cf4f6fd3041e33730
parentaabea5b1e3f13177aa302f99b435a70ad6a9b0b1 (diff)
parent29f1bc4d4c079610b3c9c83930733df856c6f61f (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.cpp15
-rw-r--r--Source/Core/DiscIO/NANDImporter.h7
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();