mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-17 00:52:50 +00:00
[fsp] Preserve homebrew cwd for SDMC root aliases
Carry the initial homebrew working directory through filesystem process registration and FSP current-process state. Use that cwd to resolve the homebrew cwd-plus-double-slash alias back to the SDMC root, allowing file browsers to navigate above their launch directory.
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "common/assert.h"
|
||||
@@ -333,14 +334,16 @@ FileSystemController::~FileSystemController() = default;
|
||||
|
||||
Result FileSystemController::RegisterProcess(
|
||||
ProcessId process_id, ProgramId program_id,
|
||||
std::shared_ptr<FileSys::RomFSFactory>&& romfs_factory) {
|
||||
std::shared_ptr<FileSys::RomFSFactory>&& romfs_factory, std::string homebrew_initial_cwd) {
|
||||
std::scoped_lock lk{registration_lock};
|
||||
|
||||
registrations.emplace(process_id, Registration{
|
||||
.program_id = program_id,
|
||||
.romfs_factory = std::move(romfs_factory),
|
||||
.save_data_factory = CreateSaveDataFactory(program_id),
|
||||
});
|
||||
registrations.insert_or_assign(process_id,
|
||||
Registration{
|
||||
.program_id = program_id,
|
||||
.romfs_factory = std::move(romfs_factory),
|
||||
.save_data_factory = CreateSaveDataFactory(program_id),
|
||||
.homebrew_initial_cwd = std::move(homebrew_initial_cwd),
|
||||
});
|
||||
|
||||
LOG_DEBUG(Service_FS, "Registered for process {}", process_id);
|
||||
return ResultSuccess;
|
||||
@@ -348,7 +351,8 @@ Result FileSystemController::RegisterProcess(
|
||||
|
||||
Result FileSystemController::OpenProcess(
|
||||
ProgramId* out_program_id, std::shared_ptr<SaveDataController>* out_save_data_controller,
|
||||
std::shared_ptr<RomFsController>* out_romfs_controller, ProcessId process_id) {
|
||||
std::shared_ptr<RomFsController>* out_romfs_controller, ProcessId process_id,
|
||||
std::string* out_homebrew_initial_cwd) {
|
||||
std::scoped_lock lk{registration_lock};
|
||||
|
||||
const auto it = registrations.find(process_id);
|
||||
@@ -361,6 +365,9 @@ Result FileSystemController::OpenProcess(
|
||||
std::make_shared<SaveDataController>(system, it->second.save_data_factory);
|
||||
*out_romfs_controller =
|
||||
std::make_shared<RomFsController>(it->second.romfs_factory, it->second.program_id);
|
||||
if (out_homebrew_initial_cwd != nullptr) {
|
||||
*out_homebrew_initial_cwd = it->second.homebrew_initial_cwd;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/fs_directory.h"
|
||||
#include "core/file_sys/fs_filesystem.h"
|
||||
@@ -71,11 +72,12 @@ public:
|
||||
~FileSystemController();
|
||||
|
||||
Result RegisterProcess(ProcessId process_id, ProgramId program_id,
|
||||
std::shared_ptr<FileSys::RomFSFactory>&& factory);
|
||||
std::shared_ptr<FileSys::RomFSFactory>&& factory,
|
||||
std::string homebrew_initial_cwd = {});
|
||||
Result OpenProcess(ProgramId* out_program_id,
|
||||
std::shared_ptr<SaveDataController>* out_save_data_controller,
|
||||
std::shared_ptr<RomFsController>* out_romfs_controller,
|
||||
ProcessId process_id);
|
||||
std::shared_ptr<SaveDataController>* out_save_data_controller,
|
||||
std::shared_ptr<RomFsController>* out_romfs_controller,
|
||||
ProcessId process_id, std::string* out_homebrew_initial_cwd = nullptr);
|
||||
void SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw);
|
||||
|
||||
std::shared_ptr<SaveDataController> OpenSaveDataController();
|
||||
@@ -136,6 +138,7 @@ private:
|
||||
ProgramId program_id;
|
||||
std::shared_ptr<FileSys::RomFSFactory> romfs_factory;
|
||||
std::shared_ptr<FileSys::SaveDataFactory> save_data_factory;
|
||||
std::string homebrew_initial_cwd;
|
||||
};
|
||||
|
||||
std::mutex registration_lock;
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/file_sys/fssrv/fssrv_sf_path.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
@@ -13,10 +16,29 @@
|
||||
|
||||
namespace Service::FileSystem {
|
||||
|
||||
IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_)
|
||||
: ServiceFramework{system_, "IFileSystem"}, backend{std::make_unique<FileSys::Fsa::IFileSystem>(
|
||||
dir_)},
|
||||
size_getter{std::move(size_getter_)} {
|
||||
static std::string ResolveHomebrewCwdRootAlias(std::string path,
|
||||
std::string_view homebrew_initial_cwd) {
|
||||
if (homebrew_initial_cwd.empty()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
const std::string normalized_path = Common::FS::SanitizePath(path);
|
||||
if (normalized_path.empty() || normalized_path == "/" ||
|
||||
normalized_path != homebrew_initial_cwd ||
|
||||
path.size() != normalized_path.size() + 2 ||
|
||||
path.substr(0, normalized_path.size()) != normalized_path ||
|
||||
path.substr(normalized_path.size()) != "//") {
|
||||
return path;
|
||||
}
|
||||
|
||||
return "/";
|
||||
}
|
||||
|
||||
IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_,
|
||||
std::string homebrew_initial_cwd_)
|
||||
: ServiceFramework{system_, "IFileSystem"},
|
||||
backend{std::make_unique<FileSys::Fsa::IFileSystem>(dir_)},
|
||||
size_getter{std::move(size_getter_)}, homebrew_initial_cwd{std::move(homebrew_initial_cwd_)} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IFileSystem::CreateFile>, "CreateFile"},
|
||||
{1, D<&IFileSystem::DeleteFile>, "DeleteFile"},
|
||||
@@ -43,7 +65,8 @@ Result IFileSystem::CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_H
|
||||
s32 option, s64 size) {
|
||||
LOG_DEBUG(Service_FS, "called. file={}, option={:#x}, size={:#08x}", path->str, option, size);
|
||||
|
||||
R_RETURN(backend->CreateFile(FileSys::Path(path->str), size));
|
||||
const auto fs_path = ResolveHomebrewCwdRootAlias(path->str, homebrew_initial_cwd);
|
||||
R_RETURN(backend->CreateFile(FileSys::Path(fs_path.c_str()), size));
|
||||
}
|
||||
|
||||
Result IFileSystem::DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
|
||||
@@ -94,7 +117,8 @@ Result IFileSystem::OpenFile(OutInterface<IFile> out_interface,
|
||||
LOG_DEBUG(Service_FS, "called. file={}, mode={}", path->str, mode);
|
||||
|
||||
FileSys::VirtualFile vfs_file{};
|
||||
R_TRY(backend->OpenFile(&vfs_file, FileSys::Path(path->str),
|
||||
const auto fs_path = ResolveHomebrewCwdRootAlias(path->str, homebrew_initial_cwd);
|
||||
R_TRY(backend->OpenFile(&vfs_file, FileSys::Path(fs_path.c_str()),
|
||||
static_cast<FileSys::OpenMode>(mode)));
|
||||
|
||||
*out_interface = std::make_shared<IFile>(system, vfs_file);
|
||||
@@ -107,7 +131,8 @@ Result IFileSystem::OpenDirectory(OutInterface<IDirectory> out_interface,
|
||||
LOG_DEBUG(Service_FS, "called. directory={}, mode={}", path->str, mode);
|
||||
|
||||
FileSys::VirtualDir vfs_dir{};
|
||||
R_TRY(backend->OpenDirectory(&vfs_dir, FileSys::Path(path->str),
|
||||
const auto fs_path = ResolveHomebrewCwdRootAlias(path->str, homebrew_initial_cwd);
|
||||
R_TRY(backend->OpenDirectory(&vfs_dir, FileSys::Path(fs_path.c_str()),
|
||||
static_cast<FileSys::OpenDirectoryMode>(mode)));
|
||||
|
||||
*out_interface = std::make_shared<IDirectory>(system, vfs_dir,
|
||||
@@ -120,7 +145,8 @@ Result IFileSystem::GetEntryType(
|
||||
LOG_DEBUG(Service_FS, "called. file={}", path->str);
|
||||
|
||||
FileSys::DirectoryEntryType vfs_entry_type{};
|
||||
R_TRY(backend->GetEntryType(&vfs_entry_type, FileSys::Path(path->str)));
|
||||
const auto fs_path = ResolveHomebrewCwdRootAlias(path->str, homebrew_initial_cwd);
|
||||
R_TRY(backend->GetEntryType(&vfs_entry_type, FileSys::Path(fs_path.c_str())));
|
||||
|
||||
*out_type = static_cast<u32>(vfs_entry_type);
|
||||
R_SUCCEED();
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "core/file_sys/fs_filesystem.h"
|
||||
#include "core/file_sys/fsa/fs_i_filesystem.h"
|
||||
@@ -23,7 +28,8 @@ class IDirectory;
|
||||
|
||||
class IFileSystem final : public ServiceFramework<IFileSystem> {
|
||||
public:
|
||||
explicit IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_);
|
||||
explicit IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_,
|
||||
std::string homebrew_initial_cwd_ = {});
|
||||
|
||||
Result CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, s32 option,
|
||||
s64 size);
|
||||
@@ -55,6 +61,7 @@ public:
|
||||
private:
|
||||
std::unique_ptr<FileSys::Fsa::IFileSystem> backend;
|
||||
SizeGetter size_getter;
|
||||
std::string homebrew_initial_cwd;
|
||||
};
|
||||
|
||||
} // namespace Service::FileSystem
|
||||
|
||||
@@ -192,8 +192,9 @@ Result FSP_SRV::SetCurrentProcess(ClientProcessId pid) {
|
||||
|
||||
LOG_DEBUG(Service_FS, "called. current_process_id={:#016x}", current_process_id);
|
||||
|
||||
R_RETURN(
|
||||
fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id));
|
||||
homebrew_initial_cwd.clear();
|
||||
R_RETURN(fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller,
|
||||
current_process_id, &homebrew_initial_cwd));
|
||||
}
|
||||
|
||||
Result FSP_SRV::OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
|
||||
@@ -224,7 +225,8 @@ Result FSP_SRV::OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface) {
|
||||
fsc.OpenSDMC(&sdmc_dir);
|
||||
|
||||
*out_interface = std::make_shared<IFileSystem>(
|
||||
system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
|
||||
system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard),
|
||||
homebrew_initial_cwd);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "core/file_sys/fs_save_data_types.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/filesystem/fsp/fsp_types.h"
|
||||
@@ -123,6 +124,7 @@ private:
|
||||
u32 access_log_program_index = 0;
|
||||
AccessLogMode access_log_mode = AccessLogMode::None;
|
||||
u64 program_id = 0;
|
||||
std::string homebrew_initial_cwd;
|
||||
std::shared_ptr<SaveDataController> save_data_controller;
|
||||
std::shared_ptr<RomFsController> romfs_controller;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user