1
0
Fork 0
forked from suyu/suyu

Merge pull request #1747 from DarkLordZach/exefs-lfs

patch_manager: Add support for applying LayeredFS patches to ExeFS
This commit is contained in:
bunnei 2018-11-23 23:31:48 -05:00 committed by GitHub
commit 67ff974387
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 65 additions and 2 deletions

View file

@ -26,6 +26,11 @@ namespace FileSys {
constexpr u64 SINGLE_BYTE_MODULUS = 0x100; constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
"main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2",
"subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9",
};
struct NSOBuildHeader { struct NSOBuildHeader {
u32_le magic; u32_le magic;
INSERT_PADDING_BYTES(0x3C); INSERT_PADDING_BYTES(0x3C);
@ -57,6 +62,15 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
if (exefs == nullptr) if (exefs == nullptr)
return exefs; return exefs;
if (Settings::values.dump_exefs) {
LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
VfsRawCopyD(exefs, exefs_dir);
}
}
const auto installed = Service::FileSystem::GetUnionContents(); const auto installed = Service::FileSystem::GetUnionContents();
// Game Updates // Game Updates
@ -70,6 +84,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
exefs = update->GetExeFS(); exefs = update->GetExeFS();
} }
// LayeredExeFS
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
if (load_dir != nullptr && load_dir->GetSize() > 0) {
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(
patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
std::vector<VirtualDir> layers;
layers.reserve(patch_dirs.size() + 1);
for (const auto& subdir : patch_dirs) {
auto exefs_dir = subdir->GetSubdirectory("exefs");
if (exefs_dir != nullptr)
layers.push_back(std::move(exefs_dir));
}
layers.push_back(exefs);
auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
if (layered != nullptr) {
LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully");
exefs = std::move(layered);
}
}
return exefs; return exefs;
} }
@ -314,18 +352,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
if (IsDirValidAndNonEmpty(exefs_dir)) { if (IsDirValidAndNonEmpty(exefs_dir)) {
bool ips = false; bool ips = false;
bool ipswitch = false; bool ipswitch = false;
bool layeredfs = false;
for (const auto& file : exefs_dir->GetFiles()) { for (const auto& file : exefs_dir->GetFiles()) {
if (file->GetExtension() == "ips") if (file->GetExtension() == "ips") {
ips = true; ips = true;
else if (file->GetExtension() == "pchtxt") } else if (file->GetExtension() == "pchtxt") {
ipswitch = true; ipswitch = true;
} else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(),
file->GetName()) != EXEFS_FILE_NAMES.end()) {
layeredfs = true;
}
} }
if (ips) if (ips)
AppendCommaIfNotEmpty(types, "IPS"); AppendCommaIfNotEmpty(types, "IPS");
if (ipswitch) if (ipswitch)
AppendCommaIfNotEmpty(types, "IPSwitch"); AppendCommaIfNotEmpty(types, "IPSwitch");
if (layeredfs)
AppendCommaIfNotEmpty(types, "LayeredExeFS");
} }
if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs")))
AppendCommaIfNotEmpty(types, "LayeredFS"); AppendCommaIfNotEmpty(types, "LayeredFS");

View file

@ -403,6 +403,7 @@ struct Values {
bool use_gdbstub; bool use_gdbstub;
u16 gdbstub_port; u16 gdbstub_port;
std::string program_args; std::string program_args;
bool dump_exefs;
bool dump_nso; bool dump_nso;
// WebService // WebService

View file

@ -432,6 +432,7 @@ void Config::ReadValues() {
Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool(); Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool();
Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt(); Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt();
Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString(); Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString();
Settings::values.dump_exefs = qt_config->value("dump_exefs", false).toBool();
Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool(); Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool();
qt_config->endGroup(); qt_config->endGroup();
@ -638,6 +639,7 @@ void Config::SaveValues() {
qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub); qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub);
qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port); qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port);
qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args)); qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args));
qt_config->setValue("dump_exefs", Settings::values.dump_exefs);
qt_config->setValue("dump_nso", Settings::values.dump_nso); qt_config->setValue("dump_nso", Settings::values.dump_nso);
qt_config->endGroup(); qt_config->endGroup();

View file

@ -34,6 +34,7 @@ void ConfigureDebug::setConfiguration() {
ui->toggle_console->setChecked(UISettings::values.show_console); ui->toggle_console->setChecked(UISettings::values.show_console);
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
ui->dump_exefs->setChecked(Settings::values.dump_exefs);
ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso); ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso);
} }
@ -43,6 +44,7 @@ void ConfigureDebug::applyConfiguration() {
UISettings::values.show_console = ui->toggle_console->isChecked(); UISettings::values.show_console = ui->toggle_console->isChecked();
Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); Settings::values.log_filter = ui->log_filter_edit->text().toStdString();
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
Settings::values.dump_exefs = ui->dump_exefs->isChecked();
Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked(); Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked();
Debugger::ToggleConsole(); Debugger::ToggleConsole();
Log::Filter filter; Log::Filter filter;

View file

@ -145,6 +145,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="dump_exefs">
<property name="whatsThis">
<string>When checked, any game that yuzu loads will have its ExeFS dumped to the yuzu/dump directory.</string>
</property>
<property name="text">
<string>Dump ExeFS</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View file

@ -366,6 +366,7 @@ void Config::ReadValues() {
Settings::values.gdbstub_port = Settings::values.gdbstub_port =
static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689)); static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689));
Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", ""); Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", "");
Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false);
Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false); Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false);
// Web Service // Web Service

View file

@ -206,6 +206,8 @@ log_filter = *:Trace
# Port for listening to GDB connections. # Port for listening to GDB connections.
use_gdbstub=false use_gdbstub=false
gdbstub_port=24689 gdbstub_port=24689
# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them
dump_exefs=false
# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them # Determines whether or not yuzu will dump all NSOs it attempts to load while loading them
dump_nso=false dump_nso=false