Browse Source

QtCommon::FS, symlink abstractor

Signed-off-by: crueter <crueter@eden-emu.dev>
pull/2815/head
crueter 3 months ago
parent
commit
f9f11057ea
  1. 3
      src/common/CMakeLists.txt
  2. 0
      src/common/fs/ryujinx_compat.cpp
  3. 0
      src/common/fs/ryujinx_compat.h
  4. 43
      src/common/fs/symlink.cpp
  5. 12
      src/common/fs/symlink.h
  6. 3
      src/qt_common/CMakeLists.txt
  7. 2
      src/qt_common/abstract/frontend.cpp
  8. 6
      src/qt_common/abstract/frontend.h
  9. 30
      src/qt_common/qt_common.cpp
  10. 2
      src/qt_common/qt_common.h
  11. 2
      src/qt_common/util/content.cpp
  12. 56
      src/qt_common/util/fs.cpp
  13. 14
      src/qt_common/util/fs.h
  14. 2
      src/qt_common/util/game.cpp
  15. 2
      src/qt_common/util/path.cpp
  16. 7
      src/yuzu/main.cpp
  17. 9
      src/yuzu/migration_worker.cpp
  18. 26
      src/yuzu/ryujinx_dialog.cpp

3
src/common/CMakeLists.txt

@ -155,7 +155,8 @@ add_library(
wall_clock.h
zstd_compression.cpp
zstd_compression.h
ryujinx_compat.h ryujinx_compat.cpp
fs/ryujinx_compat.h fs/ryujinx_compat.cpp
fs/symlink.h fs/symlink.cpp
)
if(WIN32)

0
src/common/ryujinx_compat.cpp → src/common/fs/ryujinx_compat.cpp

0
src/common/ryujinx_compat.h → src/common/fs/ryujinx_compat.h

43
src/common/fs/symlink.cpp

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "symlink.h"
#ifdef _WIN32
#include <winbase.h>
#endif
namespace fs = std::filesystem;
// The sole purpose of this file is to treat symlinks like symlinks on POSIX,
// or treat them as directory junctions on Windows.
// This is because, for some inexplicable reason, Microsoft has locked symbolic
// links behind a "security policy", whereas directory junctions--functionally identical
// for directories, by the way--are not. Why? I don't know.
namespace Common::FS {
bool CreateSymlink(const fs::path &from, const fs::path &to)
{
// TODO: test this, + does it need symlink perms?
#ifdef _WIN32
return CreateSymbolicLinkW(to.wstring().c_str(),
from.wstring().c_str(),
SYMBOLIC_LINK_FLAG_DIRECTORY);
#else
std::error_code ec;
fs::create_directory_symlink(from, to, ec);
return !ec;
#endif
}
bool IsSymlink(const fs::path &path)
{
#ifdef _WIN32
return fs::status(path).type() == fs::file_type::junction;
#else
return fs::status(path).type() == fs::file_type::symlink;
#endif
}
} // namespace Common::FS

12
src/common/fs/symlink.h

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <filesystem>
namespace Common::FS {
bool CreateSymlink(const std::filesystem::path &from, const std::filesystem::path &to);
bool IsSymlink(const std::filesystem::path &path);
} // namespace Common::FS

3
src/qt_common/CMakeLists.txt

@ -20,13 +20,14 @@ add_library(qt_common STATIC
util/applet.h util/applet.cpp
util/compress.h util/compress.cpp
abstract/qt_frontend_util.h abstract/qt_frontend_util.cpp
abstract/frontend.h abstract/frontend.cpp
abstract/qt_progress_dialog.h abstract/qt_progress_dialog.cpp
qt_string_lookup.h
qt_compat.h
discord/discord.h
util/fs.h util/fs.cpp
)
create_target_directory_groups(qt_common)

2
src/qt_common/abstract/qt_frontend_util.cpp → src/qt_common/abstract/frontend.cpp

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "qt_frontend_util.h"
#include "frontend.h"
#include "qt_common/qt_common.h"
#ifdef YUZU_QT_WIDGETS

6
src/qt_common/abstract/qt_frontend_util.h → src/qt_common/abstract/frontend.h

@ -1,8 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef QT_FRONTEND_UTIL_H
#define QT_FRONTEND_UTIL_H
#ifndef FRONTEND_H
#define FRONTEND_H
#include <QGuiApplication>
#include "qt_common/qt_common.h"
@ -136,4 +136,4 @@ const QString GetSaveFileName(const QString &title,
Options options = Options());
} // namespace QtCommon::Frontend
#endif // QT_FRONTEND_UTIL_H
#endif // FRONTEND_H

30
src/qt_common/qt_common.cpp

@ -3,13 +3,13 @@
#include "qt_common.h"
#include "common/fs/fs.h"
#include "common/ryujinx_compat.h"
#include "common/fs/ryujinx_compat.h"
#include <QGuiApplication>
#include <QStringLiteral>
#include "common/logging/log.h"
#include "core/frontend/emu_window.h"
#include "qt_common/abstract/qt_frontend_util.h"
#include "qt_common/abstract/frontend.h"
#include "qt_common/qt_string_lookup.h"
#include <QFile>
@ -126,30 +126,4 @@ std::filesystem::path GetEdenCommand()
return command;
}
u64 GetRyujinxSaveID(const u64& program_id)
{
auto path = Common::FS::GetKvdbPath();
std::vector<Common::FS::IMEN> imens;
Common::FS::IMENReadResult res = Common::FS::ReadKvdb(path, imens);
if (res == Common::FS::IMENReadResult::Success) {
// TODO: this can probably be done with std::find_if but I'm lazy
for (const Common::FS::IMEN& imen : imens) {
if (imen.title_id == program_id)
return imen.save_id;
}
QtCommon::Frontend::Critical(
tr("Could not find Ryujinx save data"),
StringLookup::Lookup(StringLookup::RyujinxNoSaveId).arg(program_id, 0, 16));
} else {
// TODO: make this long thing a function or something
QString caption = StringLookup::Lookup(
static_cast<StringLookup::StringKey>((int) res + (int) StringLookup::KvdbNonexistent));
QtCommon::Frontend::Critical(tr("Could not find Ryujinx save data"), caption);
}
return -1;
}
} // namespace QtCommon

2
src/qt_common/qt_common.h

@ -24,8 +24,6 @@ extern std::unique_ptr<Core::System> system;
extern std::shared_ptr<FileSys::RealVfsFilesystem> vfs;
extern std::unique_ptr<FileSys::ManualContentProvider> provider;
u64 GetRyujinxSaveID(const u64 &program_id);
typedef std::function<bool(std::size_t, std::size_t)> QtProgressCallback;
Core::Frontend::WindowSystemType GetWindowSystemType();

2
src/qt_common/util/content.cpp

@ -11,7 +11,7 @@
#include "frontend_common/firmware_manager.h"
#include "compress.h"
#include "qt_common/abstract/qt_frontend_util.h"
#include "qt_common/abstract/frontend.h"
#include "qt_common/abstract/qt_progress_dialog.h"
#include "qt_common/qt_common.h"

56
src/qt_common/util/fs.cpp

@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "fs.h"
#include "common/fs/ryujinx_compat.h"
#include "common/fs/symlink.h"
#include "qt_common/abstract/frontend.h"
#include "qt_common/qt_string_lookup.h"
namespace fs = std::filesystem;
namespace QtCommon::FS {
void LinkRyujinx(std::filesystem::path &from, std::filesystem::path &to) {
std::error_code ec;
// "ignore" errors--if the dir fails to be deleted, error handling later will handle it
fs::remove_all(to, ec);
if (Common::FS::CreateSymlink(from, to)) {
QtCommon::Frontend::Information(tr("Linked Save Data"), tr("Save data has been linked."));
} else {
QtCommon::Frontend::Critical(tr("Failed to link save data"),
tr("Could not link directory:\n\t%1\nTo:\n\t%2")
.arg(QString::fromStdString(from.string()),
QString::fromStdString(to.string())));
}
}
u64 GetRyujinxSaveID(const u64 &program_id)
{
auto path = Common::FS::GetKvdbPath();
std::vector<Common::FS::IMEN> imens;
Common::FS::IMENReadResult res = Common::FS::ReadKvdb(path, imens);
if (res == Common::FS::IMENReadResult::Success) {
// TODO: this can probably be done with std::find_if but I'm lazy
for (const Common::FS::IMEN &imen : imens) {
if (imen.title_id == program_id)
return imen.save_id;
}
QtCommon::Frontend::Critical(
tr("Could not find Ryujinx save data"),
StringLookup::Lookup(StringLookup::RyujinxNoSaveId).arg(program_id, 0, 16));
} else {
// TODO: make this long thing a function or something
QString caption = StringLookup::Lookup(
static_cast<StringLookup::StringKey>((int) res + (int) StringLookup::KvdbNonexistent));
QtCommon::Frontend::Critical(tr("Could not find Ryujinx save data"), caption);
}
return -1;
}
} // namespace QtCommon::FS

14
src/qt_common/util/fs.h

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "common/common_types.h"
#include <filesystem>
#pragma once
namespace QtCommon::FS {
void LinkRyujinx(std::filesystem::path &from, std::filesystem::path &to);
u64 GetRyujinxSaveID(const u64& program_id);
} // namespace QtCommon::FS

2
src/qt_common/util/game.cpp

