move fw install
Signed-off-by: crueter <crueter@eden-emu.dev>
This commit is contained in:
parent
11db0f0dbf
commit
7a0712af1f
4 changed files with 155 additions and 97 deletions
|
@ -1,6 +1,7 @@
|
||||||
#include "qt_common.h"
|
#include "qt_common.h"
|
||||||
#include "common/fs/fs.h"
|
#include "common/fs/fs.h"
|
||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "uisettings.h"
|
#include "uisettings.h"
|
||||||
|
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
@ -21,17 +22,18 @@ MetadataResult ResetMetadata()
|
||||||
{
|
{
|
||||||
if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir)
|
if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir)
|
||||||
/ "game_list/")) {
|
/ "game_list/")) {
|
||||||
return Empty;
|
return MetadataResult::Empty;
|
||||||
} else if (Common::FS::RemoveDirRecursively(
|
} else if (Common::FS::RemoveDirRecursively(
|
||||||
Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) {
|
Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) {
|
||||||
return Success;
|
return MetadataResult::Success;
|
||||||
UISettings::values.is_game_list_reload_pending.exchange(true);
|
UISettings::values.is_game_list_reload_pending.exchange(true);
|
||||||
} else {
|
} else {
|
||||||
return Failure;
|
return MetadataResult::Failure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::Frontend::WindowSystemType GetWindowSystemType() {
|
Core::Frontend::WindowSystemType GetWindowSystemType()
|
||||||
|
{
|
||||||
// Determine WSI type based on Qt platform.
|
// Determine WSI type based on Qt platform.
|
||||||
QString platform_name = QGuiApplication::platformName();
|
QString platform_name = QGuiApplication::platformName();
|
||||||
if (platform_name == QStringLiteral("windows"))
|
if (platform_name == QStringLiteral("windows"))
|
||||||
|
@ -51,7 +53,8 @@ Core::Frontend::WindowSystemType GetWindowSystemType() {
|
||||||
return Core::Frontend::WindowSystemType::Windows;
|
return Core::Frontend::WindowSystemType::Windows;
|
||||||
} // namespace Core::Frontend::WindowSystemType
|
} // namespace Core::Frontend::WindowSystemType
|
||||||
|
|
||||||
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) {
|
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
||||||
|
{
|
||||||
Core::Frontend::EmuWindow::WindowSystemInfo wsi;
|
Core::Frontend::EmuWindow::WindowSystemInfo wsi;
|
||||||
wsi.type = GetWindowSystemType();
|
wsi.type = GetWindowSystemType();
|
||||||
|
|
||||||
|
@ -59,8 +62,8 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
||||||
// Our Win32 Qt external doesn't have the private API.
|
// Our Win32 Qt external doesn't have the private API.
|
||||||
wsi.render_surface = reinterpret_cast<void*>(window->winId());
|
wsi.render_surface = reinterpret_cast<void*>(window->winId());
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
wsi.render_surface = reinterpret_cast<void* (*)(id, SEL)>(objc_msgSend)(
|
wsi.render_surface = reinterpret_cast<void* (*) (id, SEL)>(
|
||||||
reinterpret_cast<id>(window->winId()), sel_registerName("layer"));
|
objc_msgSend)(reinterpret_cast<id>(window->winId()), sel_registerName("layer"));
|
||||||
#else
|
#else
|
||||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||||
wsi.display_connection = pni->nativeResourceForWindow("display", window);
|
wsi.display_connection = pni->nativeResourceForWindow("display", window);
|
||||||
|
@ -74,4 +77,92 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
||||||
return wsi;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,11 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
|
#include "core/core.h"
|
||||||
#include <core/frontend/emu_window.h>
|
#include <core/frontend/emu_window.h>
|
||||||
|
|
||||||
|
#include <core/file_sys/vfs/vfs_real.h>
|
||||||
|
|
||||||
namespace QtCommon {
|
namespace QtCommon {
|
||||||
|
|
||||||
static constexpr std::array<const char *, 3> METADATA_RESULTS = {
|
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.",
|
"The metadata cache is already empty.",
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MetadataResult {
|
enum class MetadataResult {
|
||||||
Success,
|
Success,
|
||||||
Failure,
|
Failure,
|
||||||
Empty,
|
Empty,
|
||||||
|
@ -38,6 +41,36 @@ inline constexpr const char *GetResetMetadataResultString(MetadataResult result)
|
||||||
return METADATA_RESULTS.at(static_cast<std::size_t>(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::WindowSystemType GetWindowSystemType();
|
||||||
|
|
||||||
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window);
|
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window);
|
||||||
|
|
|
@ -132,7 +132,7 @@ void ConfigureFilesystem::ResetMetadata() {
|
||||||
const QString title = tr("Reset Metadata Cache");
|
const QString title = tr("Reset Metadata Cache");
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case QtCommon::Failure:
|
case QtCommon::MetadataResult::Failure:
|
||||||
QMessageBox::warning(this, title, resultMessage);
|
QMessageBox::warning(this, title, resultMessage);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -4356,106 +4356,40 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) {
|
||||||
return progress.wasCanceled();
|
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
|
progress.close();
|
||||||
// there.)
|
|
||||||
std::filesystem::path firmware_source_path = location.toStdString();
|
QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this);
|
||||||
if (!Common::FS::IsDir(firmware_source_path)) {
|
|
||||||
progress.close();
|
switch (result) {
|
||||||
|
case QtCommon::FirmwareInstallResult::NoNCAs:
|
||||||
|
case QtCommon::FirmwareInstallResult::FailedCorrupted:
|
||||||
|
box->setIcon(QMessageBox::Icon::Warning);
|
||||||
|
box->exec();
|
||||||
return;
|
return;
|
||||||
}
|
case QtCommon::FirmwareInstallResult::FailedCopy:
|
||||||
|
case QtCommon::FirmwareInstallResult::FailedDelete:
|
||||||
std::vector<std::filesystem::path> out;
|
box->setIcon(QMessageBox::Icon::Critical);
|
||||||
const Common::FS::DirEntryCallable callback =
|
box->exec();
|
||||||
[&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"));
|
|
||||||
return;
|
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) {
|
auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) {
|
||||||
progress.setValue(90 + static_cast<int>((processed_size * 10) / total_size));
|
progress.setValue(90 + static_cast<int>((processed_size * 10) / total_size));
|
||||||
return progress.wasCanceled();
|
return progress.wasCanceled();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto result =
|
auto results =
|
||||||
ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true);
|
ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true);
|
||||||
|
|
||||||
if (result.size() > 0) {
|
if (results.size() > 0) {
|
||||||
const auto failed_names =
|
const auto failed_names =
|
||||||
QString::fromStdString(fmt::format("{}", fmt::join(result, "\n")));
|
QString::fromStdString(fmt::format("{}", fmt::join(results, "\n")));
|
||||||
progress.close();
|
progress.close();
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
this, tr("Firmware integrity verification failed!"),
|
this, tr("Firmware integrity verification failed!"),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue