diff options
Diffstat (limited to 'src/core/hle/service/filesystem')
20 files changed, 733 insertions, 596 deletions
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index ca6d8d607..ae230afc0 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -12,18 +12,17 @@ #include "core/file_sys/card_image.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/errors.h" -#include "core/file_sys/mode.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs_factory.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/vfs.h" +#include "core/file_sys/vfs/vfs_offset.h" #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/filesystem/fsp_ldr.h" -#include "core/hle/service/filesystem/fsp_pr.h" -#include "core/hle/service/filesystem/fsp_srv.h" +#include "core/hle/service/filesystem/fsp/fsp_ldr.h" +#include "core/hle/service/filesystem/fsp/fsp_pr.h" +#include "core/hle/service/filesystem/fsp/fsp_srv.h" #include "core/hle/service/filesystem/romfs_controller.h" #include "core/hle/service/filesystem/save_data_controller.h" #include "core/hle/service/server_manager.h" @@ -53,12 +52,12 @@ Result VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size std::string path(Common::FS::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } - FileSys::EntryType entry_type{}; + FileSys::DirectoryEntryType entry_type{}; if (GetEntryType(&entry_type, path) == ResultSuccess) { - return FileSys::ERROR_PATH_ALREADY_EXISTS; + return FileSys::ResultPathAlreadyExists; } auto file = dir->CreateFile(Common::FS::GetFilename(path)); @@ -82,7 +81,7 @@ Result VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } if (!dir->DeleteFile(Common::FS::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this @@ -153,12 +152,12 @@ Result VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { // Use more-optimized vfs implementation rename. if (src == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } if (dst && Common::FS::Exists(dst->GetFullPath())) { LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath()); - return FileSys::ERROR_PATH_ALREADY_EXISTS; + return FileSys::ResultPathAlreadyExists; } if (!src->Rename(Common::FS::GetFilename(dest_path))) { @@ -195,7 +194,7 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_, if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { // Use more-optimized vfs implementation rename. if (src == nullptr) - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; if (!src->Rename(Common::FS::GetFilename(dest_path))) { // TODO(DarkLordZach): Find a better error code for this return ResultUnknown; @@ -214,7 +213,8 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_, } Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file, - const std::string& path_, FileSys::Mode mode) const { + const std::string& path_, + FileSys::OpenMode mode) const { const std::string path(Common::FS::SanitizePath(path_)); std::string_view npath = path; while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) { @@ -223,10 +223,10 @@ Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file, auto file = backing->GetFileRelative(npath); if (file == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } - if (mode == FileSys::Mode::Append) { + if (mode == FileSys::OpenMode::AllowAppend) { *out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize()); } else { *out_file = file; @@ -241,50 +241,50 @@ Result VfsDirectoryServiceWrapper::OpenDirectory(FileSys::VirtualDir* out_direct auto dir = GetDirectoryRelativeWrapped(backing, path); if (dir == nullptr) { // TODO(DarkLordZach): Find a better error code for this - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } *out_directory = dir; return ResultSuccess; } -Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::EntryType* out_entry_type, +Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::DirectoryEntryType* out_entry_type, const std::string& path_) const { std::string path(Common::FS::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } auto filename = Common::FS::GetFilename(path); // TODO(Subv): Some games use the '/' path, find out what this means. if (filename.empty()) { - *out_entry_type = FileSys::EntryType::Directory; + *out_entry_type = FileSys::DirectoryEntryType::Directory; return ResultSuccess; } if (dir->GetFile(filename) != nullptr) { - *out_entry_type = FileSys::EntryType::File; + *out_entry_type = FileSys::DirectoryEntryType::File; return ResultSuccess; } if (dir->GetSubdirectory(filename) != nullptr) { - *out_entry_type = FileSys::EntryType::Directory; + *out_entry_type = FileSys::DirectoryEntryType::Directory; return ResultSuccess; } - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw( FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const { auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } - FileSys::EntryType entry_type; + FileSys::DirectoryEntryType entry_type; if (GetEntryType(&entry_type, path) != ResultSuccess) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } *out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path)); @@ -317,7 +317,7 @@ Result FileSystemController::OpenProcess( const auto it = registrations.find(process_id); if (it == registrations.end()) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } *out_program_id = it->second.program_id; @@ -347,7 +347,7 @@ std::shared_ptr<SaveDataController> FileSystemController::OpenSaveDataController std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory( ProgramId program_id) { using YuzuPath = Common::FS::YuzuPath; - const auto rw_mode = FileSys::Mode::ReadWrite; + const auto rw_mode = FileSys::OpenMode::ReadWrite; auto vfs = system.GetFilesystem(); const auto nand_directory = @@ -360,12 +360,12 @@ Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const { LOG_TRACE(Service_FS, "Opening SDMC"); if (sdmc_factory == nullptr) { - return FileSys::ERROR_SD_CARD_NOT_FOUND; + return FileSys::ResultPortSdCardNoDevice; } auto sdmc = sdmc_factory->Open(); if (sdmc == nullptr) { - return FileSys::ERROR_SD_CARD_NOT_FOUND; + return FileSys::ResultPortSdCardNoDevice; } *out_sdmc = sdmc; @@ -377,12 +377,12 @@ Result FileSystemController::OpenBISPartition(FileSys::VirtualDir* out_bis_parti LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id); if (bis_factory == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } auto part = bis_factory->OpenPartition(id); if (part == nullptr) { - return FileSys::ERROR_INVALID_ARGUMENT; + return FileSys::ResultInvalidArgument; } *out_bis_partition = part; @@ -394,12 +394,12 @@ Result FileSystemController::OpenBISPartitionStorage( LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id); if (bis_factory == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } auto part = bis_factory->OpenPartitionStorage(id, system.GetFilesystem()); if (part == nullptr) { - return FileSys::ERROR_INVALID_ARGUMENT; + return FileSys::ResultInvalidArgument; } *out_bis_partition_storage = part; @@ -686,15 +686,15 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove using YuzuPath = Common::FS::YuzuPath; const auto sdmc_dir_path = Common::FS::GetYuzuPath(YuzuPath::SDMCDir); const auto sdmc_load_dir_path = sdmc_dir_path / "atmosphere/contents"; - const auto rw_mode = FileSys::Mode::ReadWrite; + const auto rw_mode = FileSys::OpenMode::ReadWrite; auto nand_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode); auto sd_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_dir_path), rw_mode); - auto load_directory = - vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), FileSys::Mode::Read); - auto sd_load_directory = - vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), FileSys::Mode::Read); + auto load_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), + FileSys::OpenMode::Read); + auto sd_load_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), + FileSys::OpenMode::Read); auto dump_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode); diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 48f37d289..718500385 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -4,9 +4,11 @@ #pragma once #include <memory> +#include <mutex> #include "common/common_types.h" -#include "core/file_sys/directory.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/fs_directory.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/result.h" namespace Core { @@ -26,7 +28,6 @@ class XCI; enum class BisPartitionId : u32; enum class ContentRecordType : u8; -enum class Mode : u32; enum class SaveDataSpaceId : u8; enum class SaveDataType : u8; enum class StorageId : u8; @@ -57,13 +58,6 @@ enum class ImageDirectoryId : u32 { SdCard, }; -enum class OpenDirectoryMode : u64 { - Directory = (1 << 0), - File = (1 << 1), - All = Directory | File -}; -DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode); - using ProcessId = u64; using ProgramId = u64; @@ -237,7 +231,7 @@ public: * @return Opened file, or error code */ Result OpenFile(FileSys::VirtualFile* out_file, const std::string& path, - FileSys::Mode mode) const; + FileSys::OpenMode mode) const; /** * Open a directory specified by its path @@ -250,7 +244,7 @@ public: * Get the type of the specified path * @return The type of the specified path or error code */ - Result GetEntryType(FileSys::EntryType* out_entry_type, const std::string& path) const; + Result GetEntryType(FileSys::DirectoryEntryType* out_entry_type, const std::string& path) const; /** * Get the timestamp of the specified path diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp new file mode 100644 index 000000000..39690018b --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/savedata_factory.h" +#include "core/hle/service/filesystem/fsp/fs_i_directory.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +template <typename T> +static void BuildEntryIndex(std::vector<FileSys::DirectoryEntry>& entries, + const std::vector<T>& new_data, FileSys::DirectoryEntryType type) { + entries.reserve(entries.size() + new_data.size()); + + for (const auto& new_entry : new_data) { + auto name = new_entry->GetName(); + + if (type == FileSys::DirectoryEntryType::File && + name == FileSys::GetSaveDataSizeFileName()) { + continue; + } + + entries.emplace_back(name, static_cast<s8>(type), + type == FileSys::DirectoryEntryType::Directory ? 0 + : new_entry->GetSize()); + } +} + +IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_, + FileSys::OpenDirectoryMode mode) + : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { + static const FunctionInfo functions[] = { + {0, &IDirectory::Read, "Read"}, + {1, &IDirectory::GetEntryCount, "GetEntryCount"}, + }; + RegisterHandlers(functions); + + // TODO(DarkLordZach): Verify that this is the correct behavior. + // Build entry index now to save time later. + if (True(mode & FileSys::OpenDirectoryMode::Directory)) { + BuildEntryIndex(entries, backend->GetSubdirectories(), + FileSys::DirectoryEntryType::Directory); + } + if (True(mode & FileSys::OpenDirectoryMode::File)) { + BuildEntryIndex(entries, backend->GetFiles(), FileSys::DirectoryEntryType::File); + } +} + +void IDirectory::Read(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called."); + + // Calculate how many entries we can fit in the output buffer + const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::DirectoryEntry>(); + + // Cap at total number of entries. + const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index); + + // Determine data start and end + const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index); + const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries); + const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); + + next_entry_index += actual_entries; + + // Write the data to memory + ctx.WriteBuffer(begin, range_size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(actual_entries); +} + +void IDirectory::GetEntryCount(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + u64 count = entries.size() - next_entry_index; + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(count); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.h b/src/core/hle/service/filesystem/fsp/fs_i_directory.h new file mode 100644 index 000000000..793ecfcd7 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/service.h" + +namespace FileSys { +struct DirectoryEntry; +} + +namespace Service::FileSystem { + +class IDirectory final : public ServiceFramework<IDirectory> { +public: + explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, + FileSys::OpenDirectoryMode mode); + +private: + FileSys::VirtualDir backend; + std::vector<FileSys::DirectoryEntry> entries; + u64 next_entry_index = 0; + + void Read(HLERequestContext& ctx); + void GetEntryCount(HLERequestContext& ctx); +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp new file mode 100644 index 000000000..9a18f6ec5 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp @@ -0,0 +1,127 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/file_sys/errors.h" +#include "core/hle/service/filesystem/fsp/fs_i_file.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_) + : ServiceFramework{system_, "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"}, + {4, &IFile::GetSize, "GetSize"}, + {5, nullptr, "OperateRange"}, + {6, nullptr, "OperateRangeWithBuffer"}, + }; + RegisterHandlers(functions); +} + +void IFile::Read(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 option = rp.Pop<u64>(); + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length); + + // Error checking + if (length < 0) { + LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidSize); + return; + } + if (offset < 0) { + LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidOffset); + return; + } + + // Read the data from the Storage backend + std::vector<u8> output = backend->ReadBytes(length, offset); + + // Write the data to memory + ctx.WriteBuffer(output); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u64>(output.size())); +} + +void IFile::Write(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 option = rp.Pop<u64>(); + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length); + + // Error checking + if (length < 0) { + LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidSize); + return; + } + if (offset < 0) { + LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidOffset); + return; + } + + const auto data = ctx.ReadBuffer(); + + ASSERT_MSG(static_cast<s64>(data.size()) <= length, + "Attempting to write more data than requested (requested={:016X}, actual={:016X}).", + length, data.size()); + + // Write the data to the Storage backend + const auto write_size = + static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length)); + const std::size_t written = backend->Write(data.data(), write_size, offset); + + ASSERT_MSG(static_cast<s64>(written) == length, + "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length, + written); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFile::Flush(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + // Exists for SDK compatibiltity -- No need to flush file. + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFile::SetSize(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 size = rp.Pop<u64>(); + LOG_DEBUG(Service_FS, "called, size={}", size); + + backend->Resize(size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFile::GetSize(HLERequestContext& ctx) { + const u64 size = backend->GetSize(); + LOG_DEBUG(Service_FS, "called, size={}", size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(size); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.h b/src/core/hle/service/filesystem/fsp/fs_i_file.h new file mode 100644 index 000000000..5e5430c67 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_file.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/service.h" + +namespace Service::FileSystem { + +class IFile final : public ServiceFramework<IFile> { +public: + explicit IFile(Core::System& system_, FileSys::VirtualFile backend_); + +private: + FileSys::VirtualFile backend; + + void Read(HLERequestContext& ctx); + void Write(HLERequestContext& ctx); + void Flush(HLERequestContext& ctx); + void SetSize(HLERequestContext& ctx); + void GetSize(HLERequestContext& ctx); +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp new file mode 100644 index 000000000..efa394dd1 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp @@ -0,0 +1,262 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/string_util.h" +#include "core/hle/service/filesystem/fsp/fs_i_directory.h" +#include "core/hle/service/filesystem/fsp/fs_i_file.h" +#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) + : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( + size_)} { + static const FunctionInfo functions[] = { + {0, &IFileSystem::CreateFile, "CreateFile"}, + {1, &IFileSystem::DeleteFile, "DeleteFile"}, + {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, + {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, + {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, + {5, &IFileSystem::RenameFile, "RenameFile"}, + {6, nullptr, "RenameDirectory"}, + {7, &IFileSystem::GetEntryType, "GetEntryType"}, + {8, &IFileSystem::OpenFile, "OpenFile"}, + {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, + {10, &IFileSystem::Commit, "Commit"}, + {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"}, + {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"}, + {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, + {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, + {15, nullptr, "QueryEntry"}, + {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, + }; + RegisterHandlers(functions); +} + +void IFileSystem::CreateFile(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + const u64 file_mode = rp.Pop<u64>(); + const u32 file_size = rp.Pop<u32>(); + + LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode, + file_size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.CreateFile(name, file_size)); +} + +void IFileSystem::DeleteFile(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. file={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteFile(name)); +} + +void IFileSystem::CreateDirectory(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. directory={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.CreateDirectory(name)); +} + +void IFileSystem::DeleteDirectory(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. directory={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteDirectory(name)); +} + +void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. directory={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteDirectoryRecursively(name)); +} + +void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. Directory: {}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.CleanDirectoryRecursively(name)); +} + +void IFileSystem::RenameFile(HLERequestContext& ctx) { + const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); + const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); + + 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)); +} + +void IFileSystem::OpenFile(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + const auto mode = static_cast<FileSys::OpenMode>(rp.Pop<u32>()); + + LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode); + + FileSys::VirtualFile vfs_file{}; + auto result = backend.OpenFile(&vfs_file, name, mode); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + auto file = std::make_shared<IFile>(system, vfs_file); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IFile>(std::move(file)); +} + +void IFileSystem::OpenDirectory(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>(); + + LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); + + FileSys::VirtualDir vfs_dir{}; + auto result = backend.OpenDirectory(&vfs_dir, name); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDirectory>(std::move(directory)); +} + +void IFileSystem::GetEntryType(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. file={}", name); + + FileSys::DirectoryEntryType vfs_entry_type{}; + auto result = backend.GetEntryType(&vfs_entry_type, name); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(static_cast<u32>(vfs_entry_type)); +} + +void IFileSystem::Commit(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(size.get_free_size()); +} + +void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(size.get_total_size()); +} + +void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name); + + FileSys::FileTimeStampRaw vfs_timestamp{}; + auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(ResultSuccess); + rb.PushRaw(vfs_timestamp); +} + +void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + struct FileSystemAttribute { + u8 dir_entry_name_length_max_defined; + u8 file_entry_name_length_max_defined; + u8 dir_path_name_length_max_defined; + u8 file_path_name_length_max_defined; + INSERT_PADDING_BYTES_NOINIT(0x5); + u8 utf16_dir_entry_name_length_max_defined; + u8 utf16_file_entry_name_length_max_defined; + u8 utf16_dir_path_name_length_max_defined; + u8 utf16_file_path_name_length_max_defined; + INSERT_PADDING_BYTES_NOINIT(0x18); + s32 dir_entry_name_length_max; + s32 file_entry_name_length_max; + s32 dir_path_name_length_max; + s32 file_path_name_length_max; + INSERT_PADDING_WORDS_NOINIT(0x5); + s32 utf16_dir_entry_name_length_max; + s32 utf16_file_entry_name_length_max; + s32 utf16_dir_path_name_length_max; + s32 utf16_file_path_name_length_max; + INSERT_PADDING_WORDS_NOINIT(0x18); + INSERT_PADDING_WORDS_NOINIT(0x1); + }; + static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size"); + + FileSystemAttribute savedata_attribute{}; + savedata_attribute.dir_entry_name_length_max_defined = true; + savedata_attribute.file_entry_name_length_max_defined = true; + savedata_attribute.dir_entry_name_length_max = 0x40; + savedata_attribute.file_entry_name_length_max = 0x40; + + IPC::ResponseBuilder rb{ctx, 50}; + rb.Push(ResultSuccess); + rb.PushRaw(savedata_attribute); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h new file mode 100644 index 000000000..b06b3ef0e --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/fsp/fsp_util.h" +#include "core/hle/service/service.h" + +namespace Service::FileSystem { + +class IFileSystem final : public ServiceFramework<IFileSystem> { +public: + explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_); + + void CreateFile(HLERequestContext& ctx); + void DeleteFile(HLERequestContext& ctx); + void CreateDirectory(HLERequestContext& ctx); + void DeleteDirectory(HLERequestContext& ctx); + void DeleteDirectoryRecursively(HLERequestContext& ctx); + void CleanDirectoryRecursively(HLERequestContext& ctx); + void RenameFile(HLERequestContext& ctx); + void OpenFile(HLERequestContext& ctx); + void OpenDirectory(HLERequestContext& ctx); + void GetEntryType(HLERequestContext& ctx); + void Commit(HLERequestContext& ctx); + void GetFreeSpaceSize(HLERequestContext& ctx); + void GetTotalSpaceSize(HLERequestContext& ctx); + void GetFileTimeStampRaw(HLERequestContext& ctx); + void GetFileSystemAttribute(HLERequestContext& ctx); + +private: + VfsDirectoryServiceWrapper backend; + SizeGetter size; +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp new file mode 100644 index 000000000..98223c1f9 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/file_sys/errors.h" +#include "core/hle/service/filesystem/fsp/fs_i_storage.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_) + : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { + static const FunctionInfo functions[] = { + {0, &IStorage::Read, "Read"}, + {1, nullptr, "Write"}, + {2, nullptr, "Flush"}, + {3, nullptr, "SetSize"}, + {4, &IStorage::GetSize, "GetSize"}, + {5, nullptr, "OperateRange"}, + }; + RegisterHandlers(functions); +} + +void IStorage::Read(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); + + // Error checking + if (length < 0) { + LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidSize); + return; + } + if (offset < 0) { + LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidOffset); + return; + } + + // Read the data from the Storage backend + std::vector<u8> output = backend->ReadBytes(length, offset); + // Write the data to memory + ctx.WriteBuffer(output); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IStorage::GetSize(HLERequestContext& ctx) { + const u64 size = backend->GetSize(); + LOG_DEBUG(Service_FS, "called, size={}", size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(size); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h new file mode 100644 index 000000000..cb5bebcc9 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/service.h" + +namespace Service::FileSystem { + +class IStorage final : public ServiceFramework<IStorage> { +public: + explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_); + +private: + FileSys::VirtualFile backend; + + void Read(HLERequestContext& ctx); + void GetSize(HLERequestContext& ctx); +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp index 1e3366e71..8ee733f47 100644 --- a/src/core/hle/service/filesystem/fsp_ldr.cpp +++ b/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/hle/service/filesystem/fsp_ldr.h" +#include "core/hle/service/filesystem/fsp/fsp_ldr.h" namespace Service::FileSystem { diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp/fsp_ldr.h index 358739a87..358739a87 100644 --- a/src/core/hle/service/filesystem/fsp_ldr.h +++ b/src/core/hle/service/filesystem/fsp/fsp_ldr.h diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp/fsp_pr.cpp index 4ffc31977..7c03ebaea 100644 --- a/src/core/hle/service/filesystem/fsp_pr.cpp +++ b/src/core/hle/service/filesystem/fsp/fsp_pr.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/hle/service/filesystem/fsp_pr.h" +#include "core/hle/service/filesystem/fsp/fsp_pr.h" namespace Service::FileSystem { diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp/fsp_pr.h index bd4e0a730..bd4e0a730 100644 --- a/src/core/hle/service/filesystem/fsp_pr.h +++ b/src/core/hle/service/filesystem/fsp/fsp_pr.h diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp index a2397bec4..2be72b021 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp @@ -15,18 +15,20 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" -#include "core/file_sys/directory.h" #include "core/file_sys/errors.h" -#include "core/file_sys/mode.h" +#include "core/file_sys/fs_directory.h" +#include "core/file_sys/fs_filesystem.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/system_archive/system_archive.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/result.h" #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/filesystem/fsp_srv.h" +#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" +#include "core/hle/service/filesystem/fsp/fs_i_storage.h" +#include "core/hle/service/filesystem/fsp/fsp_srv.h" #include "core/hle/service/filesystem/romfs_controller.h" #include "core/hle/service/filesystem/save_data_controller.h" #include "core/hle/service/hle_ipc.h" @@ -34,19 +36,6 @@ #include "core/reporter.h" namespace Service::FileSystem { - -struct SizeGetter { - std::function<u64()> get_free_size; - std::function<u64()> get_total_size; - - static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) { - return { - [&fsc, id] { return fsc.GetFreeSpaceSize(id); }, - [&fsc, id] { return fsc.GetTotalSpaceSize(id); }, - }; - } -}; - enum class FileSystemType : u8 { Invalid0 = 0, Invalid1 = 1, @@ -58,525 +47,6 @@ enum class FileSystemType : u8 { ApplicationPackage = 7, }; -class IStorage final : public ServiceFramework<IStorage> { -public: - explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_) - : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { - static const FunctionInfo functions[] = { - {0, &IStorage::Read, "Read"}, - {1, nullptr, "Write"}, - {2, nullptr, "Flush"}, - {3, nullptr, "SetSize"}, - {4, &IStorage::GetSize, "GetSize"}, - {5, nullptr, "OperateRange"}, - }; - RegisterHandlers(functions); - } - -private: - FileSys::VirtualFile backend; - - void Read(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const s64 offset = rp.Pop<s64>(); - const s64 length = rp.Pop<s64>(); - - LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); - - // Error checking - if (length < 0) { - LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_SIZE); - return; - } - if (offset < 0) { - LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_OFFSET); - return; - } - - // Read the data from the Storage backend - std::vector<u8> output = backend->ReadBytes(length, offset); - // Write the data to memory - ctx.WriteBuffer(output); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetSize(HLERequestContext& ctx) { - const u64 size = backend->GetSize(); - LOG_DEBUG(Service_FS, "called, size={}", size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(size); - } -}; - -class IFile final : public ServiceFramework<IFile> { -public: - explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) - : ServiceFramework{system_, "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"}, - {4, &IFile::GetSize, "GetSize"}, - {5, nullptr, "OperateRange"}, - {6, nullptr, "OperateRangeWithBuffer"}, - }; - RegisterHandlers(functions); - } - -private: - FileSys::VirtualFile backend; - - void Read(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 option = rp.Pop<u64>(); - const s64 offset = rp.Pop<s64>(); - const s64 length = rp.Pop<s64>(); - - LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, - length); - - // Error checking - if (length < 0) { - LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_SIZE); - return; - } - if (offset < 0) { - LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_OFFSET); - return; - } - - // Read the data from the Storage backend - std::vector<u8> output = backend->ReadBytes(length, offset); - - // Write the data to memory - ctx.WriteBuffer(output); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(static_cast<u64>(output.size())); - } - - void Write(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 option = rp.Pop<u64>(); - const s64 offset = rp.Pop<s64>(); - const s64 length = rp.Pop<s64>(); - - LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, - length); - - // Error checking - if (length < 0) { - LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_SIZE); - return; - } - if (offset < 0) { - LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_OFFSET); - return; - } - - const auto data = ctx.ReadBuffer(); - - ASSERT_MSG( - static_cast<s64>(data.size()) <= length, - "Attempting to write more data than requested (requested={:016X}, actual={:016X}).", - length, data.size()); - - // Write the data to the Storage backend - const auto write_size = - static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length)); - const std::size_t written = backend->Write(data.data(), write_size, offset); - - ASSERT_MSG(static_cast<s64>(written) == length, - "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length, - written); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void Flush(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - // Exists for SDK compatibiltity -- No need to flush file. - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void SetSize(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 size = rp.Pop<u64>(); - LOG_DEBUG(Service_FS, "called, size={}", size); - - backend->Resize(size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetSize(HLERequestContext& ctx) { - const u64 size = backend->GetSize(); - LOG_DEBUG(Service_FS, "called, size={}", size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(size); - } -}; - -template <typename T> -static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data, - FileSys::EntryType type) { - entries.reserve(entries.size() + new_data.size()); - - for (const auto& new_entry : new_data) { - auto name = new_entry->GetName(); - - if (type == FileSys::EntryType::File && name == FileSys::GetSaveDataSizeFileName()) { - continue; - } - - entries.emplace_back(name, type, - type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize()); - } -} - -class IDirectory final : public ServiceFramework<IDirectory> { -public: - explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, OpenDirectoryMode mode) - : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { - static const FunctionInfo functions[] = { - {0, &IDirectory::Read, "Read"}, - {1, &IDirectory::GetEntryCount, "GetEntryCount"}, - }; - RegisterHandlers(functions); - - // TODO(DarkLordZach): Verify that this is the correct behavior. - // Build entry index now to save time later. - if (True(mode & OpenDirectoryMode::Directory)) { - BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory); - } - if (True(mode & OpenDirectoryMode::File)) { - BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File); - } - } - -private: - FileSys::VirtualDir backend; - std::vector<FileSys::Entry> entries; - u64 next_entry_index = 0; - - void Read(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called."); - - // Calculate how many entries we can fit in the output buffer - const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::Entry>(); - - // Cap at total number of entries. - const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index); - - // Determine data start and end - const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index); - const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries); - const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); - - next_entry_index += actual_entries; - - // Write the data to memory - ctx.WriteBuffer(begin, range_size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(actual_entries); - } - - void GetEntryCount(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - u64 count = entries.size() - next_entry_index; - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(count); - } -}; - -class IFileSystem final : public ServiceFramework<IFileSystem> { -public: - explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) - : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( - size_)} { - static const FunctionInfo functions[] = { - {0, &IFileSystem::CreateFile, "CreateFile"}, - {1, &IFileSystem::DeleteFile, "DeleteFile"}, - {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, - {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, - {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, - {5, &IFileSystem::RenameFile, "RenameFile"}, - {6, nullptr, "RenameDirectory"}, - {7, &IFileSystem::GetEntryType, "GetEntryType"}, - {8, &IFileSystem::OpenFile, "OpenFile"}, - {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, - {10, &IFileSystem::Commit, "Commit"}, - {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"}, - {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"}, - {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, - {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, - {15, nullptr, "QueryEntry"}, - {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, - }; - RegisterHandlers(functions); - } - - void CreateFile(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - const u64 file_mode = rp.Pop<u64>(); - const u32 file_size = rp.Pop<u32>(); - - LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode, - file_size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.CreateFile(name, file_size)); - } - - void DeleteFile(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. file={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.DeleteFile(name)); - } - - void CreateDirectory(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. directory={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.CreateDirectory(name)); - } - - void DeleteDirectory(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. directory={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.DeleteDirectory(name)); - } - - void DeleteDirectoryRecursively(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. directory={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.DeleteDirectoryRecursively(name)); - } - - void CleanDirectoryRecursively(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. Directory: {}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.CleanDirectoryRecursively(name)); - } - - void RenameFile(HLERequestContext& ctx) { - const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); - const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); - - 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)); - } - - void OpenFile(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); - - LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode); - - FileSys::VirtualFile vfs_file{}; - auto result = backend.OpenFile(&vfs_file, name, mode); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - auto file = std::make_shared<IFile>(system, vfs_file); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IFile>(std::move(file)); - } - - void OpenDirectory(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - const auto mode = rp.PopRaw<OpenDirectoryMode>(); - - LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); - - FileSys::VirtualDir vfs_dir{}; - auto result = backend.OpenDirectory(&vfs_dir, name); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDirectory>(std::move(directory)); - } - - void GetEntryType(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. file={}", name); - - FileSys::EntryType vfs_entry_type{}; - auto result = backend.GetEntryType(&vfs_entry_type, name); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(static_cast<u32>(vfs_entry_type)); - } - - void Commit(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetFreeSpaceSize(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(size.get_free_size()); - } - - void GetTotalSpaceSize(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(size.get_total_size()); - } - - void GetFileTimeStampRaw(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name); - - FileSys::FileTimeStampRaw vfs_timestamp{}; - auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(ResultSuccess); - rb.PushRaw(vfs_timestamp); - } - - void GetFileSystemAttribute(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); - - struct FileSystemAttribute { - u8 dir_entry_name_length_max_defined; - u8 file_entry_name_length_max_defined; - u8 dir_path_name_length_max_defined; - u8 file_path_name_length_max_defined; - INSERT_PADDING_BYTES_NOINIT(0x5); - u8 utf16_dir_entry_name_length_max_defined; - u8 utf16_file_entry_name_length_max_defined; - u8 utf16_dir_path_name_length_max_defined; - u8 utf16_file_path_name_length_max_defined; - INSERT_PADDING_BYTES_NOINIT(0x18); - s32 dir_entry_name_length_max; - s32 file_entry_name_length_max; - s32 dir_path_name_length_max; - s32 file_path_name_length_max; - INSERT_PADDING_WORDS_NOINIT(0x5); - s32 utf16_dir_entry_name_length_max; - s32 utf16_file_entry_name_length_max; - s32 utf16_dir_path_name_length_max; - s32 utf16_file_path_name_length_max; - INSERT_PADDING_WORDS_NOINIT(0x18); - INSERT_PADDING_WORDS_NOINIT(0x1); - }; - static_assert(sizeof(FileSystemAttribute) == 0xc0, - "FileSystemAttribute has incorrect size"); - - FileSystemAttribute savedata_attribute{}; - savedata_attribute.dir_entry_name_length_max_defined = true; - savedata_attribute.file_entry_name_length_max_defined = true; - savedata_attribute.dir_entry_name_length_max = 0x40; - savedata_attribute.file_entry_name_length_max = 0x40; - - IPC::ResponseBuilder rb{ctx, 50}; - rb.Push(ResultSuccess); - rb.PushRaw(savedata_attribute); - } - -private: - VfsDirectoryServiceWrapper backend; - SizeGetter size; -}; - class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { public: explicit ISaveDataInfoReader(Core::System& system_, @@ -960,7 +430,7 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) { save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute); if (result != ResultSuccess) { IPC::ResponseBuilder rb{ctx, 2, 0, 0}; - rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); + rb.Push(FileSys::ResultTargetNotFound); return; } @@ -1127,7 +597,7 @@ void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); + rb.Push(FileSys::ResultTargetNotFound); } void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h index 26980af99..26980af99 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h diff --git a/src/core/hle/service/filesystem/fsp/fsp_util.h b/src/core/hle/service/filesystem/fsp/fsp_util.h new file mode 100644 index 000000000..253f866db --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fsp_util.h @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/filesystem/filesystem.h" + +namespace Service::FileSystem { + +struct SizeGetter { + std::function<u64()> get_free_size; + std::function<u64()> get_total_size; + + static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) { + return { + [&fsc, id] { return fsc.GetFreeSpaceSize(id); }, + [&fsc, id] { return fsc.GetTotalSpaceSize(id); }, + }; + } +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/romfs_controller.h b/src/core/hle/service/filesystem/romfs_controller.h index 9a478f71d..3c3ead344 100644 --- a/src/core/hle/service/filesystem/romfs_controller.h +++ b/src/core/hle/service/filesystem/romfs_controller.h @@ -5,7 +5,7 @@ #include "core/file_sys/nca_metadata.h" #include "core/file_sys/romfs_factory.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace Service::FileSystem { diff --git a/src/core/hle/service/filesystem/save_data_controller.cpp b/src/core/hle/service/filesystem/save_data_controller.cpp index d19b3ea1e..03e45f7f9 100644 --- a/src/core/hle/service/filesystem/save_data_controller.cpp +++ b/src/core/hle/service/filesystem/save_data_controller.cpp @@ -44,7 +44,7 @@ Result SaveDataController::CreateSaveData(FileSys::VirtualDir* out_save_data, auto save_data = factory->Create(space, attribute); if (save_data == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } *out_save_data = save_data; @@ -56,7 +56,7 @@ Result SaveDataController::OpenSaveData(FileSys::VirtualDir* out_save_data, const FileSys::SaveDataAttribute& attribute) { auto save_data = factory->Open(space, attribute); if (save_data == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } *out_save_data = save_data; @@ -67,7 +67,7 @@ Result SaveDataController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_ FileSys::SaveDataSpaceId space) { auto save_data_space = factory->GetSaveDataSpaceDirectory(space); if (save_data_space == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } *out_save_data_space = save_data_space; diff --git a/src/core/hle/service/filesystem/save_data_controller.h b/src/core/hle/service/filesystem/save_data_controller.h index 863188e4c..dc9d713df 100644 --- a/src/core/hle/service/filesystem/save_data_controller.h +++ b/src/core/hle/service/filesystem/save_data_controller.h @@ -5,7 +5,7 @@ #include "core/file_sys/nca_metadata.h" #include "core/file_sys/savedata_factory.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" namespace Service::FileSystem { |