diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.cpp new file mode 100644 index 000000000..5401329d9 --- /dev/null +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include "fs_results.hpp" +#include "fs_dir_utils.hpp" +#include "fs_ifile.hpp" + +Result FsDirUtils::CopyFile(IFileSystem *dst_fs, IFileSystem *src_fs, const FsPath &dst_parent_path, const FsPath &src_path, const FsDirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) { + Result rc; + std::unique_ptr src_file; + std::unique_ptr dst_file; + const u64 file_size = dir_ent->fileSize; + + /* Open source file for reading. */ + if (R_FAILED((rc = src_fs->OpenFile(src_file, src_path, OpenMode_Read)))) { + return rc; + } + + /* Create and open destination file. */ + { + FsPath dst_path; + if (static_cast(snprintf(dst_path.str, sizeof(dst_path.str), "%s%s", dst_parent_path.str, src_path.str)) >= sizeof(dst_path)) { + /* TODO: Error code? N aborts here. */ + std::abort(); + } + + if (R_FAILED((rc = dst_fs->CreateFile(dst_path, file_size)))) { + return rc; + } + if (R_FAILED((rc = dst_fs->OpenFile(dst_file, dst_path, OpenMode_Write)))) { + return rc; + } + } + + /* Read/Write work_buf_size chunks. */ + u64 offset = 0; + while (offset < file_size) { + u64 read_size; + if (R_FAILED((rc = src_file->Read(&read_size, offset, work_buf, work_buf_size)))) { + return rc; + } + if (R_FAILED((rc = dst_file->Write(offset, work_buf, read_size)))) { + return rc; + } + + offset += read_size; + } + + return 0; +} + +Result FsDirUtils::CopyDirectoryRecursively(IFileSystem *dst_fs, IFileSystem *src_fs, const FsPath &dst_path, const FsPath &src_path, void *work_buf, size_t work_buf_size) { + FsPath work_path = dst_path; + + return IterateDirectoryRecursively(src_fs, src_path, + [&](const FsPath &path, const FsDirectoryEntry *dir_ent) -> Result { /* On Enter Directory */ + /* Update path, create new dir. */ + strncat(work_path.str, dir_ent->name, sizeof(work_path) - strnlen(work_path.str, sizeof(work_path) - 1) - 1); + strncat(work_path.str, "/", sizeof(work_path) - strnlen(work_path.str, sizeof(work_path) - 1) - 1); + return dst_fs->CreateDirectory(work_path); + }, + [&](const FsPath &path, const FsDirectoryEntry *dir_ent) -> Result { /* On Exit Directory */ + /* Check we have a parent directory. */ + const size_t work_path_len = strnlen(work_path.str, sizeof(work_path)); + if (work_path_len < 2) { + return ResultFsInvalidPathFormat; + } + + /* Find previous separator, add NULL terminator */ + char *p = &work_path.str[work_path_len - 2]; + while (*p != '/' && p > work_path.str) { + p--; + } + p[1] = 0; + + return 0; + }, + [&](const FsPath &path, const FsDirectoryEntry *dir_ent) -> Result { /* On File */ + /* Just copy the file to the new fs. */ + return CopyFile(dst_fs, src_fs, work_path, path, dir_ent, work_buf, work_buf_size); + }); +} \ No newline at end of file diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.hpp b/stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.hpp new file mode 100644 index 000000000..76ce21be7 --- /dev/null +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.hpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +#include "fs_path_utils.hpp" +#include "fs_ifilesystem.hpp" + +class FsDirUtils { + private: + template + static Result IterateDirectoryRecursivelyInternal(IFileSystem *fs, FsPath &work_path, FsDirectoryEntry *ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { + Result rc; + std::unique_ptr dir; + + /* Open the directory. */ + if (R_FAILED((rc = fs->OpenDirectory(dir, work_path, DirectoryOpenMode_All)))) { + return rc; + } + + const size_t parent_len = strnlen(work_path.str, sizeof(work_path.str - 1)); + + /* Read and handle entries. */ + while (true) { + /* Read a single entry. */ + u64 read_count; + if (R_FAILED((rc = dir->Read(&read_count, ent_buf, 1)))) { + return rc; + } + + /* If we're out of entries, we're done. */ + if (read_count == 0) { + break; + } + + const size_t child_name_len = strnlen(ent_buf->name, sizeof(ent_buf->name) - 1); + const bool is_dir = ent_buf->type == ENTRYTYPE_DIR; + const size_t child_path_len = parent_len + child_name_len + (is_dir ? 1 : 0); + + /* Validate child path size. */ + if (child_path_len >= sizeof(work_path.str)) { + return ResultFsTooLongPath; + } + + strncat(work_path.str, ent_buf->name, sizeof(work_path.str) - 1 - parent_len); + if (is_dir) { + /* Enter directory. */ + if (R_FAILED((rc = on_enter_dir(work_path, ent_buf)))) { + return rc; + } + + /* Append separator, recurse. */ + strncat(work_path.str, "/", sizeof(work_path.str) - 1 - parent_len - child_name_len); + if (R_FAILED((rc = IterateDirectoryRecursivelyInternal(fs, work_path, ent_buf, on_enter_dir, on_exit_dir, on_file)))) { + return rc; + } + + /* Exit directory. */ + if (R_FAILED((rc = on_exit_dir(work_path, ent_buf)))) { + return rc; + } + } else { + /* Call file handler. */ + if (R_FAILED((rc = on_file(work_path, ent_buf)))) { + return rc; + } + } + + /* Restore parent path. */ + work_path.str[parent_len] = 0; + } + + return 0; + } + + public: + template + static Result IterateDirectoryRecursively(IFileSystem *fs, const FsPath &root_path, FsPath &work_path, FsDirectoryEntry *ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { + /* Ensure valid root path. */ + size_t root_path_len = strnlen(root_path.str, sizeof(root_path.str)); + if (root_path_len > FS_MAX_PATH - 1 || ((root_path_len == FS_MAX_PATH - 1) && root_path.str[root_path_len-1] != '/')) { + return ResultFsTooLongPath; + } + + /* Copy path, ensure terminating separator. */ + memcpy(work_path.str, root_path.str, root_path_len); + if (work_path.str[root_path_len-1] != '/') { + root_path_len++; + work_path.str[root_path_len-1] = '/'; + } + work_path.str[root_path_len] = 0; + + /* Actually iterate. */ + return IterateDirectoryRecursivelyInternal(fs, work_path, ent_buf, on_enter_dir, on_exit_dir, on_file); + } + + /* Helper for not specifying work path/entry buffer. */ + template + static Result IterateDirectoryRecursively(IFileSystem *fs, const FsPath &root_path, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { + FsDirectoryEntry dir_ent = {0}; + FsPath work_path = {0}; + return IterateDirectoryRecursively(fs, root_path, work_path, &dir_ent, on_enter_dir, on_exit_dir, on_file); + } + + /* Helper for iterating over the filesystem root. */ + template + static Result IterateDirectoryRecursively(IFileSystem *fs, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { + return IterateDirectoryRecursively(fs, FsPathUtils::RootPath, on_enter_dir, on_exit_dir, on_file); + } + + /* Copy API. */ + static Result CopyFile(IFileSystem *dst_fs, IFileSystem *src_fs, const FsPath &dst_parent_path, const FsPath &src_path, const FsDirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size); + static Result CopyFile(IFileSystem *fs, const FsPath &dst_parent_path, const FsPath &src_path, const FsDirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) { + return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, work_buf_size); + } + + static Result CopyDirectoryRecursively(IFileSystem *dst_fs, IFileSystem *src_fs, const FsPath &dst_path, const FsPath &src_path, void *work_buf, size_t work_buf_size); + static Result CopyDirectoryRecursively(IFileSystem *fs, const FsPath &dst_path, const FsPath &src_path, void *work_buf, size_t work_buf_size) { + return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size); + } + + /* Other Utility. */ + template + static Result RetryUntilTargetNotLocked(F f) { + const size_t MaxRetries = 10; + Result rc = 0; + + for (size_t i = 0; i < MaxRetries; i++) { + rc = f(); + + if (rc != ResultFsTargetLocked) { + break; + } + + /* If target is locked, wait 100ms and try again. */ + svcSleepThread(100'000'000ul); + } + + return rc; + } +}; diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_directory_savedata_filesystem.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_directory_savedata_filesystem.cpp new file mode 100644 index 000000000..62e46f700 --- /dev/null +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_directory_savedata_filesystem.cpp @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "../utils.hpp" +#include "fs_directory_savedata_filesystem.hpp" +#include "fs_dir_utils.hpp" + +class DirectorySaveDataFile : public IFile { + private: + std::unique_ptr base_file; + DirectorySaveDataFileSystem *parent_fs; /* TODO: shared_ptr + enabled_shared_from_this? */ + int open_mode; + public: + DirectorySaveDataFile(std::unique_ptr f, DirectorySaveDataFileSystem *p, int m) : base_file(std::move(f)), parent_fs(p), open_mode(m) { + /* ... */ + } + + virtual ~DirectorySaveDataFile() { + /* Observe closing of writable file. */ + if (this->open_mode & OpenMode_Write) { + this->parent_fs->OnWritableFileClose(); + } + } + public: + virtual Result ReadImpl(u64 *out, u64 offset, void *buffer, u64 size) override { + return this->base_file->Read(out, offset, buffer, size); + } + virtual Result GetSizeImpl(u64 *out) override { + return this->base_file->GetSize(out); + } + virtual Result FlushImpl() override { + return this->base_file->Flush(); + } + virtual Result WriteImpl(u64 offset, void *buffer, u64 size, bool flush) override { + return this->base_file->Write(offset, buffer, size, flush); + } + virtual Result SetSizeImpl(u64 size) override { + return this->base_file->SetSize(size); + } + virtual Result OperateRangeImpl(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override { + return this->base_file->OperateRange(operation_type, offset, size, out_range_info); + } +}; + +/* ================================================================================================ */ + +Result DirectorySaveDataFileSystem::Initialize() { + Result rc; + DirectoryEntryType ent_type; + + /* Check that the working directory exists. */ + if (R_FAILED((rc = this->fs->GetEntryType(&ent_type, WorkingDirectoryPath)))) { + /* If path isn't found, create working directory and committed directory. */ + if (rc == ResultFsPathNotFound) { + if (R_FAILED((rc = this->fs->CreateDirectory(WorkingDirectoryPath)))) { + return rc; + } + if (R_FAILED((rc = this->fs->CreateDirectory(CommittedDirectoryPath)))) { + return rc; + } + } else { + return rc; + } + } + + /* Now check for the committed directory. */ + rc = this->fs->GetEntryType(&ent_type, CommittedDirectoryPath); + if (R_SUCCEEDED(rc)) { + /* If committed exists, synchronize it to the working directory. */ + return this->SynchronizeDirectory(WorkingDirectoryPath, CommittedDirectoryPath); + } else if (rc == ResultFsPathNotFound) { + if (R_FAILED((rc = this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath)))) { + return rc; + } + return this->fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath); + } else { + return rc; + } +} + +Result DirectorySaveDataFileSystem::SynchronizeDirectory(const FsPath &dst_dir, const FsPath &src_dir) { + Result rc; + + /* Delete destination dir and recreate it. */ + if (R_FAILED((rc = this->fs->DeleteDirectoryRecursively(dst_dir)))) { + /* Nintendo returns error unconditionally, but I think that's a bug in their code. */ + if (rc != ResultFsPathNotFound) { + return rc; + } + } + if (R_FAILED((rc = this->fs->CreateDirectory(dst_dir)))) { + return rc; + } + + /* Get a buffer to work with. */ + void *work_buf = nullptr; + size_t work_buf_size = 0; + if (R_FAILED((rc = this->AllocateWorkBuffer(&work_buf, &work_buf_size, IdealWorkBuffersize)))) { + return rc; + } + ON_SCOPE_EXIT { free(work_buf); }; + + return FsDirUtils::CopyDirectoryRecursively(this->fs, dst_dir, src_dir, work_buf, work_buf_size); +} + +Result DirectorySaveDataFileSystem::AllocateWorkBuffer(void **out_buf, size_t *out_size, const size_t ideal_size) { + size_t try_size = ideal_size; + + /* Repeatedly try to allocate until success. */ + while (try_size > 0x200) { + void *buf = malloc(try_size); + if (buf != nullptr) { + *out_buf = buf; + *out_size = try_size; + return 0; + } + + /* Divide size by two. */ + try_size >>= 1; + } + + /* TODO: Return a result here? Nintendo does not, but they have other allocation failed results. */ + /* Consider returning ResultFsAllocationFailureInDirectorySaveDataFileSystem? */ + std::abort(); +} + +Result DirectorySaveDataFileSystem::GetFullPath(char *out, size_t out_size, const char *relative_path) { + /* Validate path. */ + if (1 + strnlen(relative_path, FS_MAX_PATH) >= out_size) { + return ResultFsTooLongPath; + } + if (relative_path[0] != '/') { + return ResultFsInvalidPath; + } + + /* Copy working directory path. */ + std::strncpy(out, WorkingDirectoryPath.str, out_size); + out[out_size-1] = 0; + + /* Normalize it. */ + constexpr size_t working_len = WorkingDirectoryPathLen - 1; + return FsPathUtils::Normalize(out + working_len, out_size - working_len, relative_path, nullptr); +} + +void DirectorySaveDataFileSystem::OnWritableFileClose() { + std::scoped_lock lk(this->lock); + this->open_writable_files--; + + /* TODO: Abort if < 0? N does not. */ +} + +/* ================================================================================================ */ + +Result DirectorySaveDataFileSystem::CreateFileImpl(const FsPath &path, uint64_t size, int flags) { + Result rc; + FsPath full_path; + + if (R_FAILED((rc = GetFullPath(full_path, path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + return this->fs->CreateFile(full_path, size, flags); +} + +Result DirectorySaveDataFileSystem::DeleteFileImpl(const FsPath &path) { + Result rc; + FsPath full_path; + + if (R_FAILED((rc = GetFullPath(full_path, path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + return this->fs->DeleteFile(full_path); +} + +Result DirectorySaveDataFileSystem::CreateDirectoryImpl(const FsPath &path) { + Result rc; + FsPath full_path; + + if (R_FAILED((rc = GetFullPath(full_path, path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + return this->fs->CreateDirectory(full_path); +} + +Result DirectorySaveDataFileSystem::DeleteDirectoryImpl(const FsPath &path) { + Result rc; + FsPath full_path; + + if (R_FAILED((rc = GetFullPath(full_path, path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + return this->fs->DeleteDirectory(full_path); +} + +Result DirectorySaveDataFileSystem::DeleteDirectoryRecursivelyImpl(const FsPath &path) { + Result rc; + FsPath full_path; + + if (R_FAILED((rc = GetFullPath(full_path, path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + return this->fs->DeleteDirectoryRecursively(full_path); +} + +Result DirectorySaveDataFileSystem::RenameFileImpl(const FsPath &old_path, const FsPath &new_path) { + Result rc; + FsPath full_old_path, full_new_path; + + if (R_FAILED((rc = GetFullPath(full_old_path, old_path)))) { + return rc; + } + + if (R_FAILED((rc = GetFullPath(full_new_path, new_path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + return this->fs->RenameFile(full_old_path, full_new_path); +} + +Result DirectorySaveDataFileSystem::RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) { + Result rc; + FsPath full_old_path, full_new_path; + + if (R_FAILED((rc = GetFullPath(full_old_path, old_path)))) { + return rc; + } + + if (R_FAILED((rc = GetFullPath(full_new_path, new_path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + return this->fs->RenameDirectory(full_old_path, full_new_path); +} + +Result DirectorySaveDataFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) { + Result rc; + FsPath full_path; + + if (R_FAILED((rc = GetFullPath(full_path, path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + return this->fs->GetEntryType(out, full_path); +} + +Result DirectorySaveDataFileSystem::OpenFileImpl(std::unique_ptr &out_file, const FsPath &path, OpenMode mode) { + Result rc; + FsPath full_path; + + if (R_FAILED((rc = GetFullPath(full_path, path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + + { + /* Open the raw file. */ + std::unique_ptr file; + if (R_FAILED((rc = this->fs->OpenFile(file, full_path, mode)))) { + return rc; + } + + /* Create DirectorySaveDataFile wrapper. */ + out_file = std::make_unique(std::move(file), this, mode); + } + + /* Check for allocation failure. */ + if (out_file == nullptr) { + return ResultFsAllocationFailureInDirectorySaveDataFileSystem; + } + + /* Increment open writable files, if needed. */ + if (mode & OpenMode_Write) { + this->open_writable_files++; + } + + return 0; +} + +Result DirectorySaveDataFileSystem::OpenDirectoryImpl(std::unique_ptr &out_dir, const FsPath &path, DirectoryOpenMode mode) { + Result rc; + FsPath full_path; + + if (R_FAILED((rc = GetFullPath(full_path, path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + return this->fs->OpenDirectory(out_dir, full_path, mode); +} + +Result DirectorySaveDataFileSystem::CommitImpl() { + /* Here, Nintendo does the following (with retries): */ + /* - Rename Committed -> Synchronizing. */ + /* - Synchronize Working -> Synchronizing (deleting Synchronizing). */ + /* - Rename Synchronizing -> Committed. */ + /* I think this is not the optimal order to do things, as the previous committed directory */ + /* will be deleted if there is an error during synchronization. */ + /* Instead, we will synchronize first, then delete committed, then rename. */ + + std::scoped_lock lk(this->lock); + Result rc; + + /* Ensure we don't have any open writable files. */ + if (this->open_writable_files != 0) { + return ResultFsPreconditionViolation; + } + + const auto SynchronizeWorkingDir = [&]() { return this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath); }; + const auto DeleteCommittedDir = [&]() { return this->fs->DeleteDirectoryRecursively(CommittedDirectoryPath); }; + const auto RenameSynchDir = [&]() { return this->fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath); }; + + /* Synchronize working directory. */ + if (R_FAILED((rc = FsDirUtils::RetryUntilTargetNotLocked(std::move(SynchronizeWorkingDir))))) { + return rc; + } + + /* Delete committed directory. */ + if (R_FAILED((rc = FsDirUtils::RetryUntilTargetNotLocked(std::move(DeleteCommittedDir))))) { + /* It is okay for us to not have a committed directory here. */ + if (rc != ResultFsPathNotFound) { + return rc; + } + } + + /* Rename synchronizing directory to committed directory. */ + if (R_FAILED((rc = FsDirUtils::RetryUntilTargetNotLocked(std::move(RenameSynchDir))))) { + return rc; + } + + /* TODO: Should I call this->fs->Commit()? Nintendo does not. */ + return rc; +} + +Result DirectorySaveDataFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) { + /* TODO: How should this work? N returns ResultFsNotImplemented. */ + return ResultFsNotImplemented; +} + +Result DirectorySaveDataFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) { + /* TODO: How should this work? N returns ResultFsNotImplemented. */ + return ResultFsNotImplemented; +} + +Result DirectorySaveDataFileSystem::CleanDirectoryRecursivelyImpl(const FsPath &path) { + Result rc; + FsPath full_path; + + if (R_FAILED((rc = GetFullPath(full_path, path)))) { + return rc; + } + + std::scoped_lock lk(this->lock); + return this->fs->CleanDirectoryRecursively(full_path); +} + +Result DirectorySaveDataFileSystem::GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) { + /* TODO: How should this work? N returns ResultFsNotImplemented. */ + return ResultFsNotImplemented; +} + +Result DirectorySaveDataFileSystem::QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) { + /* TODO: How should this work? N returns ResultFsNotImplemented. */ + return ResultFsNotImplemented; +} \ No newline at end of file diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_directory_savedata_filesystem.hpp b/stratosphere/ams_mitm/source/fs_mitm/fs_directory_savedata_filesystem.hpp new file mode 100644 index 000000000..e40521faa --- /dev/null +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_directory_savedata_filesystem.hpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +#include "fs_ifilesystem.hpp" +#include "fs_path_utils.hpp" + +class DirectorySaveDataFileSystem : public IFileSystem { + private: + static constexpr FsPath CommittedDirectoryPath = EncodeConstantFsPath("/0/"); + static constexpr FsPath WorkingDirectoryPath = EncodeConstantFsPath("/1/"); + static constexpr FsPath SynchronizingDirectoryPath = EncodeConstantFsPath("/_/"); + + static constexpr size_t CommittedDirectoryPathLen = GetConstantFsPathLen(CommittedDirectoryPath); + static constexpr size_t WorkingDirectoryPathLen = GetConstantFsPathLen(WorkingDirectoryPath); + static constexpr size_t SynchronizingDirectoryPathLen = GetConstantFsPathLen(SynchronizingDirectoryPath); + + static constexpr size_t IdealWorkBuffersize = 0x100000; /* 1 MB */ + private: + std::shared_ptr shared_fs; + std::unique_ptr unique_fs; + IFileSystem *fs; + HosMutex lock; + size_t open_writable_files = 0; + + public: + DirectorySaveDataFileSystem(IFileSystem *fs) : unique_fs(fs) { + this->fs = this->unique_fs.get(); + Result rc = this->Initialize(); + if (R_FAILED(rc)) { + fatalSimple(rc); + } + } + + DirectorySaveDataFileSystem(std::unique_ptr fs) : unique_fs(std::move(fs)) { + this->fs = this->unique_fs.get(); + Result rc = this->Initialize(); + if (R_FAILED(rc)) { + fatalSimple(rc); + } + } + + DirectorySaveDataFileSystem(std::shared_ptr fs) : shared_fs(fs) { + this->fs = this->shared_fs.get(); + Result rc = this->Initialize(); + if (R_FAILED(rc)) { + fatalSimple(rc); + } + } + + + virtual ~DirectorySaveDataFileSystem() { } + + private: + Result Initialize(); + protected: + Result SynchronizeDirectory(const FsPath &dst_dir, const FsPath &src_dir); + Result AllocateWorkBuffer(void **out_buf, size_t *out_size, const size_t ideal_size); + + Result GetFullPath(char *out, size_t out_size, const char *relative_path); + Result GetFullPath(FsPath &full_path, const FsPath &relative_path) { + return GetFullPath(full_path.str, sizeof(full_path.str), relative_path.str); + } + public: + void OnWritableFileClose(); + public: + virtual Result CreateFileImpl(const FsPath &path, uint64_t size, int flags) override; + virtual Result DeleteFileImpl(const FsPath &path) override; + virtual Result CreateDirectoryImpl(const FsPath &path) override; + virtual Result DeleteDirectoryImpl(const FsPath &path) override; + virtual Result DeleteDirectoryRecursivelyImpl(const FsPath &path) override; + virtual Result RenameFileImpl(const FsPath &old_path, const FsPath &new_path) override; + virtual Result RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) override; + virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) override; + virtual Result OpenFileImpl(std::unique_ptr &out_file, const FsPath &path, OpenMode mode) override; + virtual Result OpenDirectoryImpl(std::unique_ptr &out_dir, const FsPath &path, DirectoryOpenMode mode) override; + virtual Result CommitImpl() override; + virtual Result GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) override; + virtual Result GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) override; + virtual Result CleanDirectoryRecursivelyImpl(const FsPath &path) override; + virtual Result GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) override; + virtual Result QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) override; +}; \ No newline at end of file diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_ifile.hpp b/stratosphere/ams_mitm/source/fs_mitm/fs_ifile.hpp index 8da0e5838..9f7cb17d2 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_ifile.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_ifile.hpp @@ -49,6 +49,10 @@ class IFile { return ReadImpl(out, offset, buffer, size); } + Result Read(uint64_t *out, uint64_t offset, void *buffer, uint64_t size) { + return Read(out, offset, buffer, size, 0); + } + Result GetSize(uint64_t *out) { if (out == nullptr) { return ResultFsNullptrArgument; @@ -71,8 +75,14 @@ class IFile { return WriteImpl(offset, buffer, size, flush); } - Result Write(uint64_t offset, void *buffer, uint64_t size) { - return WriteImpl(offset, buffer, size, false); + Result Write(uint64_t offset, void *buffer, uint64_t size, bool flush = false) { + if (size == 0) { + return 0; + } + if (buffer == nullptr) { + return ResultFsNullptrArgument; + } + return WriteImpl(offset, buffer, size, flush); } Result SetSize(uint64_t size) { @@ -162,7 +172,7 @@ class ProxyFile : public IFile { fsFileClose(this->base_file.get()); } public: - virtual Result ReadImpl(u64 *out, u64 offset, void *buffer, u64 size) { + virtual Result ReadImpl(u64 *out, u64 offset, void *buffer, u64 size) override { size_t out_sz; Result rc = fsFileRead(this->base_file.get(), offset, buffer, size, &out_sz); @@ -172,13 +182,13 @@ class ProxyFile : public IFile { return rc; } - virtual Result GetSizeImpl(u64 *out) { + virtual Result GetSizeImpl(u64 *out) override { return fsFileGetSize(this->base_file.get(), out); } - virtual Result FlushImpl() { + virtual Result FlushImpl() override { return fsFileFlush(this->base_file.get()); } - virtual Result WriteImpl(u64 offset, void *buffer, u64 size, bool flush) { + virtual Result WriteImpl(u64 offset, void *buffer, u64 size, bool flush) override { Result rc = fsFileWrite(this->base_file.get(), offset, buffer, size); if (R_SUCCEEDED(rc)) { /* libnx doesn't allow passing the flush flag. */ @@ -186,10 +196,10 @@ class ProxyFile : public IFile { } return rc; } - virtual Result SetSizeImpl(u64 size) { + virtual Result SetSizeImpl(u64 size) override { return fsFileSetSize(this->base_file.get(), size); } - virtual Result OperateRangeImpl(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) { + virtual Result OperateRangeImpl(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override { return fsFileOperateRange(this->base_file.get(), operation_type, offset, size, out_range_info); } }; diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_ifilesystem.hpp b/stratosphere/ams_mitm/source/fs_mitm/fs_ifilesystem.hpp index 2b3fda4c0..4e176302a 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_ifilesystem.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_ifilesystem.hpp @@ -58,42 +58,46 @@ class IFileSystem { public: virtual ~IFileSystem() {} - Result CreateFile(FsPath &path, uint64_t size, int flags) { + Result CreateFile(const FsPath &path, uint64_t size, int flags) { return CreateFileImpl(path, size, flags); } - Result DeleteFile(FsPath &path) { + Result CreateFile(const FsPath &path, uint64_t size) { + return CreateFileImpl(path, size, 0); + } + + Result DeleteFile(const FsPath &path) { return DeleteFileImpl(path); } - Result CreateDirectory(FsPath &path) { + Result CreateDirectory(const FsPath &path) { return CreateDirectoryImpl(path); } - Result DeleteDirectory(FsPath &path) { + Result DeleteDirectory(const FsPath &path) { return DeleteDirectoryImpl(path); } - Result DeleteDirectoryRecursively(FsPath &path) { + Result DeleteDirectoryRecursively(const FsPath &path) { return DeleteDirectoryRecursivelyImpl(path); } - Result RenameFile(FsPath &old_path, FsPath &new_path) { + Result RenameFile(const FsPath &old_path, const FsPath &new_path) { return RenameFileImpl(old_path, new_path); } - Result RenameDirectory(FsPath &old_path, FsPath &new_path) { + Result RenameDirectory(const FsPath &old_path, const FsPath &new_path) { return RenameDirectoryImpl(old_path, new_path); } - Result GetEntryType(DirectoryEntryType *out, FsPath &path) { + Result GetEntryType(DirectoryEntryType *out, const FsPath &path) { if (out == nullptr) { return ResultFsNullptrArgument; } return GetEntryTypeImpl(out, path); } - Result OpenFile(std::unique_ptr &out_file, FsPath &path, OpenMode mode) { + Result OpenFile(std::unique_ptr &out_file, const FsPath &path, OpenMode mode) { if (!(mode & OpenMode_ReadWrite)) { return ResultFsInvalidArgument; } @@ -103,7 +107,7 @@ class IFileSystem { return OpenFileImpl(out_file, path, mode); } - Result OpenDirectory(std::unique_ptr &out_dir, FsPath &path, DirectoryOpenMode mode) { + Result OpenDirectory(std::unique_ptr &out_dir, const FsPath &path, DirectoryOpenMode mode) { if (!(mode & DirectoryOpenMode_All)) { return ResultFsInvalidArgument; } @@ -117,32 +121,32 @@ class IFileSystem { return CommitImpl(); } - Result GetFreeSpaceSize(uint64_t *out, FsPath &path) { + Result GetFreeSpaceSize(uint64_t *out, const FsPath &path) { if (out == nullptr) { return ResultFsNullptrArgument; } return GetFreeSpaceSizeImpl(out, path); } - Result GetTotalSpaceSize(uint64_t *out, FsPath &path) { + Result GetTotalSpaceSize(uint64_t *out, const FsPath &path) { if (out == nullptr) { return ResultFsNullptrArgument; } return GetTotalSpaceSizeImpl(out, path); } - Result CleanDirectoryRecursively(FsPath &path) { + Result CleanDirectoryRecursively(const FsPath &path) { return CleanDirectoryRecursivelyImpl(path); } - Result GetFileTimeStampRaw(FsTimeStampRaw *out, FsPath &path) { + Result GetFileTimeStampRaw(FsTimeStampRaw *out, const FsPath &path) { if (out == nullptr) { return ResultFsNullptrArgument; } return GetFileTimeStampRawImpl(out, path); } - Result QueryEntry(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, FsPath &path) { + Result QueryEntry(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) { return QueryEntryImpl(out, out_size, in, in_size, query, path); } @@ -150,39 +154,39 @@ class IFileSystem { protected: /* ...? */ private: - virtual Result CreateFileImpl(FsPath &path, uint64_t size, int flags) = 0; - virtual Result DeleteFileImpl(FsPath &path) = 0; - virtual Result CreateDirectoryImpl(FsPath &path) = 0; - virtual Result DeleteDirectoryImpl(FsPath &path) = 0; - virtual Result DeleteDirectoryRecursivelyImpl(FsPath &path) = 0; - virtual Result RenameFileImpl(FsPath &old_path, FsPath &new_path) = 0; - virtual Result RenameDirectoryImpl(FsPath &old_path, FsPath &new_path) = 0; - virtual Result GetEntryTypeImpl(DirectoryEntryType *out, FsPath &path) = 0; - virtual Result OpenFileImpl(std::unique_ptr &out_file, FsPath &path, OpenMode mode) = 0; - virtual Result OpenDirectoryImpl(std::unique_ptr &out_dir, FsPath &path, DirectoryOpenMode mode) = 0; + virtual Result CreateFileImpl(const FsPath &path, uint64_t size, int flags) = 0; + virtual Result DeleteFileImpl(const FsPath &path) = 0; + virtual Result CreateDirectoryImpl(const FsPath &path) = 0; + virtual Result DeleteDirectoryImpl(const FsPath &path) = 0; + virtual Result DeleteDirectoryRecursivelyImpl(const FsPath &path) = 0; + virtual Result RenameFileImpl(const FsPath &old_path, const FsPath &new_path) = 0; + virtual Result RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) = 0; + virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) = 0; + virtual Result OpenFileImpl(std::unique_ptr &out_file, const FsPath &path, OpenMode mode) = 0; + virtual Result OpenDirectoryImpl(std::unique_ptr &out_dir, const FsPath &path, DirectoryOpenMode mode) = 0; virtual Result CommitImpl() = 0; - virtual Result GetFreeSpaceSizeImpl(uint64_t *out, FsPath &path) { + virtual Result GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) { (void)(out); (void)(path); return ResultFsNotImplemented; } - virtual Result GetTotalSpaceSizeImpl(uint64_t *out, FsPath &path) { + virtual Result GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) { (void)(out); (void)(path); return ResultFsNotImplemented; } - virtual Result CleanDirectoryRecursivelyImpl(FsPath &path) = 0; + virtual Result CleanDirectoryRecursivelyImpl(const FsPath &path) = 0; - virtual Result GetFileTimeStampRawImpl(FsTimeStampRaw *out, FsPath &path) { + virtual Result GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) { (void)(out); (void)(path); return ResultFsNotImplemented; } - virtual Result QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, FsPath &path) { + virtual Result QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) { (void)(out); (void)(out_size); (void)(in); @@ -449,35 +453,35 @@ class ProxyFileSystem : public IFileSystem { } public: - virtual Result CreateFileImpl(FsPath &path, uint64_t size, int flags) { + virtual Result CreateFileImpl(const FsPath &path, uint64_t size, int flags) { return fsFsCreateFile(this->base_fs.get(), path.str, size, flags); } - virtual Result DeleteFileImpl(FsPath &path) { + virtual Result DeleteFileImpl(const FsPath &path) { return fsFsDeleteFile(this->base_fs.get(), path.str); } - virtual Result CreateDirectoryImpl(FsPath &path) { + virtual Result CreateDirectoryImpl(const FsPath &path) { return fsFsCreateDirectory(this->base_fs.get(), path.str); } - virtual Result DeleteDirectoryImpl(FsPath &path) { + virtual Result DeleteDirectoryImpl(const FsPath &path) { return fsFsDeleteDirectory(this->base_fs.get(), path.str); } - virtual Result DeleteDirectoryRecursivelyImpl(FsPath &path) { + virtual Result DeleteDirectoryRecursivelyImpl(const FsPath &path) { return fsFsDeleteDirectoryRecursively(this->base_fs.get(), path.str); } - virtual Result RenameFileImpl(FsPath &old_path, FsPath &new_path) { + virtual Result RenameFileImpl(const FsPath &old_path, const FsPath &new_path) { return fsFsRenameFile(this->base_fs.get(), old_path.str, new_path.str); } - virtual Result RenameDirectoryImpl(FsPath &old_path, FsPath &new_path) { + virtual Result RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) { return fsFsRenameDirectory(this->base_fs.get(), old_path.str, new_path.str); } - virtual Result GetEntryTypeImpl(DirectoryEntryType *out, FsPath &path) { + virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) { FsEntryType type; Result rc = fsFsGetEntryType(this->base_fs.get(), path.str, &type); @@ -487,7 +491,7 @@ class ProxyFileSystem : public IFileSystem { return rc; } - virtual Result OpenFileImpl(std::unique_ptr &out_file, FsPath &path, OpenMode mode) { + virtual Result OpenFileImpl(std::unique_ptr &out_file, const FsPath &path, OpenMode mode) { FsFile f; Result rc = fsFsOpenFile(this->base_fs.get(), path.str, static_cast(mode), &f); @@ -498,7 +502,7 @@ class ProxyFileSystem : public IFileSystem { return rc; } - virtual Result OpenDirectoryImpl(std::unique_ptr &out_dir, FsPath &path, DirectoryOpenMode mode) { + virtual Result OpenDirectoryImpl(std::unique_ptr &out_dir, const FsPath &path, DirectoryOpenMode mode) { FsDir d; Result rc = fsFsOpenDirectory(this->base_fs.get(), path.str, static_cast(mode), &d); @@ -513,23 +517,23 @@ class ProxyFileSystem : public IFileSystem { return fsFsCommit(this->base_fs.get()); } - virtual Result GetFreeSpaceSizeImpl(uint64_t *out, FsPath &path) { + virtual Result GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) { return fsFsGetFreeSpace(this->base_fs.get(), path.str, out); } - virtual Result GetTotalSpaceSizeImpl(uint64_t *out, FsPath &path) { + virtual Result GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) { return fsFsGetTotalSpace(this->base_fs.get(), path.str, out); } - virtual Result CleanDirectoryRecursivelyImpl(FsPath &path) { + virtual Result CleanDirectoryRecursivelyImpl(const FsPath &path) { return fsFsCleanDirectoryRecursively(this->base_fs.get(), path.str); } - virtual Result GetFileTimeStampRawImpl(FsTimeStampRaw *out, FsPath &path) { + virtual Result GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) { return fsFsGetFileTimeStampRaw(this->base_fs.get(), path.str, out); } - virtual Result QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, FsPath &path) { + virtual Result QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) { return fsFsQueryEntry(this->base_fs.get(), out, out_size, in, in_size, path.str,static_cast(query)); } }; \ No newline at end of file diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_path_utils.hpp b/stratosphere/ams_mitm/source/fs_mitm/fs_path_utils.hpp index 142fd25b7..b4ad49863 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_path_utils.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_path_utils.hpp @@ -21,7 +21,31 @@ struct FsPath { char str[FS_MAX_PATH]; }; +constexpr FsPath EncodeConstantFsPath(const char *p) { + FsPath path = {0}; + for (size_t i = 0; i < sizeof(path) - 1; i++) { + path.str[i] = p[i]; + if (p[i] == 0) { + break; + } + } + return path; +} + +constexpr size_t GetConstantFsPathLen(FsPath path) { + size_t len = 0; + for (size_t i = 0; i < sizeof(path) - 1; i++) { + if (path.str[i] == 0) { + break; + } + len++; + } + return len; +} + class FsPathUtils { + public: + static constexpr FsPath RootPath = EncodeConstantFsPath("/"); public: static Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len); static Result ConvertPathForServiceObject(FsPath *out, const char *path); diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_results.hpp b/stratosphere/ams_mitm/source/fs_mitm/fs_results.hpp index 9dd12dd60..3bcf5d50a 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_results.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_results.hpp @@ -19,11 +19,19 @@ static constexpr u32 Module_Fs = 2; +static constexpr Result ResultFsPathNotFound = MAKERESULT(Module_Fs, 1); +static constexpr Result ResultFsPathAlreadyExists = MAKERESULT(Module_Fs, 2); + +static constexpr Result ResultFsTargetLocked = MAKERESULT(Module_Fs, 7); +static constexpr Result ResultFsDirectoryNotEmpty = MAKERESULT(Module_Fs, 8); + static constexpr Result ResultFsNotImplemented = MAKERESULT(Module_Fs, 3001); static constexpr Result ResultFsOutOfRange = MAKERESULT(Module_Fs, 3005); -static constexpr Result ResultFsAllocationFailureInSubDirectoryFileSystem = MAKERESULT(Module_Fs, 3355); +static constexpr Result ResultFsAllocationFailureInDirectorySaveDataFileSystem = MAKERESULT(Module_Fs, 3321); +static constexpr Result ResultFsAllocationFailureInSubDirectoryFileSystem = MAKERESULT(Module_Fs, 3355); +static constexpr Result ResultFsPreconditionViolation = MAKERESULT(Module_Fs, 6000); static constexpr Result ResultFsInvalidArgument = MAKERESULT(Module_Fs, 6001); static constexpr Result ResultFsInvalidPath = MAKERESULT(Module_Fs, 6002); static constexpr Result ResultFsTooLongPath = MAKERESULT(Module_Fs, 6003); diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.cpp index 6d14c418a..88622e814 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.cpp @@ -71,7 +71,7 @@ Result SubDirectoryFileSystem::GetFullPath(char *out, size_t out_size, const cha return FsPathUtils::Normalize(out + this->base_path_len - 2, out_size - (this->base_path_len - 2), relative_path, nullptr); } -Result SubDirectoryFileSystem::CreateFileImpl(FsPath &path, uint64_t size, int flags) { +Result SubDirectoryFileSystem::CreateFileImpl(const FsPath &path, uint64_t size, int flags) { Result rc; FsPath full_path; @@ -82,7 +82,7 @@ Result SubDirectoryFileSystem::CreateFileImpl(FsPath &path, uint64_t size, int f return this->base_fs->CreateFile(full_path, size, flags); } -Result SubDirectoryFileSystem::DeleteFileImpl(FsPath &path) { +Result SubDirectoryFileSystem::DeleteFileImpl(const FsPath &path) { Result rc; FsPath full_path; @@ -93,7 +93,7 @@ Result SubDirectoryFileSystem::DeleteFileImpl(FsPath &path) { return this->base_fs->DeleteFile(full_path); } -Result SubDirectoryFileSystem::CreateDirectoryImpl(FsPath &path) { +Result SubDirectoryFileSystem::CreateDirectoryImpl(const FsPath &path) { Result rc; FsPath full_path; @@ -104,7 +104,7 @@ Result SubDirectoryFileSystem::CreateDirectoryImpl(FsPath &path) { return this->base_fs->CreateDirectory(full_path); } -Result SubDirectoryFileSystem::DeleteDirectoryImpl(FsPath &path) { +Result SubDirectoryFileSystem::DeleteDirectoryImpl(const FsPath &path) { Result rc; FsPath full_path; @@ -115,7 +115,7 @@ Result SubDirectoryFileSystem::DeleteDirectoryImpl(FsPath &path) { return this->base_fs->DeleteDirectory(full_path); } -Result SubDirectoryFileSystem::DeleteDirectoryRecursivelyImpl(FsPath &path) { +Result SubDirectoryFileSystem::DeleteDirectoryRecursivelyImpl(const FsPath &path) { Result rc; FsPath full_path; @@ -126,7 +126,7 @@ Result SubDirectoryFileSystem::DeleteDirectoryRecursivelyImpl(FsPath &path) { return this->base_fs->DeleteDirectoryRecursively(full_path); } -Result SubDirectoryFileSystem::RenameFileImpl(FsPath &old_path, FsPath &new_path) { +Result SubDirectoryFileSystem::RenameFileImpl(const FsPath &old_path, const FsPath &new_path) { Result rc; FsPath full_old_path, full_new_path; @@ -141,7 +141,7 @@ Result SubDirectoryFileSystem::RenameFileImpl(FsPath &old_path, FsPath &new_path return this->base_fs->RenameFile(full_old_path, full_new_path); } -Result SubDirectoryFileSystem::RenameDirectoryImpl(FsPath &old_path, FsPath &new_path) { +Result SubDirectoryFileSystem::RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) { Result rc; FsPath full_old_path, full_new_path; @@ -156,7 +156,7 @@ Result SubDirectoryFileSystem::RenameDirectoryImpl(FsPath &old_path, FsPath &new return this->base_fs->RenameDirectory(full_old_path, full_new_path); } -Result SubDirectoryFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, FsPath &path) { +Result SubDirectoryFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) { Result rc; FsPath full_path; @@ -167,7 +167,7 @@ Result SubDirectoryFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, FsPath return this->base_fs->GetEntryType(out, full_path); } -Result SubDirectoryFileSystem::OpenFileImpl(std::unique_ptr &out_file, FsPath &path, OpenMode mode) { +Result SubDirectoryFileSystem::OpenFileImpl(std::unique_ptr &out_file, const FsPath &path, OpenMode mode) { Result rc; FsPath full_path; @@ -178,7 +178,7 @@ Result SubDirectoryFileSystem::OpenFileImpl(std::unique_ptr &out_file, Fs return this->base_fs->OpenFile(out_file, full_path, mode); } -Result SubDirectoryFileSystem::OpenDirectoryImpl(std::unique_ptr &out_dir, FsPath &path, DirectoryOpenMode mode) { +Result SubDirectoryFileSystem::OpenDirectoryImpl(std::unique_ptr &out_dir, const FsPath &path, DirectoryOpenMode mode) { Result rc; FsPath full_path; @@ -193,7 +193,7 @@ Result SubDirectoryFileSystem::CommitImpl() { return this->base_fs->Commit(); } -Result SubDirectoryFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, FsPath &path) { +Result SubDirectoryFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) { Result rc; FsPath full_path; @@ -204,7 +204,7 @@ Result SubDirectoryFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, FsPath &path) return this->base_fs->GetFreeSpaceSize(out, full_path); } -Result SubDirectoryFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, FsPath &path) { +Result SubDirectoryFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) { Result rc; FsPath full_path; @@ -215,7 +215,7 @@ Result SubDirectoryFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, FsPath &path return this->base_fs->GetTotalSpaceSize(out, full_path); } -Result SubDirectoryFileSystem::CleanDirectoryRecursivelyImpl(FsPath &path) { +Result SubDirectoryFileSystem::CleanDirectoryRecursivelyImpl(const FsPath &path) { Result rc; FsPath full_path; @@ -226,7 +226,7 @@ Result SubDirectoryFileSystem::CleanDirectoryRecursivelyImpl(FsPath &path) { return this->base_fs->CleanDirectoryRecursively(full_path); } -Result SubDirectoryFileSystem::GetFileTimeStampRawImpl(FsTimeStampRaw *out, FsPath &path) { +Result SubDirectoryFileSystem::GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) { Result rc; FsPath full_path; @@ -237,7 +237,7 @@ Result SubDirectoryFileSystem::GetFileTimeStampRawImpl(FsTimeStampRaw *out, FsPa return this->base_fs->GetFileTimeStampRaw(out, full_path); } -Result SubDirectoryFileSystem::QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, FsPath &path) { +Result SubDirectoryFileSystem::QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) { Result rc; FsPath full_path; diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.hpp b/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.hpp index e6c406fa1..d1a28cef3 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_subdirectory_filesystem.hpp @@ -53,25 +53,25 @@ class SubDirectoryFileSystem : public IFileSystem { Result Initialize(const char *bp); protected: Result GetFullPath(char *out, size_t out_size, const char *relative_path); - Result GetFullPath(FsPath &full_path, FsPath &relative_path) { + Result GetFullPath(FsPath &full_path, const FsPath &relative_path) { return GetFullPath(full_path.str, sizeof(full_path.str), relative_path.str); } public: - virtual Result CreateFileImpl(FsPath &path, uint64_t size, int flags) override; - virtual Result DeleteFileImpl(FsPath &path) override; - virtual Result CreateDirectoryImpl(FsPath &path) override; - virtual Result DeleteDirectoryImpl(FsPath &path) override; - virtual Result DeleteDirectoryRecursivelyImpl(FsPath &path) override; - virtual Result RenameFileImpl(FsPath &old_path, FsPath &new_path) override; - virtual Result RenameDirectoryImpl(FsPath &old_path, FsPath &new_path) override; - virtual Result GetEntryTypeImpl(DirectoryEntryType *out, FsPath &path) override; - virtual Result OpenFileImpl(std::unique_ptr &out_file, FsPath &path, OpenMode mode) override; - virtual Result OpenDirectoryImpl(std::unique_ptr &out_dir, FsPath &path, DirectoryOpenMode mode) override; + virtual Result CreateFileImpl(const FsPath &path, uint64_t size, int flags) override; + virtual Result DeleteFileImpl(const FsPath &path) override; + virtual Result CreateDirectoryImpl(const FsPath &path) override; + virtual Result DeleteDirectoryImpl(const FsPath &path) override; + virtual Result DeleteDirectoryRecursivelyImpl(const FsPath &path) override; + virtual Result RenameFileImpl(const FsPath &old_path, const FsPath &new_path) override; + virtual Result RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) override; + virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) override; + virtual Result OpenFileImpl(std::unique_ptr &out_file, const FsPath &path, OpenMode mode) override; + virtual Result OpenDirectoryImpl(std::unique_ptr &out_dir, const FsPath &path, DirectoryOpenMode mode) override; virtual Result CommitImpl() override; - virtual Result GetFreeSpaceSizeImpl(uint64_t *out, FsPath &path) override; - virtual Result GetTotalSpaceSizeImpl(uint64_t *out, FsPath &path) override; - virtual Result CleanDirectoryRecursivelyImpl(FsPath &path) override; - virtual Result GetFileTimeStampRawImpl(FsTimeStampRaw *out, FsPath &path) override; - virtual Result QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, FsPath &path) override; + virtual Result GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) override; + virtual Result GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) override; + virtual Result CleanDirectoryRecursivelyImpl(const FsPath &path) override; + virtual Result GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) override; + virtual Result QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) override; }; \ No newline at end of file diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_service.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_service.cpp index 33f6eda10..9541f2d4e 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_service.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_service.cpp @@ -29,6 +29,7 @@ #include "fsmitm_layeredrom.hpp" #include "fs_subdirectory_filesystem.hpp" +#include "fs_directory_savedata_filesystem.hpp" #include "../debug.hpp"