mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2025-01-03 11:11:14 +00:00
fs.mitm: Implement DirectorySaveDataFileSystem.
This commit is contained in:
parent
994d7d5429
commit
d00b183f92
11 changed files with 877 additions and 85 deletions
97
stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.cpp
Normal file
97
stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.cpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <switch.h>
|
||||||
|
#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<IFile> src_file;
|
||||||
|
std::unique_ptr<IFile> 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<size_t>(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);
|
||||||
|
});
|
||||||
|
}
|
155
stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.hpp
Normal file
155
stratosphere/ams_mitm/source/fs_mitm/fs_dir_utils.hpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
#include "fs_path_utils.hpp"
|
||||||
|
#include "fs_ifilesystem.hpp"
|
||||||
|
|
||||||
|
class FsDirUtils {
|
||||||
|
private:
|
||||||
|
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
|
||||||
|
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<IDirectory> 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<typename OnEnterDir, typename OnExitDir, typename OnFile>
|
||||||
|
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<typename OnEnterDir, typename OnExitDir, typename OnFile>
|
||||||
|
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<typename OnEnterDir, typename OnExitDir, typename OnFile>
|
||||||
|
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<typename F>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "../utils.hpp"
|
||||||
|
#include "fs_directory_savedata_filesystem.hpp"
|
||||||
|
#include "fs_dir_utils.hpp"
|
||||||
|
|
||||||
|
class DirectorySaveDataFile : public IFile {
|
||||||
|
private:
|
||||||
|
std::unique_ptr<IFile> base_file;
|
||||||
|
DirectorySaveDataFileSystem *parent_fs; /* TODO: shared_ptr + enabled_shared_from_this? */
|
||||||
|
int open_mode;
|
||||||
|
public:
|
||||||
|
DirectorySaveDataFile(std::unique_ptr<IFile> 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<HosMutex> 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<HosMutex> 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<HosMutex> 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<HosMutex> 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<HosMutex> 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<HosMutex> 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<HosMutex> 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<HosMutex> 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<HosMutex> lk(this->lock);
|
||||||
|
return this->fs->GetEntryType(out, full_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DirectorySaveDataFileSystem::OpenFileImpl(std::unique_ptr<IFile> &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<HosMutex> lk(this->lock);
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Open the raw file. */
|
||||||
|
std::unique_ptr<IFile> file;
|
||||||
|
if (R_FAILED((rc = this->fs->OpenFile(file, full_path, mode)))) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create DirectorySaveDataFile wrapper. */
|
||||||
|
out_file = std::make_unique<DirectorySaveDataFile>(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<IDirectory> &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<HosMutex> 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<HosMutex> 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<HosMutex> 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;
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#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<IFileSystem> shared_fs;
|
||||||
|
std::unique_ptr<IFileSystem> 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<IFileSystem> 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<IFileSystem> 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<IFile> &out_file, const FsPath &path, OpenMode mode) override;
|
||||||
|
virtual Result OpenDirectoryImpl(std::unique_ptr<IDirectory> &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;
|
||||||
|
};
|
|
@ -49,6 +49,10 @@ class IFile {
|
||||||
return ReadImpl(out, offset, buffer, size);
|
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) {
|
Result GetSize(uint64_t *out) {
|
||||||
if (out == nullptr) {
|
if (out == nullptr) {
|
||||||
return ResultFsNullptrArgument;
|
return ResultFsNullptrArgument;
|
||||||
|
@ -71,8 +75,14 @@ class IFile {
|
||||||
return WriteImpl(offset, buffer, size, flush);
|
return WriteImpl(offset, buffer, size, flush);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Write(uint64_t offset, void *buffer, uint64_t size) {
|
Result Write(uint64_t offset, void *buffer, uint64_t size, bool flush = false) {
|
||||||
return WriteImpl(offset, buffer, size, false);
|
if (size == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (buffer == nullptr) {
|
||||||
|
return ResultFsNullptrArgument;
|
||||||
|
}
|
||||||
|
return WriteImpl(offset, buffer, size, flush);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetSize(uint64_t size) {
|
Result SetSize(uint64_t size) {
|
||||||
|
@ -162,7 +172,7 @@ class ProxyFile : public IFile {
|
||||||
fsFileClose(this->base_file.get());
|
fsFileClose(this->base_file.get());
|
||||||
}
|
}
|
||||||
public:
|
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;
|
size_t out_sz;
|
||||||
|
|
||||||
Result rc = fsFileRead(this->base_file.get(), offset, buffer, size, &out_sz);
|
Result rc = fsFileRead(this->base_file.get(), offset, buffer, size, &out_sz);
|
||||||
|
@ -172,13 +182,13 @@ class ProxyFile : public IFile {
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
virtual Result GetSizeImpl(u64 *out) {
|
virtual Result GetSizeImpl(u64 *out) override {
|
||||||
return fsFileGetSize(this->base_file.get(), out);
|
return fsFileGetSize(this->base_file.get(), out);
|
||||||
}
|
}
|
||||||
virtual Result FlushImpl() {
|
virtual Result FlushImpl() override {
|
||||||
return fsFileFlush(this->base_file.get());
|
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);
|
Result rc = fsFileWrite(this->base_file.get(), offset, buffer, size);
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
/* libnx doesn't allow passing the flush flag. */
|
/* libnx doesn't allow passing the flush flag. */
|
||||||
|
@ -186,10 +196,10 @@ class ProxyFile : public IFile {
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
virtual Result SetSizeImpl(u64 size) {
|
virtual Result SetSizeImpl(u64 size) override {
|
||||||
return fsFileSetSize(this->base_file.get(), size);
|
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);
|
return fsFileOperateRange(this->base_file.get(), operation_type, offset, size, out_range_info);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -58,42 +58,46 @@ class IFileSystem {
|
||||||
public:
|
public:
|
||||||
virtual ~IFileSystem() {}
|
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);
|
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);
|
return DeleteFileImpl(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CreateDirectory(FsPath &path) {
|
Result CreateDirectory(const FsPath &path) {
|
||||||
return CreateDirectoryImpl(path);
|
return CreateDirectoryImpl(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeleteDirectory(FsPath &path) {
|
Result DeleteDirectory(const FsPath &path) {
|
||||||
return DeleteDirectoryImpl(path);
|
return DeleteDirectoryImpl(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeleteDirectoryRecursively(FsPath &path) {
|
Result DeleteDirectoryRecursively(const FsPath &path) {
|
||||||
return DeleteDirectoryRecursivelyImpl(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);
|
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);
|
return RenameDirectoryImpl(old_path, new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetEntryType(DirectoryEntryType *out, FsPath &path) {
|
Result GetEntryType(DirectoryEntryType *out, const FsPath &path) {
|
||||||
if (out == nullptr) {
|
if (out == nullptr) {
|
||||||
return ResultFsNullptrArgument;
|
return ResultFsNullptrArgument;
|
||||||
}
|
}
|
||||||
return GetEntryTypeImpl(out, path);
|
return GetEntryTypeImpl(out, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpenFile(std::unique_ptr<IFile> &out_file, FsPath &path, OpenMode mode) {
|
Result OpenFile(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
||||||
if (!(mode & OpenMode_ReadWrite)) {
|
if (!(mode & OpenMode_ReadWrite)) {
|
||||||
return ResultFsInvalidArgument;
|
return ResultFsInvalidArgument;
|
||||||
}
|
}
|
||||||
|
@ -103,7 +107,7 @@ class IFileSystem {
|
||||||
return OpenFileImpl(out_file, path, mode);
|
return OpenFileImpl(out_file, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpenDirectory(std::unique_ptr<IDirectory> &out_dir, FsPath &path, DirectoryOpenMode mode) {
|
Result OpenDirectory(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
||||||
if (!(mode & DirectoryOpenMode_All)) {
|
if (!(mode & DirectoryOpenMode_All)) {
|
||||||
return ResultFsInvalidArgument;
|
return ResultFsInvalidArgument;
|
||||||
}
|
}
|
||||||
|
@ -117,32 +121,32 @@ class IFileSystem {
|
||||||
return CommitImpl();
|
return CommitImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetFreeSpaceSize(uint64_t *out, FsPath &path) {
|
Result GetFreeSpaceSize(uint64_t *out, const FsPath &path) {
|
||||||
if (out == nullptr) {
|
if (out == nullptr) {
|
||||||
return ResultFsNullptrArgument;
|
return ResultFsNullptrArgument;
|
||||||
}
|
}
|
||||||
return GetFreeSpaceSizeImpl(out, path);
|
return GetFreeSpaceSizeImpl(out, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetTotalSpaceSize(uint64_t *out, FsPath &path) {
|
Result GetTotalSpaceSize(uint64_t *out, const FsPath &path) {
|
||||||
if (out == nullptr) {
|
if (out == nullptr) {
|
||||||
return ResultFsNullptrArgument;
|
return ResultFsNullptrArgument;
|
||||||
}
|
}
|
||||||
return GetTotalSpaceSizeImpl(out, path);
|
return GetTotalSpaceSizeImpl(out, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CleanDirectoryRecursively(FsPath &path) {
|
Result CleanDirectoryRecursively(const FsPath &path) {
|
||||||
return CleanDirectoryRecursivelyImpl(path);
|
return CleanDirectoryRecursivelyImpl(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetFileTimeStampRaw(FsTimeStampRaw *out, FsPath &path) {
|
Result GetFileTimeStampRaw(FsTimeStampRaw *out, const FsPath &path) {
|
||||||
if (out == nullptr) {
|
if (out == nullptr) {
|
||||||
return ResultFsNullptrArgument;
|
return ResultFsNullptrArgument;
|
||||||
}
|
}
|
||||||
return GetFileTimeStampRawImpl(out, path);
|
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);
|
return QueryEntryImpl(out, out_size, in, in_size, query, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,39 +154,39 @@ class IFileSystem {
|
||||||
protected:
|
protected:
|
||||||
/* ...? */
|
/* ...? */
|
||||||
private:
|
private:
|
||||||
virtual Result CreateFileImpl(FsPath &path, uint64_t size, int flags) = 0;
|
virtual Result CreateFileImpl(const FsPath &path, uint64_t size, int flags) = 0;
|
||||||
virtual Result DeleteFileImpl(FsPath &path) = 0;
|
virtual Result DeleteFileImpl(const FsPath &path) = 0;
|
||||||
virtual Result CreateDirectoryImpl(FsPath &path) = 0;
|
virtual Result CreateDirectoryImpl(const FsPath &path) = 0;
|
||||||
virtual Result DeleteDirectoryImpl(FsPath &path) = 0;
|
virtual Result DeleteDirectoryImpl(const FsPath &path) = 0;
|
||||||
virtual Result DeleteDirectoryRecursivelyImpl(FsPath &path) = 0;
|
virtual Result DeleteDirectoryRecursivelyImpl(const FsPath &path) = 0;
|
||||||
virtual Result RenameFileImpl(FsPath &old_path, FsPath &new_path) = 0;
|
virtual Result RenameFileImpl(const FsPath &old_path, const FsPath &new_path) = 0;
|
||||||
virtual Result RenameDirectoryImpl(FsPath &old_path, FsPath &new_path) = 0;
|
virtual Result RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) = 0;
|
||||||
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, FsPath &path) = 0;
|
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) = 0;
|
||||||
virtual Result OpenFileImpl(std::unique_ptr<IFile> &out_file, FsPath &path, OpenMode mode) = 0;
|
virtual Result OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) = 0;
|
||||||
virtual Result OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, FsPath &path, DirectoryOpenMode mode) = 0;
|
virtual Result OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) = 0;
|
||||||
virtual Result CommitImpl() = 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)(out);
|
||||||
(void)(path);
|
(void)(path);
|
||||||
return ResultFsNotImplemented;
|
return ResultFsNotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result GetTotalSpaceSizeImpl(uint64_t *out, FsPath &path) {
|
virtual Result GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
||||||
(void)(out);
|
(void)(out);
|
||||||
(void)(path);
|
(void)(path);
|
||||||
return ResultFsNotImplemented;
|
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)(out);
|
||||||
(void)(path);
|
(void)(path);
|
||||||
return ResultFsNotImplemented;
|
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);
|
||||||
(void)(out_size);
|
(void)(out_size);
|
||||||
(void)(in);
|
(void)(in);
|
||||||
|
@ -449,35 +453,35 @@ class ProxyFileSystem : public IFileSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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;
|
FsEntryType type;
|
||||||
|
|
||||||
Result rc = fsFsGetEntryType(this->base_fs.get(), path.str, &type);
|
Result rc = fsFsGetEntryType(this->base_fs.get(), path.str, &type);
|
||||||
|
@ -487,7 +491,7 @@ class ProxyFileSystem : public IFileSystem {
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
virtual Result OpenFileImpl(std::unique_ptr<IFile> &out_file, FsPath &path, OpenMode mode) {
|
virtual Result OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
||||||
FsFile f;
|
FsFile f;
|
||||||
|
|
||||||
Result rc = fsFsOpenFile(this->base_fs.get(), path.str, static_cast<int>(mode), &f);
|
Result rc = fsFsOpenFile(this->base_fs.get(), path.str, static_cast<int>(mode), &f);
|
||||||
|
@ -498,7 +502,7 @@ class ProxyFileSystem : public IFileSystem {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, FsPath &path, DirectoryOpenMode mode) {
|
virtual Result OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
||||||
FsDir d;
|
FsDir d;
|
||||||
|
|
||||||
Result rc = fsFsOpenDirectory(this->base_fs.get(), path.str, static_cast<int>(mode), &d);
|
Result rc = fsFsOpenDirectory(this->base_fs.get(), path.str, static_cast<int>(mode), &d);
|
||||||
|
@ -513,23 +517,23 @@ class ProxyFileSystem : public IFileSystem {
|
||||||
return fsFsCommit(this->base_fs.get());
|
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);
|
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);
|
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);
|
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);
|
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<FsFileSystemQueryType>(query));
|
return fsFsQueryEntry(this->base_fs.get(), out, out_size, in, in_size, path.str,static_cast<FsFileSystemQueryType>(query));
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -21,7 +21,31 @@ struct FsPath {
|
||||||
char str[FS_MAX_PATH];
|
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 {
|
class FsPathUtils {
|
||||||
|
public:
|
||||||
|
static constexpr FsPath RootPath = EncodeConstantFsPath("/");
|
||||||
public:
|
public:
|
||||||
static Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len);
|
static Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len);
|
||||||
static Result ConvertPathForServiceObject(FsPath *out, const char *path);
|
static Result ConvertPathForServiceObject(FsPath *out, const char *path);
|
||||||
|
|
|
@ -19,11 +19,19 @@
|
||||||
|
|
||||||
static constexpr u32 Module_Fs = 2;
|
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 ResultFsNotImplemented = MAKERESULT(Module_Fs, 3001);
|
||||||
static constexpr Result ResultFsOutOfRange = MAKERESULT(Module_Fs, 3005);
|
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 ResultFsInvalidArgument = MAKERESULT(Module_Fs, 6001);
|
||||||
static constexpr Result ResultFsInvalidPath = MAKERESULT(Module_Fs, 6002);
|
static constexpr Result ResultFsInvalidPath = MAKERESULT(Module_Fs, 6002);
|
||||||
static constexpr Result ResultFsTooLongPath = MAKERESULT(Module_Fs, 6003);
|
static constexpr Result ResultFsTooLongPath = MAKERESULT(Module_Fs, 6003);
|
||||||
|
|
|
@ -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);
|
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;
|
Result rc;
|
||||||
FsPath full_path;
|
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);
|
return this->base_fs->CreateFile(full_path, size, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::DeleteFileImpl(FsPath &path) {
|
Result SubDirectoryFileSystem::DeleteFileImpl(const FsPath &path) {
|
||||||
Result rc;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ Result SubDirectoryFileSystem::DeleteFileImpl(FsPath &path) {
|
||||||
return this->base_fs->DeleteFile(full_path);
|
return this->base_fs->DeleteFile(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::CreateDirectoryImpl(FsPath &path) {
|
Result SubDirectoryFileSystem::CreateDirectoryImpl(const FsPath &path) {
|
||||||
Result rc;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ Result SubDirectoryFileSystem::CreateDirectoryImpl(FsPath &path) {
|
||||||
return this->base_fs->CreateDirectory(full_path);
|
return this->base_fs->CreateDirectory(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::DeleteDirectoryImpl(FsPath &path) {
|
Result SubDirectoryFileSystem::DeleteDirectoryImpl(const FsPath &path) {
|
||||||
Result rc;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ Result SubDirectoryFileSystem::DeleteDirectoryImpl(FsPath &path) {
|
||||||
return this->base_fs->DeleteDirectory(full_path);
|
return this->base_fs->DeleteDirectory(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::DeleteDirectoryRecursivelyImpl(FsPath &path) {
|
Result SubDirectoryFileSystem::DeleteDirectoryRecursivelyImpl(const FsPath &path) {
|
||||||
Result rc;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ Result SubDirectoryFileSystem::DeleteDirectoryRecursivelyImpl(FsPath &path) {
|
||||||
return this->base_fs->DeleteDirectoryRecursively(full_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;
|
Result rc;
|
||||||
FsPath full_old_path, full_new_path;
|
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);
|
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;
|
Result rc;
|
||||||
FsPath full_old_path, full_new_path;
|
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);
|
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;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ Result SubDirectoryFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, FsPath
|
||||||
return this->base_fs->GetEntryType(out, full_path);
|
return this->base_fs->GetEntryType(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_file, FsPath &path, OpenMode mode) {
|
Result SubDirectoryFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
||||||
Result rc;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ Result SubDirectoryFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_file, Fs
|
||||||
return this->base_fs->OpenFile(out_file, full_path, mode);
|
return this->base_fs->OpenFile(out_file, full_path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, FsPath &path, DirectoryOpenMode mode) {
|
Result SubDirectoryFileSystem::OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
||||||
Result rc;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ Result SubDirectoryFileSystem::CommitImpl() {
|
||||||
return this->base_fs->Commit();
|
return this->base_fs->Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, FsPath &path) {
|
Result SubDirectoryFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
||||||
Result rc;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ Result SubDirectoryFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, FsPath &path)
|
||||||
return this->base_fs->GetFreeSpaceSize(out, full_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;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ Result SubDirectoryFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, FsPath &path
|
||||||
return this->base_fs->GetTotalSpaceSize(out, full_path);
|
return this->base_fs->GetTotalSpaceSize(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::CleanDirectoryRecursivelyImpl(FsPath &path) {
|
Result SubDirectoryFileSystem::CleanDirectoryRecursivelyImpl(const FsPath &path) {
|
||||||
Result rc;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ Result SubDirectoryFileSystem::CleanDirectoryRecursivelyImpl(FsPath &path) {
|
||||||
return this->base_fs->CleanDirectoryRecursively(full_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;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ Result SubDirectoryFileSystem::GetFileTimeStampRawImpl(FsTimeStampRaw *out, FsPa
|
||||||
return this->base_fs->GetFileTimeStampRaw(out, full_path);
|
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;
|
Result rc;
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
|
||||||
|
|
|
@ -53,25 +53,25 @@ class SubDirectoryFileSystem : public IFileSystem {
|
||||||
Result Initialize(const char *bp);
|
Result Initialize(const char *bp);
|
||||||
protected:
|
protected:
|
||||||
Result GetFullPath(char *out, size_t out_size, const char *relative_path);
|
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);
|
return GetFullPath(full_path.str, sizeof(full_path.str), relative_path.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual Result CreateFileImpl(FsPath &path, uint64_t size, int flags) override;
|
virtual Result CreateFileImpl(const FsPath &path, uint64_t size, int flags) override;
|
||||||
virtual Result DeleteFileImpl(FsPath &path) override;
|
virtual Result DeleteFileImpl(const FsPath &path) override;
|
||||||
virtual Result CreateDirectoryImpl(FsPath &path) override;
|
virtual Result CreateDirectoryImpl(const FsPath &path) override;
|
||||||
virtual Result DeleteDirectoryImpl(FsPath &path) override;
|
virtual Result DeleteDirectoryImpl(const FsPath &path) override;
|
||||||
virtual Result DeleteDirectoryRecursivelyImpl(FsPath &path) override;
|
virtual Result DeleteDirectoryRecursivelyImpl(const FsPath &path) override;
|
||||||
virtual Result RenameFileImpl(FsPath &old_path, FsPath &new_path) override;
|
virtual Result RenameFileImpl(const FsPath &old_path, const FsPath &new_path) override;
|
||||||
virtual Result RenameDirectoryImpl(FsPath &old_path, FsPath &new_path) override;
|
virtual Result RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) override;
|
||||||
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, FsPath &path) override;
|
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) override;
|
||||||
virtual Result OpenFileImpl(std::unique_ptr<IFile> &out_file, FsPath &path, OpenMode mode) override;
|
virtual Result OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) override;
|
||||||
virtual Result OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, FsPath &path, DirectoryOpenMode mode) override;
|
virtual Result OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) override;
|
||||||
virtual Result CommitImpl() override;
|
virtual Result CommitImpl() override;
|
||||||
virtual Result GetFreeSpaceSizeImpl(uint64_t *out, FsPath &path) override;
|
virtual Result GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) override;
|
||||||
virtual Result GetTotalSpaceSizeImpl(uint64_t *out, FsPath &path) override;
|
virtual Result GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) override;
|
||||||
virtual Result CleanDirectoryRecursivelyImpl(FsPath &path) override;
|
virtual Result CleanDirectoryRecursivelyImpl(const FsPath &path) override;
|
||||||
virtual Result GetFileTimeStampRawImpl(FsTimeStampRaw *out, 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, 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;
|
||||||
};
|
};
|
|
@ -29,6 +29,7 @@
|
||||||
#include "fsmitm_layeredrom.hpp"
|
#include "fsmitm_layeredrom.hpp"
|
||||||
|
|
||||||
#include "fs_subdirectory_filesystem.hpp"
|
#include "fs_subdirectory_filesystem.hpp"
|
||||||
|
#include "fs_directory_savedata_filesystem.hpp"
|
||||||
|
|
||||||
#include "../debug.hpp"
|
#include "../debug.hpp"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue