move fw install

Signed-off-by: crueter <crueter@eden-emu.dev>
This commit is contained in:
crueter 2025-07-22 17:05:57 -04:00
parent 11db0f0dbf
commit 7a0712af1f
Signed by: crueter
GPG key ID: 425ACD2D4830EBC6
4 changed files with 155 additions and 97 deletions

View file

@ -1,6 +1,7 @@
#include "qt_common.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "uisettings.h"
#include <QGuiApplication>
@ -21,17 +22,18 @@ MetadataResult ResetMetadata()
{
if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir)
/ "game_list/")) {
return Empty;
return MetadataResult::Empty;
} else if (Common::FS::RemoveDirRecursively(
Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) {
return Success;
return MetadataResult::Success;
UISettings::values.is_game_list_reload_pending.exchange(true);
} else {
return Failure;
return MetadataResult::Failure;
}
}
Core::Frontend::WindowSystemType GetWindowSystemType() {
Core::Frontend::WindowSystemType GetWindowSystemType()
{
// Determine WSI type based on Qt platform.
QString platform_name = QGuiApplication::platformName();
if (platform_name == QStringLiteral("windows"))
@ -51,7 +53,8 @@ Core::Frontend::WindowSystemType GetWindowSystemType() {
return Core::Frontend::WindowSystemType::Windows;
} // namespace Core::Frontend::WindowSystemType
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) {
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
{
Core::Frontend::EmuWindow::WindowSystemInfo wsi;
wsi.type = GetWindowSystemType();
@ -59,8 +62,8 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
// Our Win32 Qt external doesn't have the private API.
wsi.render_surface = reinterpret_cast<void*>(window->winId());
#elif defined(__APPLE__)
wsi.render_surface = reinterpret_cast<void* (*)(id, SEL)>(objc_msgSend)(
reinterpret_cast<id>(window->winId()), sel_registerName("layer"));
wsi.render_surface = reinterpret_cast<void* (*) (id, SEL)>(
objc_msgSend)(reinterpret_cast<id>(window->winId()), sel_registerName("layer"));
#else
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
wsi.display_connection = pni->nativeResourceForWindow("display", window);
@ -74,4 +77,92 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
return wsi;
}
FirmwareInstallResult InstallFirmware(const QString& location,
bool recursive,
std::function<bool(size_t, size_t)> QtProgressCallback,
Core::System* system,
FileSys::VfsFilesystem* vfs)
{
LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString());
// Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in
// there.)
std::filesystem::path firmware_source_path = location.toStdString();
if (!Common::FS::IsDir(firmware_source_path)) {
return FirmwareInstallResult::NoOp;
}
std::vector<std::filesystem::path> out;
const Common::FS::DirEntryCallable callback =
[&out](const std::filesystem::directory_entry& entry) {
if (entry.path().has_extension() && entry.path().extension() == ".nca") {
out.emplace_back(entry.path());
}
return true;
};
QtProgressCallback(100, 10);
if (recursive) {
Common::FS::IterateDirEntriesRecursively(firmware_source_path,
callback,
Common::FS::DirEntryFilter::File);
} else {
Common::FS::IterateDirEntries(firmware_source_path,
callback,
Common::FS::DirEntryFilter::File);
}
if (out.size() <= 0) {
return FirmwareInstallResult::NoNCAs;
}
// Locate and erase the content of nand/system/Content/registered/*.nca, if any.
auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory();
if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) {
return FirmwareInstallResult::FailedDelete;
}
LOG_INFO(Frontend,
"Cleaned nand/system/Content/registered folder in preparation for new firmware.");
QtProgressCallback(100, 20);
auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered");
bool success = true;
int i = 0;
for (const auto& firmware_src_path : out) {
i++;
auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(),
FileSys::OpenMode::Read);
auto firmware_dst_vfile = firmware_vdir
->CreateFileRelative(firmware_src_path.filename().string());
if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) {
LOG_ERROR(Frontend,
"Failed to copy firmware file {} to {} in registered folder!",
firmware_src_path.generic_string(),
firmware_src_path.filename().string());
success = false;
}
if (QtProgressCallback(100,
20
+ static_cast<int>(((i) / static_cast<float>(out.size()))
* 70.0))) {
return FirmwareInstallResult::FailedCorrupted;
}
}
if (!success) {
return FirmwareInstallResult::FailedCopy;
}
// Re-scan VFS for the newly placed firmware files.
system->GetFileSystemController().CreateFactories(*vfs);
return FirmwareInstallResult::Success;
}
}

View file