@ -8,7 +8,7 @@
#include "core/file_sys/savedata_factory.h"
#include "core/hle/service/am/am_types.h"
#include "frontend_common/content_manager.h"
#include "qt_common/abstract/qt_frontend_util.h"
#include "qt_common/abstract/frontend.h"
#include "qt_common/config/uisettings.h"
#include "qt_common/qt_common.h"
#include "yuzu/util/util.h"

2
src/qt_common/util/path.cpp

@ -7,7 +7,7 @@
#include <QUrl>
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "qt_common/abstract/qt_frontend_util.h"
#include "qt_common/abstract/frontend.h"
#include <fmt/format.h>
namespace QtCommon::Path {

7
src/yuzu/main.cpp

@ -6,11 +6,12 @@
#include "core/tools/renderdoc.h"
#include "frontend_common/firmware_manager.h"
#include "qt_common/qt_common.h"
#include "qt_common/abstract/qt_frontend_util.h"
#include "qt_common/abstract/frontend.h"
#include "qt_common/util/content.h"
#include "qt_common/util/game.h"
#include "qt_common/util/meta.h"
#include "qt_common/util/path.h"
#include "qt_common/util/fs.h"
#include <clocale>
#include <cmath>
#include <memory>
@ -109,7 +110,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "common/detached_tasks.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/ryujinx_compat.h"
#include "common/fs/ryujinx_compat.h"
#include "common/literals.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
@ -2918,7 +2919,7 @@ void GMainWindow::OnLinkToRyujinx(const u64& program_id)
{
namespace fs = std::filesystem;
u64 save_id = QtCommon::GetRyujinxSaveID(program_id);
u64 save_id = QtCommon::FS::GetRyujinxSaveID(program_id);
if (save_id == (u64) -1)
return;
fs::path ryu_dir = Common::FS::GetRyuSavePath(save_id);

9
src/yuzu/migration_worker.cpp

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "migration_worker.h"
#include "common/fs/symlink.h"
#include <QMap>
#include <boost/algorithm/string/predicate.hpp>
@ -37,7 +38,7 @@ void MigrationWorker::process()
try {
fs::remove_all(eden_dir);
} catch (fs::filesystem_error &_) {
// ignore because linux does stupid crap sometimes.
// ignore because linux does stupid crap sometimes
}
switch (strategy) {
@ -46,7 +47,7 @@ void MigrationWorker::process()
// Windows 11 has random permission nonsense to deal with.
try {
fs::create_directory_symlink(legacy_user_dir, eden_dir);
Common::FS::CreateSymlink(legacy_user_dir, eden_dir);
} catch (const fs::filesystem_error &e) {
emit error(tr("Linking the old directory failed. You may need to re-run with "
"administrative privileges on Windows.\nOS gave error: %1")
@ -58,11 +59,11 @@ void MigrationWorker::process()
// are already children of the root directory
#ifndef WIN32
if (fs::is_directory(legacy_config_dir)) {
fs::create_directory_symlink(legacy_config_dir, config_dir);
Common::FS::CreateSymlink(legacy_config_dir, config_dir);
}
if (fs::is_directory(legacy_cache_dir)) {
fs::create_directory_symlink(legacy_cache_dir, cache_dir);
Common::FS::CreateSymlink(legacy_cache_dir, cache_dir);
}
#endif

26
src/yuzu/ryujinx_dialog.cpp

@ -1,11 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "qt_common/abstract/qt_frontend_util.h"
#include "ryujinx_dialog.h"
#include "qt_common/util/fs.h"
#include "ui_ryujinx_dialog.h"
#include <filesystem>
#include <system_error>
#include <fmt/format.h>
namespace fs = std::filesystem;
@ -43,26 +42,5 @@ void RyujinxDialog::fromRyujinx()
void RyujinxDialog::link(std::filesystem::path &from, std::filesystem::path &to)
{
std::error_code ec;
// "ignore" errors--if the dir fails to be deleted, error handling later will handle it
fs::remove_all(to, ec);
#ifdef _WIN32
const std::string command = fmt::format("mklink /J {} {}", to.string(), from.string());
system(command.c_str());
#else
try {
fs::create_directory_symlink(from, to);
} catch (std::exception &e) {
QtCommon::Frontend::Critical(tr("Failed to link save data"),
tr("Could not link directory:\n\t%1\nTo:\n\t%2\n\nError: %3")
.arg(QString::fromStdString(from.string()),
QString::fromStdString(to.string()),
QString::fromStdString(e.what())));
return;
}
#endif
QtCommon::Frontend::Information(tr("Linked Save Data"), tr("Save data has been linked."));
QtCommon::FS::LinkRyujinx(from, to);
}
Loading…
Cancel
Save