Browse Source

move fw install

Signed-off-by: crueter <crueter@eden-emu.dev>
pull/94/head
crueter 8 months ago
parent
commit
7a0712af1f
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 105
      src/qt_common/qt_common.cpp
  2. 35
      src/qt_common/qt_common.h
  3. 2
      src/yuzu/configuration/configure_filesystem.cpp
  4. 106
      src/yuzu/main.cpp

105
src/qt_common/qt_common.cpp

@ -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)(
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 #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;
}
} }

35
src/qt_common/qt_common.h

@ -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);

2
src/yuzu/configuration/configure_filesystem.cpp

@ -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:

106
src/yuzu/main.cpp

@ -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
// there.)
std::filesystem::path firmware_source_path = location.toStdString();
if (!Common::FS::IsDir(firmware_source_path)) {
progress.close();
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);
progress.close();
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);
}
QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this);
if (out.size() <= 0) {
progress.close();
QMessageBox::warning(this, tr("Firmware install failed"),
tr("Unable to locate potential firmware NCA files"));
return;
}
// 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."));
switch (result) {
case QtCommon::FirmwareInstallResult::NoNCAs:
case QtCommon::FirmwareInstallResult::FailedCorrupted:
box->setIcon(QMessageBox::Icon::Warning);
box->exec();
return; 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."));
case QtCommon::FirmwareInstallResult::FailedCopy:
case QtCommon::FirmwareInstallResult::FailedDelete:
box->setIcon(QMessageBox::Icon::Critical);
box->exec();
return; return;
default:
box->deleteLater();
break;
} }
// 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 =
ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true);
auto results =
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…
Cancel
Save