diff options
author | Zach Hilman <DarkLordZach@users.noreply.github.com> | 2018-07-06 16:51:32 +0200 |
---|---|---|
committer | bunnei <bunneidev@gmail.com> | 2018-07-06 16:51:32 +0200 |
commit | 77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2 (patch) | |
tree | 38ef6451732c5eecb0efdd198f3db4d33848453c /src/core/hle | |
parent | Merge pull request #629 from Subv/depth_test (diff) | |
download | yuzu-77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.tar yuzu-77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.tar.gz yuzu-77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.tar.bz2 yuzu-77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.tar.lz yuzu-77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.tar.xz yuzu-77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.tar.zst yuzu-77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.zip |
Diffstat (limited to 'src/core/hle')
-rw-r--r-- | src/core/hle/service/am/am.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/service/filesystem/filesystem.cpp | 225 | ||||
-rw-r--r-- | src/core/hle/service/filesystem/filesystem.h | 133 | ||||
-rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 114 | ||||
-rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.h | 2 |
5 files changed, 405 insertions, 71 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index a871b3eaa..7bb13c735 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 f58b518b6..25810c165 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -2,36 +2,221 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <boost/container/flat_map.hpp> +#include "boost/container/flat_map.hpp" +#include "common/assert.h" +#include "common/common_paths.h" #include "common/file_util.h" +#include "core/core.h" +#include "core/file_sys/errors.h" #include "core/file_sys/filesystem.h" -#include "core/file_sys/savedata_factory.h" -#include "core/file_sys/sdmc_factory.h" +#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs_real.h" +#include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_srv.h" namespace Service::FileSystem { +// Size of emulated sd card free space, reported in bytes. +// Just using 32GB because thats reasonable +// TODO(DarkLordZach): Eventually make this configurable in settings. +constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000; + +static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, + const std::string& dir_name) { + if (dir_name == "." || dir_name == "" || dir_name == "/" || dir_name == "\\") + return base; + + return base->GetDirectoryRelative(dir_name); +} + +VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_) + : backing(backing_) {} + +std::string VfsDirectoryServiceWrapper::GetName() const { + return backing->GetName(); +} + +ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path, u64 size) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + auto file = dir->CreateFile(FileUtil::GetFilename(path)); + if (file == nullptr) + return ResultCode(-1); + if (!file->Resize(size)) + return ResultCode(-1); + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (!backing->DeleteFile(FileUtil::GetFilename(path))) + return ResultCode(-1); + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty()) + dir = backing; + auto new_dir = dir->CreateSubdirectory(FileUtil::GetFilename(path)); + if (new_dir == nullptr) + return ResultCode(-1); + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) + return ResultCode(-1); + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) + return ResultCode(-1); + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path, + const std::string& dest_path) const { + auto src = backing->GetFileRelative(src_path); + if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { + // Use more-optimized vfs implementation rename. + if (src == nullptr) + return FileSys::ERROR_PATH_NOT_FOUND; + if (!src->Rename(FileUtil::GetFilename(dest_path))) + return ResultCode(-1); + return RESULT_SUCCESS; + } + + // Move by hand -- TODO(DarkLordZach): Optimize + auto c_res = CreateFile(dest_path, src->GetSize()); + if (c_res != RESULT_SUCCESS) + return c_res; + + auto dest = backing->GetFileRelative(dest_path); + ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found."); + + ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(), + "Could not write all of the bytes but everything else has succeded."); + + if (!src->GetContainingDirectory()->DeleteFile(FileUtil::GetFilename(src_path))) + return ResultCode(-1); + + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path, + const std::string& dest_path) const { + auto src = GetDirectoryRelativeWrapped(backing, src_path); + if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { + // Use more-optimized vfs implementation rename. + if (src == nullptr) + return FileSys::ERROR_PATH_NOT_FOUND; + if (!src->Rename(FileUtil::GetFilename(dest_path))) + return ResultCode(-1); + return RESULT_SUCCESS; + } + + // TODO(DarkLordZach): Implement renaming across the tree (move). + ASSERT_MSG(false, + "Could not rename directory with path \"{}\" to new path \"{}\" because parent dirs " + "don't match -- UNIMPLEMENTED", + src_path, dest_path); + + return ResultCode(-1); +} + +ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path, + FileSys::Mode mode) const { + auto file = backing->GetFileRelative(path); + if (file == nullptr) + return FileSys::ERROR_PATH_NOT_FOUND; + + if ((static_cast<u32>(mode) & static_cast<u32>(FileSys::Mode::Append)) != 0) { + return MakeResult<FileSys::VirtualFile>( + std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize())); + } + + return MakeResult<FileSys::VirtualFile>(file); +} + +ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path) { + auto dir = GetDirectoryRelativeWrapped(backing, path); + if (dir == nullptr) + return ResultCode(-1); + return MakeResult(dir); +} + +u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const { + if (backing->IsWritable()) + return EMULATED_SD_REPORTED_SIZE; + + return 0; +} + +ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType( + const std::string& path) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (dir == nullptr) + return ResultCode(-1); + auto filename = FileUtil::GetFilename(path); + if (dir->GetFile(filename) != nullptr) + return MakeResult(FileSys::EntryType::File); + if (dir->GetSubdirectory(filename) != nullptr) + return MakeResult(FileSys::EntryType::Directory); + return ResultCode(-1); +} + +// A deferred filesystem for nand save data. +// This must be deferred because the directory is dependent on title id, which is not set at +// registration time. +struct SaveDataDeferredFilesystem : DeferredFilesystem { +protected: + FileSys::VirtualDir CreateFilesystem() override { + u64 title_id = Core::CurrentProcess()->program_id; + // TODO(DarkLordZach): Users + u32 user_id = 0; + std::string nand_directory = fmt::format( + "{}save/{:016X}/{:08X}/", FileUtil::GetUserPath(D_NAND_IDX), title_id, user_id); + + auto savedata = + std::make_shared<FileSys::RealVfsDirectory>(nand_directory, FileSys::Mode::Write); + return savedata; + } +}; + /** * Map of registered file systems, identified by type. Once an file system is registered here, it * is never removed until UnregisterFileSystems is called. */ -static boost::container::flat_map<Type, std::unique_ptr<FileSys::FileSystemFactory>> filesystem_map; +static boost::container::flat_map<Type, std::unique_ptr<DeferredFilesystem>> filesystem_map; +static FileSys::VirtualFile filesystem_romfs = nullptr; -ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type) { +ResultCode RegisterFileSystem(std::unique_ptr<DeferredFilesystem>&& factory, Type type) { auto result = filesystem_map.emplace(type, std::move(factory)); bool inserted = result.second; ASSERT_MSG(inserted, "Tried to register more than one system with same id code"); auto& filesystem = result.first->second; + LOG_DEBUG(Service_FS, "Registered file system with id code 0x{:08X}", static_cast<u32>(type)); + return RESULT_SUCCESS; +} + +ResultCode RegisterRomFS(FileSys::VirtualFile filesystem) { + ASSERT_MSG(filesystem_romfs == nullptr, + "Tried to register more than one system with same id code"); + + filesystem_romfs = filesystem; LOG_DEBUG(Service_FS, "Registered file system {} with id code 0x{:08X}", filesystem->GetName(), - static_cast<u32>(type)); + static_cast<u32>(Type::RomFS)); return RESULT_SUCCESS; } -ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, - FileSys::Path& path) { +ResultVal<FileSys::VirtualDir> OpenFileSystem(Type type) { LOG_TRACE(Service_FS, "Opening FileSystem with type={}", static_cast<u32>(type)); auto itr = filesystem_map.find(type); @@ -40,7 +225,13 @@ ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, return ResultCode(-1); } - return itr->second->Open(path); + return MakeResult(itr->second->Get()); +} + +ResultVal<FileSys::VirtualFile> OpenRomFS() { + if (filesystem_romfs == nullptr) + return ResultCode(-1); + return MakeResult(filesystem_romfs); } ResultCode FormatFileSystem(Type type) { @@ -52,21 +243,21 @@ ResultCode FormatFileSystem(Type type) { return ResultCode(-1); } - FileSys::Path unused; - return itr->second->Format(unused); + return itr->second->Get()->GetParentDirectory()->DeleteSubdirectory( + itr->second->Get()->GetName()) + ? RESULT_SUCCESS + : ResultCode(-1); } void RegisterFileSystems() { filesystem_map.clear(); + filesystem_romfs = nullptr; - std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX); + auto sdcard = std::make_shared<FileSys::RealVfsDirectory>(sd_directory, FileSys::Mode::Write); + RegisterFileSystem(std::make_unique<DeferredFilesystem>(sdcard), Type::SDMC); - auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory)); - RegisterFileSystem(std::move(savedata), Type::SaveData); - - auto sdcard = std::make_unique<FileSys::SDMC_Factory>(std::move(sd_directory)); - RegisterFileSystem(std::move(sdcard), Type::SDMC); + RegisterFileSystem(std::make_unique<SaveDataDeferredFilesystem>(), Type::SaveData); } void InstallInterfaces(SM::ServiceManager& service_manager) { diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 56d26146e..d3de797f1 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -6,6 +6,8 @@ #include <memory> #include "common/common_types.h" +#include "core/file_sys/filesystem.h" +#include "core/file_sys/vfs.h" #include "core/hle/result.h" namespace FileSys { @@ -29,12 +31,136 @@ enum class Type { SDMC = 3, }; +// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of +// pointers and booleans. This makes using a VfsDirectory with switch services much easier and +// avoids repetitive code. +class VfsDirectoryServiceWrapper { +public: + explicit VfsDirectoryServiceWrapper(FileSys::VirtualDir backing); + + /** + * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) + */ + std::string GetName() const; + + /** + * Create a file specified by its path + * @param path Path relative to the Archive + * @param size The size of the new file, filled with zeroes + * @return Result of the operation + */ + ResultCode CreateFile(const std::string& path, u64 size) const; + + /** + * Delete a file specified by its path + * @param path Path relative to the archive + * @return Result of the operation + */ + ResultCode DeleteFile(const std::string& path) const; + + /** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Result of the operation + */ + ResultCode CreateDirectory(const std::string& path) const; + + /** + * Delete a directory specified by its path + * @param path Path relative to the archive + * @return Result of the operation + */ + ResultCode DeleteDirectory(const std::string& path) const; + + /** + * Delete a directory specified by its path and anything under it + * @param path Path relative to the archive + * @return Result of the operation + */ + ResultCode DeleteDirectoryRecursively(const std::string& path) const; + + /** + * Rename a File specified by its path + * @param src_path Source path relative to the archive + * @param dest_path Destination path relative to the archive + * @return Result of the operation + */ + ResultCode RenameFile(const std::string& src_path, const std::string& dest_path) const; + + /** + * Rename a Directory specified by its path + * @param src_path Source path relative to the archive + * @param dest_path Destination path relative to the archive + * @return Result of the operation + */ + ResultCode RenameDirectory(const std::string& src_path, const std::string& dest_path) const; + + /** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or error code + */ + ResultVal<FileSys::VirtualFile> OpenFile(const std::string& path, FileSys::Mode mode) const; + + /** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or error code + */ + ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path); + + /** + * Get the free space + * @return The number of free bytes in the archive + */ + u64 GetFreeSpaceSize() const; + + /** + * Get the type of the specified path + * @return The type of the specified path or error code + */ + ResultVal<FileSys::EntryType> GetEntryType(const std::string& path) const; + +private: + FileSys::VirtualDir backing; +}; + +// A class that deferres the creation of a filesystem until a later time. +// This is useful if construction depends on a variable not known when the filesystem is registered. +// Construct this with a filesystem (VirtualDir) to avoid the deferrence feature or override the +// CreateFilesystem method which will be called on first use. +struct DeferredFilesystem { + DeferredFilesystem() = default; + + explicit DeferredFilesystem(FileSys::VirtualDir vfs_directory) : fs(std::move(vfs_directory)) {} + + FileSys::VirtualDir Get() { + if (fs == nullptr) + fs = CreateFilesystem(); + + return fs; + } + + virtual ~DeferredFilesystem() = default; + +protected: + virtual FileSys::VirtualDir CreateFilesystem() { + return fs; + } + +private: + FileSys::VirtualDir fs; +}; + /** * Registers a FileSystem, instances of which can later be opened using its IdCode. * @param factory FileSystem backend interface to use * @param type Type used to access this type of FileSystem */ -ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type); +ResultCode RegisterFileSystem(std::unique_ptr<DeferredFilesystem>&& fs, Type type); + +ResultCode RegisterRomFS(FileSys::VirtualFile fs); /** * Opens a file system @@ -42,8 +168,9 @@ ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& fact * @param path Path to the file system, used with Binary paths * @return FileSys::FileSystemBackend interface to the file system */ -ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, - FileSys::Path& path); +ResultVal<FileSys::VirtualDir> OpenFileSystem(Type type); + +ResultVal<FileSys::VirtualFile> OpenRomFS(); /** * Formats a file system diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 216bfea0a..26e8a8c88 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -19,8 +19,8 @@ namespace Service::FileSystem { class IStorage final : public ServiceFramework<IStorage> { public: - IStorage(std::unique_ptr<FileSys::StorageBackend>&& backend) - : ServiceFramework("IStorage"), backend(std::move(backend)) { + IStorage(FileSys::VirtualFile backend_) + : ServiceFramework("IStorage"), backend(std::move(backend_)) { static const FunctionInfo functions[] = { {0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"}, {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"}, @@ -29,7 +29,7 @@ public: } private: - std::unique_ptr<FileSys::StorageBackend> backend; + FileSys::VirtualFile backend; void Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; @@ -51,8 +51,8 @@ private: } // Read the data from the Storage backend - std::vector<u8> output(length); - ResultVal<size_t> res = backend->Read(offset, length, output.data()); + std::vector<u8> output = backend->ReadBytes(length, offset); + auto res = MakeResult<size_t>(output.size()); if (res.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(res.Code()); @@ -69,8 +69,8 @@ private: class IFile final : public ServiceFramework<IFile> { public: - explicit IFile(std::unique_ptr<FileSys::StorageBackend>&& backend) - : ServiceFramework("IFile"), backend(std::move(backend)) { + explicit IFile(FileSys::VirtualFile backend_) + : ServiceFramework("IFile"), backend(std::move(backend_)) { static const FunctionInfo functions[] = { {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"}, @@ -80,7 +80,7 @@ public: } private: - std::unique_ptr<FileSys::StorageBackend> backend; + FileSys::VirtualFile backend; void Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; @@ -103,8 +103,8 @@ private: } // Read the data from the Storage backend - std::vector<u8> output(length); - ResultVal<size_t> res = backend->Read(offset, length, output.data()); + std::vector<u8> output = backend->ReadBytes(length, offset); + auto res = MakeResult<size_t>(output.size()); if (res.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(res.Code()); @@ -139,9 +139,10 @@ private: return; } - // Write the data to the Storage backend std::vector<u8> data = ctx.ReadBuffer(); - ResultVal<size_t> res = backend->Write(offset, length, true, data.data()); + data.resize(length); + // Write the data to the Storage backend + auto res = MakeResult<size_t>(backend->WriteBytes(data, offset)); if (res.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(res.Code()); @@ -154,7 +155,8 @@ private: void Flush(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "called"); - backend->Flush(); + + // Exists for SDK compatibiltity -- No need to flush file. IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -163,7 +165,7 @@ private: void SetSize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 size = rp.Pop<u64>(); - backend->SetSize(size); + backend->Resize(size); LOG_DEBUG(Service_FS, "called, size={}", size); IPC::ResponseBuilder rb{ctx, 2}; @@ -180,19 +182,38 @@ private: } }; +template <typename T> +static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data, + FileSys::EntryType type) { + for (const auto& new_entry : new_data) { + FileSys::Entry entry; + entry.filename[0] = '\0'; + std::strncat(entry.filename, new_entry->GetName().c_str(), FileSys::FILENAME_LENGTH - 1); + entry.type = type; + entry.file_size = new_entry->GetSize(); + entries.emplace_back(std::move(entry)); + } +} + class IDirectory final : public ServiceFramework<IDirectory> { public: - explicit IDirectory(std::unique_ptr<FileSys::DirectoryBackend>&& backend) - : ServiceFramework("IDirectory"), backend(std::move(backend)) { + explicit IDirectory(FileSys::VirtualDir backend_) + : ServiceFramework("IDirectory"), backend(std::move(backend_)) { static const FunctionInfo functions[] = { {0, &IDirectory::Read, "Read"}, {1, &IDirectory::GetEntryCount, "GetEntryCount"}, }; RegisterHandlers(functions); + + // Build entry index now to save time later. + BuildEntryIndex(entries, backend->GetFiles(), FileSys::File); + BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::Directory); } private: - std::unique_ptr<FileSys::DirectoryBackend> backend; + FileSys::VirtualDir backend; + std::vector<FileSys::Entry> entries; + u64 next_entry_index = 0; void Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; @@ -203,26 +224,31 @@ 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<FileSys::Entry> entries(count_entries); - u64 read_entries = backend->Read(count_entries, entries.data()); + std::vector<FileSys::Entry> entry_data(entries.begin() + next_entry_index, + entries.begin() + next_entry_index + actual_entries); + + next_entry_index += actual_entries; // Convert the data into a byte array - std::vector<u8> output(entries.size() * sizeof(FileSys::Entry)); - std::memcpy(output.data(), entries.data(), output.size()); + std::vector<u8> 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); @@ -232,7 +258,7 @@ private: class IFileSystem final : public ServiceFramework<IFileSystem> { public: - explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend) + explicit IFileSystem(FileSys::VirtualDir backend) : ServiceFramework("IFileSystem"), backend(std::move(backend)) { static const FunctionInfo functions[] = { {0, &IFileSystem::CreateFile, "CreateFile"}, @@ -267,7 +293,7 @@ public: LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend->CreateFile(name, size)); + rb.Push(backend.CreateFile(name, size)); } void DeleteFile(Kernel::HLERequestContext& ctx) { @@ -279,7 +305,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) { @@ -291,7 +317,7 @@ public: LOG_DEBUG(Service_FS, "called directory {}", name); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend->CreateDirectory(name)); + rb.Push(backend.CreateDirectory(name)); } void RenameFile(Kernel::HLERequestContext& ctx) { @@ -309,7 +335,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) { @@ -322,14 +348,14 @@ public: LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(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); @@ -347,14 +373,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); @@ -369,7 +395,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()); @@ -389,7 +415,7 @@ public: } private: - std::unique_ptr<FileSys::FileSystemBackend> backend; + VfsDirectoryServiceWrapper backend; }; FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { @@ -490,8 +516,7 @@ void FSP_SRV::TryLoadRomFS() { if (romfs) { return; } - FileSys::Path unused; - auto res = OpenFileSystem(Type::RomFS, unused); + auto res = OpenRomFS(); if (res.Succeeded()) { romfs = std::move(res.Unwrap()); } @@ -507,8 +532,7 @@ void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) { void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "called"); - FileSys::Path unused; - auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap(); + IFileSystem filesystem(OpenFileSystem(Type::SDMC).Unwrap()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -531,8 +555,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); @@ -559,18 +582,11 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { return; } - // Attempt to open a StorageBackend interface to the RomFS - auto storage = romfs->OpenFile({}, {}); - if (storage.Failed()) { - LOG_CRITICAL(Service_FS, "no storage interface available!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(storage.Code()); - return; - } + IStorage storage(romfs); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap())); + rb.PushIpcInterface<IStorage>(std::move(storage)); } void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index acb78fac1..b1ef6397f 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -29,7 +29,7 @@ private: void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); void OpenRomStorage(Kernel::HLERequestContext& ctx); - std::unique_ptr<FileSys::FileSystemBackend> romfs; + FileSys::VirtualFile romfs; }; } // namespace Service::FileSystem |