From 80f2c08f31dbf9642ee0c137baff099ebc29787e Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Tue, 26 Jun 2018 20:58:46 -0400 Subject: [PATCH] Fixes and testing --- src/core/core.cpp | 3 +- src/core/file_sys/content_archive.h | 2 +- src/core/file_sys/partition_filesystem.cpp | 4 +- src/core/file_sys/vfs.cpp | 37 ++++++- src/core/file_sys/vfs.h | 1 + src/core/file_sys/vfs_real.cpp | 15 ++- src/core/file_sys/vfs_real.h | 3 +- src/core/hle/service/am/am.cpp | 2 +- .../hle/service/filesystem/filesystem.cpp | 97 +++++++++++-------- src/core/hle/service/filesystem/filesystem.h | 5 +- src/core/hle/service/filesystem/fsp_srv.cpp | 80 +++++++++------ .../loader/deconstructed_rom_directory.cpp | 24 ++--- src/core/loader/deconstructed_rom_directory.h | 3 - src/core/loader/loader.cpp | 17 ++-- src/core/loader/loader.h | 5 +- src/core/loader/nca.cpp | 13 +-- src/core/loader/nca.h | 2 - src/core/loader/nso.cpp | 3 + src/yuzu/game_list.cpp | 4 +- 19 files changed, 185 insertions(+), 135 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 8335d502e3..82db5cccff 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -19,6 +19,7 @@ #include "core/loader/loader.h" #include "core/memory_setup.h" #include "core/settings.h" +#include "file_sys/vfs_real.h" #include "video_core/video_core.h" namespace Core { @@ -84,7 +85,7 @@ System::ResultStatus System::SingleStep() { } System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) { - app_loader = Loader::GetLoader(filepath); + app_loader = Loader::GetLoader(std::make_shared(filepath)); if (!app_loader) { LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index 63a81d7482..19d04feb24 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -44,7 +44,7 @@ static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size."); static bool IsDirectoryExeFS(std::shared_ptr pfs) { // According to switchbrew, an exefs must only contain these two files: - return pfs->GetFile("main") != nullptr && pfs->GetFile("main.ndpm") != nullptr; + return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr; } static bool IsValidNCA(const NCAHeader& header) { diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index c405e9844a..810eb8edf5 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp @@ -21,7 +21,7 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr file) { // For cartridges, HFSs can get very large, so we need to calculate the size up to // the actual content itself instead of just blindly reading in the entire file. Header pfs_header; - if (!file->ReadObject(&pfs_header)) { + if (sizeof(Header) != file->ReadObject(&pfs_header)) { status = Loader::ResultStatus::Error; return; } @@ -52,7 +52,7 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr file) { return; } - memcpy(&pfs_header, &file_data, sizeof(Header)); + memcpy(&pfs_header, file_data.data(), sizeof(Header)); if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') && pfs_header.magic != Common::MakeMagic('P', 'F', 'S', '0')) { status = Loader::ResultStatus::ErrorInvalidFormat; diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index fa513ae1a3..82e8c6041e 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -54,7 +54,7 @@ std::shared_ptr VfsDirectory::GetFileRelative(const filesystem::path& p auto parent = path.parent_path().string(); parent.replace(path.root_path().string().begin(), path.root_path().string().end(), ""); - const auto index = parent.find_first_of('\\'); + const auto index = parent.find_first_of('/'); const auto first_dir = parent.substr(0, index), rest = parent.substr(index + 1); const auto sub = GetSubdirectory(first_dir); if (sub == nullptr) @@ -69,11 +69,23 @@ std::shared_ptr VfsDirectory::GetFileAbsolute(const filesystem::path& p return GetParentDirectory()->GetFileAbsolute(path); } -std::shared_ptr VfsDirectory::GetDirectoryRelative(const filesystem::path& path) const { - return ""; +std::shared_ptr VfsDirectory::GetDirectoryRelative( + const filesystem::path& path) const { + if (path.parent_path() == path.root_path()) + return GetSubdirectory(path.filename().string()); + + auto parent = path.parent_path().string(); + parent.replace(path.root_path().string().begin(), path.root_path().string().end(), ""); + const auto index = parent.find_first_of('/'); + const auto first_dir = parent.substr(0, index), rest = parent.substr(index + 1); + const auto sub = GetSubdirectory(first_dir); + if (sub == nullptr) + return nullptr; + return sub->GetDirectoryRelative(path.root_path().string() + rest); } -std::shared_ptr VfsDirectory::GetDirectoryAbsolute(const filesystem::path& path) const { +std::shared_ptr VfsDirectory::GetDirectoryAbsolute( + const filesystem::path& path) const { if (IsRoot()) return GetDirectoryRelative(path); @@ -113,6 +125,23 @@ size_t VfsDirectory::GetSize() const { return file_total + subdir_total; } +bool VfsDirectory::DeleteSubdirectoryRecursive(const std::string& name) { + auto dir = GetSubdirectory(name); + if (dir == nullptr) + return false; + + bool success = true; + for (const auto& file : dir->GetFiles()) + if (!DeleteFile(file->GetName())) + success = false; + + for (const auto& sdir : dir->GetSubdirectories()) + if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) + success = false; + + return success; +} + bool VfsDirectory::Copy(const std::string& src, const std::string& dest) { const auto f1 = CreateFile(src); auto f2 = CreateFile(dest); diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 5aa2edd42e..b130a717fe 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -119,6 +119,7 @@ struct VfsDirectory : NonCopyable { virtual std::shared_ptr CreateFile(const std::string& name) = 0; virtual bool DeleteSubdirectory(const std::string& name) = 0; + virtual bool DeleteSubdirectoryRecursive(const std::string& name); virtual bool DeleteFile(const std::string& name) = 0; virtual bool Rename(const std::string& name) = 0; diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 1a4ecf3017..c7b351db0e 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -7,17 +7,21 @@ namespace FileSys { -static const char* PermissionsToCharArray(filesystem::perms perms) { +static std::string PermissionsToCharArray(filesystem::perms perms) { std::string out; if ((perms & filesystem::perms::owner_read) != filesystem::perms::none) out += "r"; if ((perms & filesystem::perms::owner_write) != filesystem::perms::none) - out += "w"; - return out.c_str(); + out += "+"; + if (out == "+") + out = "w"; + return out + "b"; } RealVfsFile::RealVfsFile(const filesystem::path& path_, filesystem::perms perms_) - : backing(path_.string(), PermissionsToCharArray(perms_)), path(path_), perms(perms_) {} + : backing(path_.string(), PermissionsToCharArray(perms_).c_str()), path(path_), perms(perms_) { + path.make_preferred(); +} std::string RealVfsFile::GetName() const { return path.filename().string(); @@ -58,12 +62,13 @@ size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) { bool RealVfsFile::Rename(const std::string& name) { const auto out = FileUtil::Rename(GetName(), name); path = path.parent_path() / name; - backing = FileUtil::IOFile(path.string(), PermissionsToCharArray(perms)); + backing = FileUtil::IOFile(path.string(), PermissionsToCharArray(perms).c_str()); return out; } RealVfsDirectory::RealVfsDirectory(const filesystem::path& path_, filesystem::perms perms_) : path(path_), perms(perms_) { + path.make_preferred(); for (const auto& entry : filesystem::directory_iterator(path)) { if (filesystem::is_directory(entry.path())) subdirectories.emplace_back(std::make_shared(entry.path(), perms)); diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index a4f8488923..fdddfd93f8 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h @@ -11,7 +11,8 @@ namespace FileSys { struct RealVfsFile : public VfsFile { - RealVfsFile(const filesystem::path& name, filesystem::perms perms); + RealVfsFile(const filesystem::path& name, + filesystem::perms perms = filesystem::perms::owner_read); std::string GetName() const override; size_t GetSize() const override; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index a871b3eaa0..7bb13c7357 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -621,7 +621,7 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; FileSys::Path unused; - auto savedata = FileSystem::OpenFileSystem(FileSystem::Type::SaveData, unused); + auto savedata = FileSystem::OpenFileSystem(FileSystem::Type::SaveData); if (savedata.Failed()) { // Create the save data and return an error indicating that the operation was performed. FileSystem::FormatFileSystem(FileSystem::Type::SaveData); diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 803cae6131..01a8ebb57d 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -7,116 +7,132 @@ #include "common/file_util.h" #include "core/file_sys/filesystem.h" #include "core/file_sys/vfs.h" +#include "core/file_sys/vfs_offset.h" #include "core/file_sys/vfs_real.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_srv.h" namespace Service::FileSystem { -VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(v_dir backing_) : backing(backing_) { } +VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(v_dir backing_) : backing(backing_) {} std::string VfsDirectoryServiceWrapper::GetName() const { return backing->GetName(); } -// TODO(DarkLordZach): Verify path usage. ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path, u64 size) const { filesystem::path s_path(path); auto dir = backing->GetDirectoryRelative(s_path.parent_path()); - auto file = dir->CreateFile(path.filename().string()); - if (file == nullptr) return ResultCode(-1); - if (!file->Resize(size)) return ResultCode(-1); + auto file = dir->CreateFile(s_path.filename().string()); + if (file == nullptr) + return ResultCode(-1); + if (!file->Resize(size)) + return ResultCode(-1); return RESULT_SUCCESS; } -// TODO(DarkLordZach): Verify path usage. ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const { filesystem::path s_path(path); auto dir = backing->GetDirectoryRelative(s_path.parent_path()); - if (!backing->DeleteFile(s_path.filename().string())) return ResultCode(-1); + if (!backing->DeleteFile(s_path.filename().string())) + return ResultCode(-1); return RESULT_SUCCESS; } -// TODO(DarkLordZach): Verify path usage. ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path) const { filesystem::path s_path(path); auto dir = backing->GetDirectoryRelative(s_path.parent_path()); - auto new_dir = dir->CreateSubdirectory(path.filename().name); - if (new_dir == nullptr) return ResultCode(-1); + auto new_dir = dir->CreateSubdirectory(s_path.filename().string()); + if (new_dir == nullptr) + return ResultCode(-1); return RESULT_SUCCESS; } -// TODO(DarkLordZach): Verify path usage. ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path) const { filesystem::path s_path(path); auto dir = backing->GetDirectoryRelative(s_path.parent_path()); - if (!dir->DeleteSubdirectory(path.filename().string())) return ResultCode(-1); + if (!dir->DeleteSubdirectory(s_path.filename().string())) + return ResultCode(-1); return RESULT_SUCCESS; } -// TODO(DarkLordZach): Verify path usage. ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path) const { filesystem::path s_path(path); auto dir = backing->GetDirectoryRelative(s_path.parent_path()); - if (!dir->DeleteSubdirectoryRecursive(path.filename().string())) return ResultCode(-1); + if (!dir->DeleteSubdirectoryRecursive(s_path.filename().string())) + return ResultCode(-1); return RESULT_SUCCESS; } -// TODO(DarkLordZach): Verify path usage. -ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path, const std::string& dest_path) const { +ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path, + const std::string& dest_path) const { filesystem::path s_path(src_path); auto file = backing->GetFileRelative(s_path); file->GetContainingDirectory()->DeleteFile(file->GetName()); auto res_code = CreateFile(dest_path, file->GetSize()); - if (res_code != RESULT_SUCCESS) return res_code; + if (res_code != RESULT_SUCCESS) + return res_code; auto file2 = backing->GetFileRelative(filesystem::path(dest_path)); - if (file2->WriteBytes(file->ReadAllBytes() != file->GetSize()) return ResultCode(-1); + if (file2->WriteBytes(file->ReadAllBytes()) != file->GetSize()) + return ResultCode(-1); return RESULT_SUCCESS; } -// TODO(DarkLordZach): Verify path usage. -ResultCode -VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path, const std::string& dest_path) const { +ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path, + const std::string& dest_path) const { filesystem::path s_path(src_path); auto file = backing->GetFileRelative(s_path); file->GetContainingDirectory()->DeleteFile(file->GetName()); auto res_code = CreateFile(dest_path, file->GetSize()); - if (res_code != RESULT_SUCCESS) return res_code; + if (res_code != RESULT_SUCCESS) + return res_code; auto file2 = backing->GetFileRelative(filesystem::path(dest_path)); - if (file2->WriteBytes(file->ReadAllBytes() != file->GetSize())) return ResultCode(-1); + if (file2->WriteBytes(file->ReadAllBytes()) != file->GetSize()) + return ResultCode(-1); return RESULT_SUCCESS; } -// TODO(DarkLordZach): Verify path usage. -ResultVal VfsDirectoryServiceWrapper::OpenFile(const std::string& path, FileSys::Mode mode) const { +ResultVal VfsDirectoryServiceWrapper::OpenFile(const std::string& path, + FileSys::Mode mode) const { auto file = backing->GetFileRelative(filesystem::path(path)); - if (file == nullptr) return ResultVal(-1); - if (mode == FileSys::Mode::Append) return MakeResult(std::make_shared(file, 0, file->GetSize())); - else if (mode == FileSys::Mode::Write && file->IsWritable()) return file; - else if (mode == FileSys::Mode::Read && file->IsReadable()) return file; - return ResultVal(-1); + if (file == nullptr) + return ResultCode(-1); + if (mode == FileSys::Mode::Append) + return MakeResult( + std::make_shared(file, 0, file->GetSize())); + else if (mode == FileSys::Mode::Write && file->IsWritable()) + return MakeResult(file); + else if (mode == FileSys::Mode::Read && file->IsReadable()) + return MakeResult(file); + return ResultCode(-1); } -// TODO(DarkLordZach): Verify path usage. ResultVal VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path) const { auto dir = backing->GetDirectoryRelative(filesystem::path(path)); - if (dir == nullptr) return ResultVal(-1); - return MakeResult(RESULT_SUCCESS, dir); + if (dir == nullptr) + return ResultCode(-1); + return MakeResult(dir); } u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const { // TODO(DarkLordZach): Infinite? Actual? Is this actually used productively or...? + if (backing->IsWritable()) + return -1; + return 0; } -// TODO(DarkLordZach): Verify path usage. -ResultVal VfsDirectoryServiceWrapper::GetEntryType(const std::string& path) const { +ResultVal VfsDirectoryServiceWrapper::GetEntryType( + const std::string& path) const { filesystem::path r_path(path); auto dir = backing->GetDirectoryRelative(r_path.parent_path()); - if (dir == nullptr) return ResultVal(-1); - if (dir->GetFile(r_path.filename().string()) != nullptr) return MakeResult(FileSys::EntryType::File); - if (dir->GetSubdirectory(r_path.filename().string()) != nullptr) return MakeResult(FileSys::EntryType::Directory); - return ResultVal(-1); + if (dir == nullptr) + return ResultCode(-1); + if (dir->GetFile(r_path.filename().string()) != nullptr) + return MakeResult(FileSys::EntryType::File); + if (dir->GetSubdirectory(r_path.filename().string()) != nullptr) + return MakeResult(FileSys::EntryType::Directory); + return ResultCode(-1); } /** @@ -161,7 +177,8 @@ ResultVal OpenFileSystem(Type type) { } ResultVal OpenRomFS() { - if (filesystem_romfs == nullptr) return ResultVal(-1); + if (filesystem_romfs == nullptr) + return ResultCode(-1); return MakeResult(filesystem_romfs); } diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 4e10080e0c..b8cc5cb45b 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -6,6 +6,7 @@ #include #include "common/common_types.h" +#include "core/file_sys/filesystem.h" #include "core/file_sys/vfs.h" #include "core/hle/result.h" @@ -121,10 +122,6 @@ public: ResultVal GetEntryType(const std::string& path) const; }; -class VfsFileServiceWrapper { - v_file backing; -}; - /** * Registers a FileSystem, instances of which can later be opened using its IdCode. * @param factory FileSystem backend interface to use diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index df8e200c0e..c8dcf5b2e7 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -137,8 +137,10 @@ private: return; } + std::vector data = ctx.ReadBuffer(); + data.resize(length); // Write the data to the Storage backend - auto res = MakeResult(backend->WriteBytes(ctx.ReadBuffer(), length, offset)); + auto res = MakeResult(backend->WriteBytes(data, offset)); if (res.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(res.Code()); @@ -180,17 +182,37 @@ private: class IDirectory final : public ServiceFramework { public: - explicit IDirectory(std::unique_ptr&& backend) - : ServiceFramework("IDirectory"), backend(std::move(backend)) { + explicit IDirectory(v_dir backend_) : ServiceFramework("IDirectory"), backend(backend_) { static const FunctionInfo functions[] = { {0, &IDirectory::Read, "Read"}, {1, &IDirectory::GetEntryCount, "GetEntryCount"}, }; RegisterHandlers(functions); + + // Build entry index now to save time later. + for (const auto& file : backend->GetFiles()) { + FileSys::Entry entry; + entry.filename[0] = '\0'; + strncat(entry.filename, file->GetName().c_str(), FileSys::FILENAME_LENGTH - 1); + entry.type = FileSys::File; + entry.file_size = file->GetSize(); + entries.emplace_back(entry); + } + + for (const auto& dir : backend->GetSubdirectories()) { + FileSys::Entry entry; + entry.filename[0] = '\0'; + strncat(entry.filename, dir->GetName().c_str(), FileSys::FILENAME_LENGTH - 1); + entry.type = FileSys::Directory; + entry.file_size = dir->GetSize(); + entries.emplace_back(entry); + } } private: - std::unique_ptr backend; + v_dir backend; + std::vector entries; + u64 next_entry_index = 0; void Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; @@ -201,26 +223,29 @@ private: // Calculate how many entries we can fit in the output buffer u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); + // Cap at total number of entries. + u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index); + // Read the data from the Directory backend - std::vector entries(count_entries); - u64 read_entries = backend->Read(count_entries, entries.data()); + std::vector entry_data(entries.begin() + next_entry_index, + entries.begin() + next_entry_index + actual_entries); // Convert the data into a byte array - std::vector output(entries.size() * sizeof(FileSys::Entry)); - std::memcpy(output.data(), entries.data(), output.size()); + std::vector output(entry_data.size() * sizeof(FileSys::Entry)); + std::memcpy(output.data(), entry_data.data(), output.size()); // Write the data to memory ctx.WriteBuffer(output); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - rb.Push(read_entries); + rb.Push(actual_entries); } void GetEntryCount(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "called"); - u64 count = backend->GetEntryCount(); + u64 count = entries.size() - next_entry_index; IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); @@ -265,12 +290,7 @@ public: LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size); IPC::ResponseBuilder rb{ctx, 2}; - auto b1 = backend->CreateFile(name); - if (b1 == nullptr) { - } - auto b2 = b1->Res - - rb.Push(? RESULT_SUCCESS : ResultCode(-1)); + rb.Push(backend.CreateFile(name, size)); } void DeleteFile(Kernel::HLERequestContext& ctx) { @@ -282,7 +302,7 @@ public: LOG_DEBUG(Service_FS, "called file {}", name); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend->DeleteFile(name)); + rb.Push(backend.DeleteFile(name)); } void CreateDirectory(Kernel::HLERequestContext& ctx) { @@ -294,8 +314,7 @@ public: LOG_DEBUG(Service_FS, "called directory {}", name); IPC::ResponseBuilder rb{ctx, 2}; - auto dir = backend->CreateSubdirectory(name); - rb.Push(dir == nullptr ? -1 : 0); + rb.Push(backend.CreateDirectory(name)); } void RenameFile(Kernel::HLERequestContext& ctx) { @@ -313,7 +332,7 @@ public: LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend->RenameFile(src_name, dst_name)); + rb.Push(backend.RenameFile(src_name, dst_name)); } void OpenFile(Kernel::HLERequestContext& ctx) { @@ -326,14 +345,14 @@ public: LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast(mode)); - auto result = backend->OpenFile(name, mode); + auto result = backend.OpenFile(name, mode); if (result.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result.Code()); return; } - auto file = std::move(result.Unwrap()); + IFile file(result.Unwrap()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -351,14 +370,14 @@ public: LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags); - auto result = backend->OpenDirectory(name); + auto result = backend.OpenDirectory(name); if (result.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result.Code()); return; } - auto directory = std::move(result.Unwrap()); + IDirectory directory(result.Unwrap()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -373,7 +392,7 @@ public: LOG_DEBUG(Service_FS, "called file {}", name); - auto result = backend->GetEntryType(name); + auto result = backend.GetEntryType(name); if (result.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result.Code()); @@ -393,7 +412,7 @@ public: } private: - v_dir backend; + VfsDirectoryServiceWrapper backend; }; FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { @@ -510,7 +529,7 @@ void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) { void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "called"); - auto filesystem = OpenFileSystem(Type::SDMC).Unwrap(); + IFileSystem filesystem(OpenFileSystem(Type::SDMC).Unwrap()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -533,8 +552,7 @@ void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_FS, "(STUBBED) called"); - FileSys::Path unused; - auto filesystem = OpenFileSystem(Type::SaveData, unused).Unwrap(); + IFileSystem filesystem(OpenFileSystem(Type::SaveData).Unwrap()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -561,9 +579,11 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { return; } + IStorage storage(romfs); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(std::move(storage.Unwrap())); + rb.PushIpcInterface(std::move(storage)); } void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index f7430f54cb..aa556b8b3c 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -102,27 +102,19 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( metadata.GetMainThreadStackSize()); // Find the RomFS by searching for a ".romfs" file in this directory - const auto romfs_iter = - std::find_if(dir->GetFiles().begin(), dir->GetFiles().end(), [](const v_file& file) { - return file->GetName().find(".romfs") != std::string::npos; - }); + const auto& files = dir->GetFiles(); + const auto romfs_iter = std::find_if(files.begin(), files.end(), [](const v_file& file) { + return file->GetName().find(".romfs") != std::string::npos; + }); // TODO(DarkLordZach): Identify RomFS if its a subdirectory. - romfs = (romfs_iter == dir->GetFiles().end()) ? nullptr : *romfs_iter; + const auto romfs = (romfs_iter == files.end()) ? nullptr : *romfs_iter; + + if (romfs != nullptr) + Service::FileSystem::RegisterRomFS(romfs); is_loaded = true; return ResultStatus::Success; } -ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(v_file& file) { - if (romfs == nullptr) { - LOG_DEBUG(Loader, "No RomFS available"); - return ResultStatus::ErrorNotUsed; - } - - file = romfs; - - return ResultStatus::Success; -} - } // namespace Loader diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index f772ee34d9..73152c8102 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -35,10 +35,7 @@ public: ResultStatus Load(Kernel::SharedPtr& process) override; - ResultStatus ReadRomFS(v_file& file) override; - private: - v_file romfs; FileSys::ProgramMetadata metadata; }; diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 520185c0e8..14c793928e 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -6,6 +6,7 @@ #include #include "common/logging/log.h" #include "common/string_util.h" +#include "core/file_sys/vfs_real.h" #include "core/hle/kernel/process.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/elf.h" @@ -41,25 +42,19 @@ FileType IdentifyFile(v_file file) { } FileType IdentifyFile(const std::string& file_name) { - FileUtil::IOFile file(file_name, "rb"); - if (!file.IsOpen()) { - LOG_ERROR(Loader, "Failed to load file {}", file_name); - return FileType::Unknown; - } - - return IdentifyFile(file, file_name); + return IdentifyFile(v_file(std::make_shared(file_name))); } FileType GuessFromExtension(const std::string& extension_) { std::string extension = Common::ToLower(extension_); - if (extension == ".elf") + if (extension == "elf") return FileType::ELF; - else if (extension == ".nro") + else if (extension == "nro") return FileType::NRO; - else if (extension == ".nso") + else if (extension == "nso") return FileType::NSO; - else if (extension == ".nca") + else if (extension == "nca") return FileType::NCA; return FileType::Unknown; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index d645c15b96..33b1b2b414 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -37,10 +37,9 @@ enum class FileType { /** * Identifies the type of a bootable file based on the magic value in its header. * @param file open file - * @param filepath Path of the file that we are opening. * @return FileType of file */ -FileType IdentifyFile(FileUtil::IOFile& file, const std::string& filepath); +FileType IdentifyFile(v_file file); /** * Identifies the type of a bootable file based on the magic value in its header. @@ -197,6 +196,6 @@ extern const std::initializer_list default_address_mappi * @param filename String filename of bootable file * @return best loader for this file */ -std::unique_ptr GetLoader(const std::string& filename); +std::unique_ptr GetLoader(v_file file); } // namespace Loader diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 4c9bd806c8..c19a487e7d 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -66,6 +66,7 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr& process) { for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { const VAddr load_addr = next_load_addr; + next_load_addr = AppLoader_NSO::LoadModule(exefs->GetFile(module), load_addr); if (next_load_addr) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); @@ -83,18 +84,10 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr& process) { metadata.GetMainThreadStackSize()); is_loaded = true; - return ResultStatus::Success; -} -ResultStatus AppLoader_NCA::ReadRomFS(v_file& file) { const auto romfs = nca->GetRomFS(); - - if (romfs == nullptr) { - NGLOG_DEBUG(Loader, "No RomFS available"); - return ResultStatus::ErrorNotUsed; - } - - file = romfs; + if (romfs != nullptr) + Service::FileSystem::RegisterRomFS(romfs); return ResultStatus::Success; } diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 682ee16898..e51c52eecc 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -31,8 +31,6 @@ public: ResultStatus Load(Kernel::SharedPtr& process) override; - ResultStatus ReadRomFS(v_file& file) override; - ~AppLoader_NCA(); private: diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index fdf9758757..bf4d5f99c3 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -96,6 +96,9 @@ static constexpr u32 PageAlignSize(u32 size) { } VAddr AppLoader_NSO::LoadModule(v_file file, VAddr load_base) { + if (file == nullptr) + return {}; + if (file->GetSize() < sizeof(NsoHeader)) return {}; diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 5a708dc73b..59f4896ac8 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -12,6 +12,7 @@ #include "common/common_paths.h" #include "common/logging/log.h" #include "common/string_util.h" +#include "core/file_sys/vfs_real.h" #include "core/loader/loader.h" #include "game_list.h" #include "game_list_p.h" @@ -404,7 +405,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign bool is_dir = FileUtil::IsDirectory(physical_name); if (!is_dir && (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { - std::unique_ptr loader = Loader::GetLoader(physical_name); + std::unique_ptr loader = + Loader::GetLoader(std::make_unique(physical_name)); if (!loader) return true;