diff options
| author | liamwhite <liamwhite@users.noreply.github.com> | 2024-02-22 12:34:47 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-22 12:34:47 -0500 | 
| commit | d12d9dad4096af6280c6c418cf36a2faacede102 (patch) | |
| tree | ba52bf26efd8b2f7bf282b0564a68870022cccb7 | |
| parent | 2b3f1d3fc53c1b7a729c3f1cebbddebcd9427952 (diff) | |
| parent | ef5027712413705802d10c797b0f0b66375a9f58 (diff) | |
Merge pull request #12982 from FearlessTobi/fs-rewrite-part0
fs: Add FileSystemAccessor and use cmif serialization
| -rw-r--r-- | src/core/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/core/file_sys/fs_filesystem.h | 27 | ||||
| -rw-r--r-- | src/core/file_sys/fs_memory_management.h | 8 | ||||
| -rw-r--r-- | src/core/file_sys/fs_path.h | 2 | ||||
| -rw-r--r-- | src/core/file_sys/fs_path_utility.h | 7 | ||||
| -rw-r--r-- | src/core/file_sys/fs_string_util.h | 15 | ||||
| -rw-r--r-- | src/core/file_sys/fsa/fs_i_directory.h | 91 | ||||
| -rw-r--r-- | src/core/file_sys/fsa/fs_i_file.h | 167 | ||||
| -rw-r--r-- | src/core/file_sys/fsa/fs_i_filesystem.h | 206 | ||||
| -rw-r--r-- | src/core/file_sys/fssrv/fssrv_sf_path.h | 36 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp/fs_i_directory.cpp | 72 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp/fs_i_directory.h | 13 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp/fs_i_file.cpp | 124 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp/fs_i_file.h | 21 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp | 283 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp/fs_i_filesystem.h | 60 | 
16 files changed, 757 insertions, 379 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f67a12f8f..cfce352c9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -59,8 +59,12 @@ add_library(core STATIC      file_sys/fs_path.h      file_sys/fs_path_utility.h      file_sys/fs_string_util.h +    file_sys/fsa/fs_i_directory.h +    file_sys/fsa/fs_i_file.h +    file_sys/fsa/fs_i_filesystem.h      file_sys/fsmitm_romfsbuild.cpp      file_sys/fsmitm_romfsbuild.h +    file_sys/fssrv/fssrv_sf_path.h      file_sys/fssystem/fs_i_storage.h      file_sys/fssystem/fs_types.h      file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp diff --git a/src/core/file_sys/fs_filesystem.h b/src/core/file_sys/fs_filesystem.h index 7f237b7fa..329b5aca5 100644 --- a/src/core/file_sys/fs_filesystem.h +++ b/src/core/file_sys/fs_filesystem.h @@ -23,6 +23,8 @@ enum class OpenDirectoryMode : u64 {      File = (1 << 1),      All = (Directory | File), + +    NotRequireFileSize = (1ULL << 31),  };  DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode) @@ -36,4 +38,29 @@ enum class CreateOption : u8 {      BigFile = (1 << 0),  }; +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"); +  } // namespace FileSys diff --git a/src/core/file_sys/fs_memory_management.h b/src/core/file_sys/fs_memory_management.h index f03c6354b..080017c5d 100644 --- a/src/core/file_sys/fs_memory_management.h +++ b/src/core/file_sys/fs_memory_management.h @@ -10,7 +10,7 @@ namespace FileSys {  constexpr size_t RequiredAlignment = alignof(u64); -void* AllocateUnsafe(size_t size) { +inline void* AllocateUnsafe(size_t size) {      // Allocate      void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment}); @@ -21,16 +21,16 @@ void* AllocateUnsafe(size_t size) {      return ptr;  } -void DeallocateUnsafe(void* ptr, size_t size) { +inline void DeallocateUnsafe(void* ptr, size_t size) {      // Deallocate the pointer      ::operator delete(ptr, std::align_val_t{RequiredAlignment});  } -void* Allocate(size_t size) { +inline void* Allocate(size_t size) {      return AllocateUnsafe(size);  } -void Deallocate(void* ptr, size_t size) { +inline void Deallocate(void* ptr, size_t size) {      // If the pointer is non-null, deallocate it      if (ptr != nullptr) {          DeallocateUnsafe(ptr, size); diff --git a/src/core/file_sys/fs_path.h b/src/core/file_sys/fs_path.h index 56ba08a6a..1566e82b9 100644 --- a/src/core/file_sys/fs_path.h +++ b/src/core/file_sys/fs_path.h @@ -381,7 +381,7 @@ public:          // Check that it's possible for us to remove a child          auto* p = m_write_buffer.Get(); -        s32 len = std::strlen(p); +        s32 len = static_cast<s32>(std::strlen(p));          R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);          // Handle a trailing separator diff --git a/src/core/file_sys/fs_path_utility.h b/src/core/file_sys/fs_path_utility.h index 5643141f9..cdfd8c772 100644 --- a/src/core/file_sys/fs_path_utility.h +++ b/src/core/file_sys/fs_path_utility.h @@ -426,9 +426,10 @@ public:          R_SUCCEED();      } -    static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size, -                            bool is_windows_path, bool is_drive_relative_path, -                            bool allow_all_characters = false) { +    static constexpr Result Normalize(char* dst, size_t* out_len, const char* path, +                                      size_t max_out_size, bool is_windows_path, +                                      bool is_drive_relative_path, +                                      bool allow_all_characters = false) {          // Use StringTraits names for remainder of scope          using namespace StringTraits; diff --git a/src/core/file_sys/fs_string_util.h b/src/core/file_sys/fs_string_util.h index 874e09054..c751a8f1a 100644 --- a/src/core/file_sys/fs_string_util.h +++ b/src/core/file_sys/fs_string_util.h @@ -20,6 +20,11 @@ constexpr int Strlen(const T* str) {  }  template <typename T> +constexpr int Strnlen(const T* str, std::size_t count) { +    return Strnlen(str, static_cast<int>(count)); +} + +template <typename T>  constexpr int Strnlen(const T* str, int count) {      ASSERT(str != nullptr);      ASSERT(count >= 0); @@ -33,6 +38,11 @@ constexpr int Strnlen(const T* str, int count) {  }  template <typename T> +constexpr int Strncmp(const T* lhs, const T* rhs, std::size_t count) { +    return Strncmp(lhs, rhs, static_cast<int>(count)); +} + +template <typename T>  constexpr int Strncmp(const T* lhs, const T* rhs, int count) {      ASSERT(lhs != nullptr);      ASSERT(rhs != nullptr); @@ -52,6 +62,11 @@ constexpr int Strncmp(const T* lhs, const T* rhs, int count) {  }  template <typename T> +static constexpr int Strlcpy(T* dst, const T* src, std::size_t count) { +    return Strlcpy<T>(dst, src, static_cast<int>(count)); +} + +template <typename T>  static constexpr int Strlcpy(T* dst, const T* src, int count) {      ASSERT(dst != nullptr);      ASSERT(src != nullptr); diff --git a/src/core/file_sys/fsa/fs_i_directory.h b/src/core/file_sys/fsa/fs_i_directory.h new file mode 100644 index 000000000..c8e895eab --- /dev/null +++ b/src/core/file_sys/fsa/fs_i_directory.h @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/fs_directory.h" +#include "core/file_sys/fs_file.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/savedata_factory.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/result.h" + +namespace FileSys::Fsa { + +class IDirectory { +public: +    explicit IDirectory(VirtualDir backend_, OpenDirectoryMode mode) +        : backend(std::move(backend_)) { +        // TODO(DarkLordZach): Verify that this is the correct behavior. +        // Build entry index now to save time later. +        if (True(mode & OpenDirectoryMode::Directory)) { +            BuildEntryIndex(backend->GetSubdirectories(), DirectoryEntryType::Directory); +        } +        if (True(mode & OpenDirectoryMode::File)) { +            BuildEntryIndex(backend->GetFiles(), DirectoryEntryType::File); +        } +    } +    virtual ~IDirectory() {} + +    Result Read(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) { +        R_UNLESS(out_count != nullptr, ResultNullptrArgument); +        if (max_entries == 0) { +            *out_count = 0; +            R_SUCCEED(); +        } +        R_UNLESS(out_entries != nullptr, ResultNullptrArgument); +        R_UNLESS(max_entries > 0, ResultInvalidArgument); +        R_RETURN(this->DoRead(out_count, out_entries, max_entries)); +    } + +    Result GetEntryCount(s64* out) { +        R_UNLESS(out != nullptr, ResultNullptrArgument); +        R_RETURN(this->DoGetEntryCount(out)); +    } + +private: +    Result DoRead(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) { +        const u64 actual_entries = +            std::min(static_cast<u64>(max_entries), entries.size() - next_entry_index); +        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; +        *out_count = actual_entries; + +        std::memcpy(out_entries, begin, range_size); + +        R_SUCCEED(); +    } + +    Result DoGetEntryCount(s64* out) { +        *out = entries.size() - next_entry_index; +        R_SUCCEED(); +    } + +    // TODO: Remove this when VFS is gone +    template <typename T> +    void BuildEntryIndex(const std::vector<T>& new_data, DirectoryEntryType type) { +        entries.reserve(entries.size() + new_data.size()); + +        for (const auto& new_entry : new_data) { +            auto name = new_entry->GetName(); + +            if (type == DirectoryEntryType::File && name == GetSaveDataSizeFileName()) { +                continue; +            } + +            entries.emplace_back(name, static_cast<s8>(type), +                                 type == DirectoryEntryType::Directory ? 0 : new_entry->GetSize()); +        } +    } + +    VirtualDir backend; +    std::vector<DirectoryEntry> entries; +    u64 next_entry_index = 0; +}; + +} // namespace FileSys::Fsa diff --git a/src/core/file_sys/fsa/fs_i_file.h b/src/core/file_sys/fsa/fs_i_file.h new file mode 100644 index 000000000..1188ae8ca --- /dev/null +++ b/src/core/file_sys/fsa/fs_i_file.h @@ -0,0 +1,167 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/overflow.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/fs_file.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/fs_operate_range.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_types.h" +#include "core/hle/result.h" + +namespace FileSys::Fsa { + +class IFile { +public: +    explicit IFile(VirtualFile backend_) : backend(std::move(backend_)) {} +    virtual ~IFile() {} + +    Result Read(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) { +        // Check that we have an output pointer +        R_UNLESS(out != nullptr, ResultNullptrArgument); + +        // If we have nothing to read, just succeed +        if (size == 0) { +            *out = 0; +            R_SUCCEED(); +        } + +        // Check that the read is valid +        R_UNLESS(buffer != nullptr, ResultNullptrArgument); +        R_UNLESS(offset >= 0, ResultOutOfRange); +        R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange); + +        // Do the read +        R_RETURN(this->DoRead(out, offset, buffer, size, option)); +    } + +    Result Read(size_t* out, s64 offset, void* buffer, size_t size) { +        R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None)); +    } + +    Result GetSize(s64* out) { +        R_UNLESS(out != nullptr, ResultNullptrArgument); +        R_RETURN(this->DoGetSize(out)); +    } + +    Result Flush() { +        R_RETURN(this->DoFlush()); +    } + +    Result Write(s64 offset, const void* buffer, size_t size, const WriteOption& option) { +        // Handle the zero-size case +        if (size == 0) { +            if (option.HasFlushFlag()) { +                R_TRY(this->Flush()); +            } +            R_SUCCEED(); +        } + +        // Check the write is valid +        R_UNLESS(buffer != nullptr, ResultNullptrArgument); +        R_UNLESS(offset >= 0, ResultOutOfRange); +        R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange); + +        R_RETURN(this->DoWrite(offset, buffer, size, option)); +    } + +    Result SetSize(s64 size) { +        R_UNLESS(size >= 0, ResultOutOfRange); +        R_RETURN(this->DoSetSize(size)); +    } + +    Result OperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, +                        const void* src, size_t src_size) { +        R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size)); +    } + +    Result OperateRange(OperationId op_id, s64 offset, s64 size) { +        R_RETURN(this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0)); +    } + +protected: +    Result DryRead(size_t* out, s64 offset, size_t size, const ReadOption& option, +                   OpenMode open_mode) { +        // Check that we can read +        R_UNLESS(static_cast<u32>(open_mode & OpenMode::Read) != 0, ResultReadNotPermitted); + +        // Get the file size, and validate our offset +        s64 file_size = 0; +        R_TRY(this->DoGetSize(std::addressof(file_size))); +        R_UNLESS(offset <= file_size, ResultOutOfRange); + +        *out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size))); +        R_SUCCEED(); +    } + +    Result DrySetSize(s64 size, OpenMode open_mode) { +        // Check that we can write +        R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted); +        R_SUCCEED(); +    } + +    Result DryWrite(bool* out_append, s64 offset, size_t size, const WriteOption& option, +                    OpenMode open_mode) { +        // Check that we can write +        R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted); + +        // Get the file size +        s64 file_size = 0; +        R_TRY(this->DoGetSize(&file_size)); + +        // Determine if we need to append +        *out_append = false; +        if (file_size < offset + static_cast<s64>(size)) { +            R_UNLESS(static_cast<u32>(open_mode & OpenMode::AllowAppend) != 0, +                     ResultFileExtensionWithoutOpenModeAllowAppend); +            *out_append = true; +        } + +        R_SUCCEED(); +    } + +private: +    Result DoRead(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) { +        const auto read_size = backend->Read(static_cast<u8*>(buffer), size, offset); +        *out = read_size; + +        R_SUCCEED(); +    } + +    Result DoGetSize(s64* out) { +        *out = backend->GetSize(); +        R_SUCCEED(); +    } + +    Result DoFlush() { +        // Exists for SDK compatibiltity -- No need to flush file. +        R_SUCCEED(); +    } + +    Result DoWrite(s64 offset, const void* buffer, size_t size, const WriteOption& option) { +        const std::size_t written = backend->Write(static_cast<const u8*>(buffer), size, offset); + +        ASSERT_MSG(written == size, +                   "Could not write all bytes to file (requested={:016X}, actual={:016X}).", size, +                   written); + +        R_SUCCEED(); +    } + +    Result DoSetSize(s64 size) { +        backend->Resize(size); +        R_SUCCEED(); +    } + +    Result DoOperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, +                          const void* src, size_t src_size) { +        R_THROW(ResultNotImplemented); +    } + +    VirtualFile backend; +}; + +} // namespace FileSys::Fsa diff --git a/src/core/file_sys/fsa/fs_i_filesystem.h b/src/core/file_sys/fsa/fs_i_filesystem.h new file mode 100644 index 000000000..8172190f4 --- /dev/null +++ b/src/core/file_sys/fsa/fs_i_filesystem.h @@ -0,0 +1,206 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/errors.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/fs_path.h" +#include "core/file_sys/vfs/vfs_types.h" +#include "core/hle/result.h" +#include "core/hle/service/filesystem/filesystem.h" + +namespace FileSys::Fsa { + +class IFile; +class IDirectory; + +enum class QueryId : u32 { +    SetConcatenationFileAttribute = 0, +    UpdateMac = 1, +    IsSignedSystemPartitionOnSdCardValid = 2, +    QueryUnpreparedFileInformation = 3, +}; + +class IFileSystem { +public: +    explicit IFileSystem(VirtualDir backend_) : backend{std::move(backend_)} {} +    virtual ~IFileSystem() {} + +    Result CreateFile(const Path& path, s64 size, CreateOption option) { +        R_UNLESS(size >= 0, ResultOutOfRange); +        R_RETURN(this->DoCreateFile(path, size, static_cast<int>(option))); +    } + +    Result CreateFile(const Path& path, s64 size) { +        R_RETURN(this->CreateFile(path, size, CreateOption::None)); +    } + +    Result DeleteFile(const Path& path) { +        R_RETURN(this->DoDeleteFile(path)); +    } + +    Result CreateDirectory(const Path& path) { +        R_RETURN(this->DoCreateDirectory(path)); +    } + +    Result DeleteDirectory(const Path& path) { +        R_RETURN(this->DoDeleteDirectory(path)); +    } + +    Result DeleteDirectoryRecursively(const Path& path) { +        R_RETURN(this->DoDeleteDirectoryRecursively(path)); +    } + +    Result RenameFile(const Path& old_path, const Path& new_path) { +        R_RETURN(this->DoRenameFile(old_path, new_path)); +    } + +    Result RenameDirectory(const Path& old_path, const Path& new_path) { +        R_RETURN(this->DoRenameDirectory(old_path, new_path)); +    } + +    Result GetEntryType(DirectoryEntryType* out, const Path& path) { +        R_RETURN(this->DoGetEntryType(out, path)); +    } + +    Result OpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) { +        R_UNLESS(out_file != nullptr, ResultNullptrArgument); +        R_UNLESS(static_cast<u32>(mode & OpenMode::ReadWrite) != 0, ResultInvalidOpenMode); +        R_UNLESS(static_cast<u32>(mode & ~OpenMode::All) == 0, ResultInvalidOpenMode); +        R_RETURN(this->DoOpenFile(out_file, path, mode)); +    } + +    Result OpenDirectory(VirtualDir* out_dir, const Path& path, OpenDirectoryMode mode) { +        R_UNLESS(out_dir != nullptr, ResultNullptrArgument); +        R_UNLESS(static_cast<u64>(mode & OpenDirectoryMode::All) != 0, ResultInvalidOpenMode); +        R_UNLESS(static_cast<u64>( +                     mode & ~(OpenDirectoryMode::All | OpenDirectoryMode::NotRequireFileSize)) == 0, +                 ResultInvalidOpenMode); +        R_RETURN(this->DoOpenDirectory(out_dir, path, mode)); +    } + +    Result Commit() { +        R_RETURN(this->DoCommit()); +    } + +    Result GetFreeSpaceSize(s64* out, const Path& path) { +        R_UNLESS(out != nullptr, ResultNullptrArgument); +        R_RETURN(this->DoGetFreeSpaceSize(out, path)); +    } + +    Result GetTotalSpaceSize(s64* out, const Path& path) { +        R_UNLESS(out != nullptr, ResultNullptrArgument); +        R_RETURN(this->DoGetTotalSpaceSize(out, path)); +    } + +    Result CleanDirectoryRecursively(const Path& path) { +        R_RETURN(this->DoCleanDirectoryRecursively(path)); +    } + +    Result GetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) { +        R_UNLESS(out != nullptr, ResultNullptrArgument); +        R_RETURN(this->DoGetFileTimeStampRaw(out, path)); +    } + +    Result QueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query, +                      const Path& path) { +        R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path)); +    } + +    // These aren't accessible as commands +    Result CommitProvisionally(s64 counter) { +        R_RETURN(this->DoCommitProvisionally(counter)); +    } + +    Result Rollback() { +        R_RETURN(this->DoRollback()); +    } + +    Result Flush() { +        R_RETURN(this->DoFlush()); +    } + +private: +    Result DoCreateFile(const Path& path, s64 size, int flags) { +        R_RETURN(backend.CreateFile(path.GetString(), size)); +    } + +    Result DoDeleteFile(const Path& path) { +        R_RETURN(backend.DeleteFile(path.GetString())); +    } + +    Result DoCreateDirectory(const Path& path) { +        R_RETURN(backend.CreateDirectory(path.GetString())); +    } + +    Result DoDeleteDirectory(const Path& path) { +        R_RETURN(backend.DeleteDirectory(path.GetString())); +    } + +    Result DoDeleteDirectoryRecursively(const Path& path) { +        R_RETURN(backend.DeleteDirectoryRecursively(path.GetString())); +    } + +    Result DoRenameFile(const Path& old_path, const Path& new_path) { +        R_RETURN(backend.RenameFile(old_path.GetString(), new_path.GetString())); +    } + +    Result DoRenameDirectory(const Path& old_path, const Path& new_path) { +        R_RETURN(backend.RenameDirectory(old_path.GetString(), new_path.GetString())); +    } + +    Result DoGetEntryType(DirectoryEntryType* out, const Path& path) { +        R_RETURN(backend.GetEntryType(out, path.GetString())); +    } + +    Result DoOpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) { +        R_RETURN(backend.OpenFile(out_file, path.GetString(), mode)); +    } + +    Result DoOpenDirectory(VirtualDir* out_directory, const Path& path, OpenDirectoryMode mode) { +        R_RETURN(backend.OpenDirectory(out_directory, path.GetString())); +    } + +    Result DoCommit() { +        R_THROW(ResultNotImplemented); +    } + +    Result DoGetFreeSpaceSize(s64* out, const Path& path) { +        R_THROW(ResultNotImplemented); +    } + +    Result DoGetTotalSpaceSize(s64* out, const Path& path) { +        R_THROW(ResultNotImplemented); +    } + +    Result DoCleanDirectoryRecursively(const Path& path) { +        R_RETURN(backend.CleanDirectoryRecursively(path.GetString())); +    } + +    Result DoGetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) { +        R_RETURN(backend.GetFileTimeStampRaw(out, path.GetString())); +    } + +    Result DoQueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query, +                        const Path& path) { +        R_THROW(ResultNotImplemented); +    } + +    // These aren't accessible as commands +    Result DoCommitProvisionally(s64 counter) { +        R_THROW(ResultNotImplemented); +    } + +    Result DoRollback() { +        R_THROW(ResultNotImplemented); +    } + +    Result DoFlush() { +        R_THROW(ResultNotImplemented); +    } + +    Service::FileSystem::VfsDirectoryServiceWrapper backend; +}; + +} // namespace FileSys::Fsa diff --git a/src/core/file_sys/fssrv/fssrv_sf_path.h b/src/core/file_sys/fssrv/fssrv_sf_path.h new file mode 100644 index 000000000..a0c0b2dac --- /dev/null +++ b/src/core/file_sys/fssrv/fssrv_sf_path.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/fs_directory.h" + +namespace FileSys::Sf { + +struct Path { +    char str[EntryNameLengthMax + 1]; + +    static constexpr Path Encode(const char* p) { +        Path path = {}; +        for (size_t i = 0; i < sizeof(path) - 1; i++) { +            path.str[i] = p[i]; +            if (p[i] == '\x00') { +                break; +            } +        } +        return path; +    } + +    static constexpr size_t GetPathLength(const Path& path) { +        size_t len = 0; +        for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) { +            len++; +        } +        return len; +    } +}; +static_assert(std::is_trivially_copyable_v<Path>, "Path must be trivially copyable."); + +using FspPath = Path; + +} // namespace FileSys::Sf diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp index 39690018b..8483394d0 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp @@ -3,82 +3,34 @@  #include "core/file_sys/fs_filesystem.h"  #include "core/file_sys/savedata_factory.h" +#include "core/hle/service/cmif_serialization.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_, +IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir directory_,                         FileSys::OpenDirectoryMode mode) -    : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { +    : ServiceFramework{system_, "IDirectory"}, +      backend(std::make_unique<FileSys::Fsa::IDirectory>(directory_, mode)) {      static const FunctionInfo functions[] = { -        {0, &IDirectory::Read, "Read"}, -        {1, &IDirectory::GetEntryCount, "GetEntryCount"}, +        {0, D<&IDirectory::Read>, "Read"}, +        {1, D<&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) { +Result IDirectory::Read( +    Out<s64> out_count, +    const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries) {      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); +    R_RETURN(backend->Read(out_count, out_entries.data(), out_entries.size()));  } -void IDirectory::GetEntryCount(HLERequestContext& ctx) { +Result IDirectory::GetEntryCount(Out<s64> out_count) {      LOG_DEBUG(Service_FS, "called"); -    u64 count = entries.size() - next_entry_index; - -    IPC::ResponseBuilder rb{ctx, 4}; -    rb.Push(ResultSuccess); -    rb.Push(count); +    R_RETURN(backend->GetEntryCount(out_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 index 793ecfcd7..b6251f7fd 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_directory.h +++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.h @@ -3,7 +3,9 @@  #pragma once +#include "core/file_sys/fsa/fs_i_directory.h"  #include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/cmif_types.h"  #include "core/hle/service/filesystem/filesystem.h"  #include "core/hle/service/service.h" @@ -15,16 +17,15 @@ namespace Service::FileSystem {  class IDirectory final : public ServiceFramework<IDirectory> {  public: -    explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, +    explicit IDirectory(Core::System& system_, FileSys::VirtualDir directory_,                          FileSys::OpenDirectoryMode mode);  private: -    FileSys::VirtualDir backend; -    std::vector<FileSys::DirectoryEntry> entries; -    u64 next_entry_index = 0; +    std::unique_ptr<FileSys::Fsa::IDirectory> backend; -    void Read(HLERequestContext& ctx); -    void GetEntryCount(HLERequestContext& ctx); +    Result Read(Out<s64> out_count, +                const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries); +    Result GetEntryCount(Out<s64> out_count);  };  } // 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 index 9a18f6ec5..a355d46ae 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp @@ -2,126 +2,64 @@  // SPDX-License-Identifier: GPL-2.0-or-later  #include "core/file_sys/errors.h" +#include "core/hle/service/cmif_serialization.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_)) { +IFile::IFile(Core::System& system_, FileSys::VirtualFile file_) +    : ServiceFramework{system_, "IFile"}, backend{std::make_unique<FileSys::Fsa::IFile>(file_)} { +    // clang-format off      static const FunctionInfo functions[] = { -        {0, &IFile::Read, "Read"}, -        {1, &IFile::Write, "Write"}, -        {2, &IFile::Flush, "Flush"}, -        {3, &IFile::SetSize, "SetSize"}, -        {4, &IFile::GetSize, "GetSize"}, +        {0, D<&IFile::Read>, "Read"}, +        {1, D<&IFile::Write>, "Write"}, +        {2, D<&IFile::Flush>, "Flush"}, +        {3, D<&IFile::SetSize>, "SetSize"}, +        {4, D<&IFile::GetSize>, "GetSize"},          {5, nullptr, "OperateRange"},          {6, nullptr, "OperateRangeWithBuffer"},      }; +    // clang-format on      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; -    } +Result IFile::Read( +    FileSys::ReadOption option, Out<s64> out_size, s64 offset, +    const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_buffer, +    s64 size) { +    LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset, +              size);      // 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())); +    R_RETURN( +        backend->Read(reinterpret_cast<size_t*>(out_size.Get()), offset, out_buffer.data(), 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(); +Result IFile::Write( +    const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer, +    FileSys::WriteOption option, s64 offset, s64 size) { +    LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset, +              size); -    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); +    R_RETURN(backend->Write(offset, buffer.data(), size, option));  } -void IFile::Flush(HLERequestContext& ctx) { +Result IFile::Flush() {      LOG_DEBUG(Service_FS, "called"); -    // Exists for SDK compatibiltity -- No need to flush file. - -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(ResultSuccess); +    R_RETURN(backend->Flush());  } -void IFile::SetSize(HLERequestContext& ctx) { -    IPC::RequestParser rp{ctx}; -    const u64 size = rp.Pop<u64>(); +Result IFile::SetSize(s64 size) {      LOG_DEBUG(Service_FS, "called, size={}", size); -    backend->Resize(size); - -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(ResultSuccess); +    R_RETURN(backend->SetSize(size));  } -void IFile::GetSize(HLERequestContext& ctx) { -    const u64 size = backend->GetSize(); -    LOG_DEBUG(Service_FS, "called, size={}", size); +Result IFile::GetSize(Out<s64> out_size) { +    LOG_DEBUG(Service_FS, "called"); -    IPC::ResponseBuilder rb{ctx, 4}; -    rb.Push(ResultSuccess); -    rb.Push<u64>(size); +    R_RETURN(backend->GetSize(out_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 index 5e5430c67..e8599ee2f 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_file.h +++ b/src/core/hle/service/filesystem/fsp/fs_i_file.h @@ -3,6 +3,8 @@  #pragma once +#include "core/file_sys/fsa/fs_i_file.h" +#include "core/hle/service/cmif_types.h"  #include "core/hle/service/filesystem/filesystem.h"  #include "core/hle/service/service.h" @@ -10,16 +12,21 @@ namespace Service::FileSystem {  class IFile final : public ServiceFramework<IFile> {  public: -    explicit IFile(Core::System& system_, FileSys::VirtualFile backend_); +    explicit IFile(Core::System& system_, FileSys::VirtualFile file_);  private: -    FileSys::VirtualFile backend; +    std::unique_ptr<FileSys::Fsa::IFile> backend; -    void Read(HLERequestContext& ctx); -    void Write(HLERequestContext& ctx); -    void Flush(HLERequestContext& ctx); -    void SetSize(HLERequestContext& ctx); -    void GetSize(HLERequestContext& ctx); +    Result Read(FileSys::ReadOption option, Out<s64> out_size, s64 offset, +                const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> +                    out_buffer, +                s64 size); +    Result Write( +        const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer, +        FileSys::WriteOption option, s64 offset, s64 size); +    Result Flush(); +    Result SetSize(s64 size); +    Result GetSize(Out<s64> out_size);  };  } // 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 index efa394dd1..d881e144d 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp @@ -2,261 +2,172 @@  // SPDX-License-Identifier: GPL-2.0-or-later  #include "common/string_util.h" +#include "core/file_sys/fssrv/fssrv_sf_path.h" +#include "core/hle/service/cmif_serialization.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_)} { +IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_) +    : ServiceFramework{system_, "IFileSystem"}, backend{std::make_unique<FileSys::Fsa::IFileSystem>( +                                                    dir_)}, +      size_getter{std::move(size_getter_)} {      static 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"}, +        {0, D<&IFileSystem::CreateFile>, "CreateFile"}, +        {1, D<&IFileSystem::DeleteFile>, "DeleteFile"}, +        {2, D<&IFileSystem::CreateDirectory>, "CreateDirectory"}, +        {3, D<&IFileSystem::DeleteDirectory>, "DeleteDirectory"}, +        {4, D<&IFileSystem::DeleteDirectoryRecursively>, "DeleteDirectoryRecursively"}, +        {5, D<&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"}, +        {7, D<&IFileSystem::GetEntryType>, "GetEntryType"}, +        {8, D<&IFileSystem::OpenFile>, "OpenFile"}, +        {9, D<&IFileSystem::OpenDirectory>, "OpenDirectory"}, +        {10, D<&IFileSystem::Commit>, "Commit"}, +        {11, D<&IFileSystem::GetFreeSpaceSize>, "GetFreeSpaceSize"}, +        {12, D<&IFileSystem::GetTotalSpaceSize>, "GetTotalSpaceSize"}, +        {13, D<&IFileSystem::CleanDirectoryRecursively>, "CleanDirectoryRecursively"}, +        {14, D<&IFileSystem::GetFileTimeStampRaw>, "GetFileTimeStampRaw"},          {15, nullptr, "QueryEntry"}, -        {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, +        {16, D<&IFileSystem::GetFileSystemAttribute>, "GetFileSystemAttribute"},      };      RegisterHandlers(functions);  } -void IFileSystem::CreateFile(HLERequestContext& ctx) { -    IPC::RequestParser rp{ctx}; +Result IFileSystem::CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, +                               s32 option, s64 size) { +    LOG_DEBUG(Service_FS, "called. file={}, option=0x{:X}, size=0x{:08X}", path->str, option, size); -    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)); +    R_RETURN(backend->CreateFile(FileSys::Path(path->str), size));  } -void IFileSystem::DeleteFile(HLERequestContext& ctx) { -    const auto file_buffer = ctx.ReadBuffer(); -    const std::string name = Common::StringFromBuffer(file_buffer); +Result IFileSystem::DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) { +    LOG_DEBUG(Service_FS, "called. file={}", path->str); -    LOG_DEBUG(Service_FS, "called. file={}", name); - -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(backend.DeleteFile(name)); +    R_RETURN(backend->DeleteFile(FileSys::Path(path->str)));  } -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); +Result IFileSystem::CreateDirectory( +    const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) { +    LOG_DEBUG(Service_FS, "called. directory={}", path->str); -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(backend.CreateDirectory(name)); +    R_RETURN(backend->CreateDirectory(FileSys::Path(path->str)));  } -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); +Result IFileSystem::DeleteDirectory( +    const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) { +    LOG_DEBUG(Service_FS, "called. directory={}", path->str); -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(backend.DeleteDirectory(name)); +    R_RETURN(backend->DeleteDirectory(FileSys::Path(path->str)));  } -void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) { -    const auto file_buffer = ctx.ReadBuffer(); -    const std::string name = Common::StringFromBuffer(file_buffer); +Result IFileSystem::DeleteDirectoryRecursively( +    const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) { +    LOG_DEBUG(Service_FS, "called. directory={}", path->str); -    LOG_DEBUG(Service_FS, "called. directory={}", name); - -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(backend.DeleteDirectoryRecursively(name)); +    R_RETURN(backend->DeleteDirectoryRecursively(FileSys::Path(path->str)));  } -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); +Result IFileSystem::CleanDirectoryRecursively( +    const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) { +    LOG_DEBUG(Service_FS, "called. Directory: {}", path->str); -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(backend.CleanDirectoryRecursively(name)); +    R_RETURN(backend->CleanDirectoryRecursively(FileSys::Path(path->str)));  } -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); +Result IFileSystem::RenameFile( +    const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path, +    const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path) { +    LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", old_path->str, new_path->str); -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(backend.RenameFile(src_name, dst_name)); +    R_RETURN(backend->RenameFile(FileSys::Path(old_path->str), FileSys::Path(new_path->str)));  } -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); +Result IFileSystem::OpenFile(OutInterface<IFile> out_interface, +                             const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, +                             u32 mode) { +    LOG_DEBUG(Service_FS, "called. file={}, mode={}", path->str, 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}; +    R_TRY(backend->OpenFile(&vfs_file, FileSys::Path(path->str), +                            static_cast<FileSys::OpenMode>(mode))); -    const auto file_buffer = ctx.ReadBuffer(); -    const std::string name = Common::StringFromBuffer(file_buffer); -    const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>(); +    *out_interface = std::make_shared<IFile>(system, vfs_file); +    R_SUCCEED(); +} -    LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); +Result IFileSystem::OpenDirectory(OutInterface<IDirectory> out_interface, +                                  const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, +                                  u32 mode) { +    LOG_DEBUG(Service_FS, "called. directory={}, mode={}", path->str, 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)); -} +    R_TRY(backend->OpenDirectory(&vfs_dir, FileSys::Path(path->str), +                                 static_cast<FileSys::OpenDirectoryMode>(mode))); -void IFileSystem::GetEntryType(HLERequestContext& ctx) { -    const auto file_buffer = ctx.ReadBuffer(); -    const std::string name = Common::StringFromBuffer(file_buffer); +    *out_interface = std::make_shared<IDirectory>(system, vfs_dir, +                                                  static_cast<FileSys::OpenDirectoryMode>(mode)); +    R_SUCCEED(); +} -    LOG_DEBUG(Service_FS, "called. file={}", name); +Result IFileSystem::GetEntryType( +    Out<u32> out_type, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) { +    LOG_DEBUG(Service_FS, "called. file={}", path->str);      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)); +    R_TRY(backend->GetEntryType(&vfs_entry_type, FileSys::Path(path->str))); + +    *out_type = static_cast<u32>(vfs_entry_type); +    R_SUCCEED();  } -void IFileSystem::Commit(HLERequestContext& ctx) { +Result IFileSystem::Commit() {      LOG_WARNING(Service_FS, "(STUBBED) called"); -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(ResultSuccess); +    R_SUCCEED();  } -void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) { +Result IFileSystem::GetFreeSpaceSize( +    Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {      LOG_DEBUG(Service_FS, "called"); -    IPC::ResponseBuilder rb{ctx, 4}; -    rb.Push(ResultSuccess); -    rb.Push(size.get_free_size()); +    *out_size = size_getter.get_free_size(); +    R_SUCCEED();  } -void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) { +Result IFileSystem::GetTotalSpaceSize( +    Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {      LOG_DEBUG(Service_FS, "called"); -    IPC::ResponseBuilder rb{ctx, 4}; -    rb.Push(ResultSuccess); -    rb.Push(size.get_total_size()); +    *out_size = size_getter.get_total_size(); +    R_SUCCEED();  } -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); +Result IFileSystem::GetFileTimeStampRaw( +    Out<FileSys::FileTimeStampRaw> out_timestamp, +    const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) { +    LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", path->str);      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); +    R_TRY(backend->GetFileTimeStampRaw(&vfs_timestamp, FileSys::Path(path->str))); + +    *out_timestamp = vfs_timestamp; +    R_SUCCEED();  } -void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) { +Result IFileSystem::GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute) {      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{}; +    FileSys::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); +    *out_attribute = savedata_attribute; +    R_SUCCEED();  }  } // 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 index b06b3ef0e..113369203 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h +++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h @@ -3,36 +3,58 @@  #pragma once +#include "common/common_funcs.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/fsa/fs_i_filesystem.h"  #include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/cmif_types.h"  #include "core/hle/service/filesystem/filesystem.h"  #include "core/hle/service/filesystem/fsp/fsp_util.h"  #include "core/hle/service/service.h" +namespace FileSys::Sf { +struct Path; +} +  namespace Service::FileSystem { +class IFile; +class IDirectory; +  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); +    explicit IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_); + +    Result CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, s32 option, +                      s64 size); +    Result DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path); +    Result CreateDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path); +    Result DeleteDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path); +    Result DeleteDirectoryRecursively( +        const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path); +    Result CleanDirectoryRecursively( +        const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path); +    Result RenameFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path, +                      const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path); +    Result OpenFile(OutInterface<IFile> out_interface, +                    const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, u32 mode); +    Result OpenDirectory(OutInterface<IDirectory> out_interface, +                         const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, +                         u32 mode); +    Result GetEntryType(Out<u32> out_type, +                        const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path); +    Result Commit(); +    Result GetFreeSpaceSize(Out<s64> out_size, +                            const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path); +    Result GetTotalSpaceSize(Out<s64> out_size, +                             const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path); +    Result GetFileTimeStampRaw(Out<FileSys::FileTimeStampRaw> out_timestamp, +                               const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path); +    Result GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute);  private: -    VfsDirectoryServiceWrapper backend; -    SizeGetter size; +    std::unique_ptr<FileSys::Fsa::IFileSystem> backend; +    SizeGetter size_getter;  };  } // namespace Service::FileSystem  | 