@ -7,8 +7,11 @@
#include <array>
#include <QWindow>
#include "core/core.h"
#include <core/frontend/emu_window.h>
#include <core/file_sys/vfs/vfs_real.h>
namespace QtCommon {
static constexpr std::array<const char *, 3> METADATA_RESULTS = {
@ -17,7 +20,7 @@ static constexpr std::array<const char *, 3> METADATA_RESULTS = {
"The metadata cache is already empty.",
};
enum MetadataResult {
enum class MetadataResult {
Success,
Failure,
Empty,
@ -38,6 +41,36 @@ inline constexpr const char *GetResetMetadataResultString(MetadataResult result)
return METADATA_RESULTS.at(static_cast<std::size_t>(result));
}
static constexpr std::array<const char *, 6> FIRMWARE_RESULTS = {
"",
"",
"Unable to locate potential firmware NCA files",
"Failed to delete one or more firmware files.",
"One or more firmware files failed to copy into NAND.",
"Firmware installation cancelled, firmware may be in a bad state or corrupted."
"Restart Eden or re-install firmware."
};
enum class FirmwareInstallResult {
Success,
NoOp,
NoNCAs,
FailedDelete,
FailedCopy,
FailedCorrupted,
};
FirmwareInstallResult InstallFirmware(const QString &location,
bool recursive,
std::function<bool(size_t, size_t)> QtProgressCallback,
Core::System *system,
FileSys::VfsFilesystem *vfs);
inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result)
{
return FIRMWARE_RESULTS.at(static_cast<std::size_t>(result));
}
Core::Frontend::WindowSystemType GetWindowSystemType();
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window);

View file

@ -132,7 +132,7 @@ void ConfigureFilesystem::ResetMetadata() {
const QString title = tr("Reset Metadata Cache");
switch (result) {
case QtCommon::Failure:
case QtCommon::MetadataResult::Failure:
QMessageBox::warning(this, title, resultMessage);
break;
default:

View file

@ -4356,106 +4356,40 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) {
return progress.wasCanceled();
};
LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString());
auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get());
const char* resultMessage = QtCommon::GetFirmwareInstallResultString(result);
// Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in
// there.)
std::filesystem::path firmware_source_path = location.toStdString();
if (!Common::FS::IsDir(firmware_source_path)) {
progress.close();
QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this);
switch (result) {
case QtCommon::FirmwareInstallResult::NoNCAs:
case QtCommon::FirmwareInstallResult::FailedCorrupted:
box->setIcon(QMessageBox::Icon::Warning);
box->exec();
return;
}
std::vector<std::filesystem::path> out;
const Common::FS::DirEntryCallable callback =
[&out](const std::filesystem::directory_entry& entry) {
if (entry.path().has_extension() && entry.path().extension() == ".nca") {
out.emplace_back(entry.path());
}
return true;
};
QtProgressCallback(100, 10);
if (recursive) {
Common::FS::IterateDirEntriesRecursively(firmware_source_path, callback,
Common::FS::DirEntryFilter::File);
} else {
Common::FS::IterateDirEntries(firmware_source_path, callback,
Common::FS::DirEntryFilter::File);
}
if (out.size() <= 0) {
progress.close();
QMessageBox::warning(this, tr("Firmware install failed"),
tr("Unable to locate potential firmware NCA files"));
case QtCommon::FirmwareInstallResult::FailedCopy:
case QtCommon::FirmwareInstallResult::FailedDelete:
box->setIcon(QMessageBox::Icon::Critical);
box->exec();
return;
default:
box->deleteLater();
break;
}
// Locate and erase the content of nand/system/Content/registered/*.nca, if any.
auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory();
if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) {
progress.close();
QMessageBox::critical(this, tr("Firmware install failed"),
tr("Failed to delete one or more firmware file."));
return;
}
LOG_INFO(Frontend,
"Cleaned nand/system/Content/registered folder in preparation for new firmware.");
QtProgressCallback(100, 20);
auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered");
bool success = true;
int i = 0;
for (const auto& firmware_src_path : out) {
i++;
auto firmware_src_vfile =
vfs->OpenFile(firmware_src_path.generic_string(), FileSys::OpenMode::Read);
auto firmware_dst_vfile =
firmware_vdir->CreateFileRelative(firmware_src_path.filename().string());
if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) {
LOG_ERROR(Frontend, "Failed to copy firmware file {} to {} in registered folder!",
firmware_src_path.generic_string(), firmware_src_path.filename().string());
success = false;
}
if (QtProgressCallback(
100, 20 + static_cast<int>(((i) / static_cast<float>(out.size())) * 70.0))) {
progress.close();
QMessageBox::warning(
this, tr("Firmware install failed"),
tr("Firmware installation cancelled, firmware may be in a bad state or corrupted. "
"Restart Eden or re-install firmware."));
return;
}
}
if (!success) {
progress.close();
QMessageBox::critical(this, tr("Firmware install failed"),
tr("One or more firmware files failed to copy into NAND."));
return;
}
// Re-scan VFS for the newly placed firmware files.
system->GetFileSystemController().CreateFactories(*vfs);
auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) {
progress.setValue(90 + static_cast<int>((processed_size * 10) / total_size));
return progress.wasCanceled();
};
auto result =
auto results =
ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true);
if (result.size() > 0) {
if (results.size() > 0) {
const auto failed_names =
QString::fromStdString(fmt::format("{}", fmt::join(result, "\n")));
QString::fromStdString(fmt::format("{}", fmt::join(results, "\n")));
progress.close();
QMessageBox::critical(
this, tr("Firmware integrity verification failed!"),