/* * Copyright (c) 2018-2019 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 "../utils.hpp" #include "fs_filesystem_types.hpp" #include "fs_path_utils.hpp" #include "fs_ifile.hpp" #include "fs_idirectory.hpp" enum FsIFileSystemCmd : u32 { /* 1.0.0+ */ FsIFileSystemCmd_CreateFile = 0, FsIFileSystemCmd_DeleteFile = 1, FsIFileSystemCmd_CreateDirectory = 2, FsIFileSystemCmd_DeleteDirectory = 3, FsIFileSystemCmd_DeleteDirectoryRecursively = 4, FsIFileSystemCmd_RenameFile = 5, FsIFileSystemCmd_RenameDirectory = 6, FsIFileSystemCmd_GetEntryType = 7, FsIFileSystemCmd_OpenFile = 8, FsIFileSystemCmd_OpenDirectory = 9, FsIFileSystemCmd_Commit = 10, FsIFileSystemCmd_GetFreeSpaceSize = 11, FsIFileSystemCmd_GetTotalSpaceSize = 12, /* 3.0.0+ */ FsIFileSystemCmd_CleanDirectoryRecursively = 13, FsIFileSystemCmd_GetFileTimeStampRaw = 14, /* 4.0.0+ */ FsIFileSystemCmd_QueryEntry = 15, }; class IFile; class IDirectory; class IFileSystem { public: virtual ~IFileSystem() {} Result CreateFile(const FsPath &path, uint64_t size, int flags) { return CreateFileImpl(path, size, flags); } Result CreateFile(const FsPath &path, uint64_t size) { return CreateFileImpl(path, size, 0); } Result DeleteFile(const FsPath &path) { return DeleteFileImpl(path); } Result CreateDirectory(const FsPath &path) { return CreateDirectoryImpl(path); } Result DeleteDirectory(const FsPath &path) { return DeleteDirectoryImpl(path); } Result DeleteDirectoryRecursively(const FsPath &path) { return DeleteDirectoryRecursivelyImpl(path); } Result RenameFile(const FsPath &old_path, const FsPath &new_path) { return RenameFileImpl(old_path, new_path); } Result RenameDirectory(const FsPath &old_path, const FsPath &new_path) { return RenameDirectoryImpl(old_path, new_path); } Result GetEntryType(DirectoryEntryType *out, const FsPath &path) { if (out == nullptr) { return ResultFsNullptrArgument; } return GetEntryTypeImpl(out, path); } Result OpenFile(std::unique_ptr &out_file, const FsPath &path, OpenMode mode) { if (!(mode & OpenMode_ReadWrite)) { return ResultFsInvalidArgument; } if (mode & ~OpenMode_All) { return ResultFsInvalidArgument; } return OpenFileImpl(out_file, path, mode); } Result OpenDirectory(std::unique_ptr &out_dir, const FsPath &path, DirectoryOpenMode mode) { if (!(mode & DirectoryOpenMode_All)) { return ResultFsInvalidArgument; } if (mode & ~DirectoryOpenMode_All) { return ResultFsInvalidArgument; } return OpenDirectoryImpl(out_dir, path, mode); } Result Commit() { return CommitImpl(); } Result GetFreeSpaceSize(uint64_t *out, const FsPath &path) { if (out == nullptr) { return ResultFsNullptrArgument; } return GetFreeSpaceSizeImpl(out, path); } Result GetTotalSpaceSize(uint64_t *out, const FsPath &path) { if (out == nullptr) { return ResultFsNullptrArgument; } return GetTotalSpaceSizeImpl(out, path); } Result CleanDirectoryRecursively(const FsPath &path) { return CleanDirectoryRecursivelyImpl(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, const FsPath &path) { return QueryEntryImpl(out, out_size, in, in_size, query, path); } protected: /* ...? */ private: 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, const FsPath &path) { (void)(out); (void)(path); return ResultFsNotImplemented; } virtual Result GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) { (void)(out); (void)(path); return ResultFsNotImplemented; } virtual Result CleanDirectoryRecursivelyImpl(const FsPath &path) = 0; 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, const FsPath &path) { (void)(out); (void)(out_size); (void)(in); (void)(in_size); (void)(query); (void)(path); return ResultFsNotImplemented; } }; class IFileSystemInterface : public IServiceObject { private: std::unique_ptr unique_fs; std::shared_ptr shared_fs; IFileSystem *base_fs; public: IFileSystemInterface(IFileSystem *fs) : unique_fs(fs) { this->base_fs = this->unique_fs.get(); }; IFileSystemInterface(std::unique_ptr fs) : unique_fs(std::move(fs)) { this->base_fs = this->unique_fs.get(); }; IFileSystemInterface(std::shared_ptr fs) : shared_fs(fs) { this->base_fs = this->shared_fs.get(); }; private: /* Actual command API. */ virtual Result CreateFile(InPointer in_path, uint64_t size, int flags) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); return this->base_fs->CreateFile(path, size, flags); } virtual Result DeleteFile(InPointer in_path) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); return this->base_fs->DeleteFile(path); } virtual Result CreateDirectory(InPointer in_path) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); return this->base_fs->CreateDirectory(path); } virtual Result DeleteDirectory(InPointer in_path) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); return this->base_fs->DeleteDirectory(path); } virtual Result DeleteDirectoryRecursively(InPointer in_path) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); return this->base_fs->DeleteDirectoryRecursively(path); } virtual Result RenameFile(InPointer in_old_path, InPointer in_new_path) final { FsPath old_path; FsPath new_path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&old_path, in_old_path.pointer)); R_TRY(FsPathUtils::ConvertPathForServiceObject(&new_path, in_new_path.pointer)); return this->base_fs->RenameFile(old_path, new_path); } virtual Result RenameDirectory(InPointer in_old_path, InPointer in_new_path) final { FsPath old_path; FsPath new_path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&old_path, in_old_path.pointer)); R_TRY(FsPathUtils::ConvertPathForServiceObject(&new_path, in_new_path.pointer)); return this->base_fs->RenameDirectory(old_path, new_path); } virtual Result GetEntryType(Out out_type, InPointer in_path) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); DirectoryEntryType type; R_TRY(this->base_fs->GetEntryType(&type, path)); out_type.SetValue(type); return ResultSuccess; } virtual Result OpenFile(Out> out_intf, InPointer in_path, uint32_t mode) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); std::unique_ptr out_file; R_TRY(this->base_fs->OpenFile(out_file, path, static_cast(mode))); out_intf.SetValue(std::make_shared(std::move(out_file))); return ResultSuccess; } virtual Result OpenDirectory(Out> out_intf, InPointer in_path, uint32_t mode) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); std::unique_ptr out_dir; R_TRY(this->base_fs->OpenDirectory(out_dir, path, static_cast(mode))); out_intf.SetValue(std::make_shared(std::move(out_dir))); return ResultSuccess; } virtual Result Commit() final { return this->base_fs->Commit(); } virtual Result GetFreeSpaceSize(Out out_size, InPointer in_path) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); return this->base_fs->GetFreeSpaceSize(out_size.GetPointer(), path); } virtual Result GetTotalSpaceSize(Out out_size, InPointer in_path) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); return this->base_fs->GetTotalSpaceSize(out_size.GetPointer(), path); } virtual Result CleanDirectoryRecursively(InPointer in_path) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); return this->base_fs->CleanDirectoryRecursively(path); } virtual Result GetFileTimeStampRaw(Out out_timestamp, InPointer in_path) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); return this->base_fs->GetFileTimeStampRaw(out_timestamp.GetPointer(), path); } virtual Result QueryEntry(OutBuffer out_buffer, InBuffer in_buffer, int query, InPointer in_path) final { FsPath path; R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)); return this->base_fs->QueryEntry(out_buffer.buffer, out_buffer.num_elements, in_buffer.buffer, in_buffer.num_elements, query, path); } public: DEFINE_SERVICE_DISPATCH_TABLE { /* 1.0.0- */ MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), MakeServiceCommandMeta(), /* 3.0.0- */ MakeServiceCommandMeta(), MakeServiceCommandMeta(), /* 4.0.0- */ MakeServiceCommandMeta(), }; }; class ProxyFileSystem : public IFileSystem { private: std::unique_ptr base_fs; public: ProxyFileSystem(FsFileSystem *fs) : base_fs(fs) { /* ... */ } ProxyFileSystem(std::unique_ptr fs) : base_fs(std::move(fs)) { /* ... */ } ProxyFileSystem(FsFileSystem fs) { this->base_fs = std::make_unique(fs); } virtual ~ProxyFileSystem() { fsFsClose(this->base_fs.get()); } public: virtual Result CreateFileImpl(const FsPath &path, uint64_t size, int flags) { return fsFsCreateFile(this->base_fs.get(), path.str, size, flags); } virtual Result DeleteFileImpl(const FsPath &path) { return fsFsDeleteFile(this->base_fs.get(), path.str); } virtual Result CreateDirectoryImpl(const FsPath &path) { return fsFsCreateDirectory(this->base_fs.get(), path.str); } virtual Result DeleteDirectoryImpl(const FsPath &path) { return fsFsDeleteDirectory(this->base_fs.get(), path.str); } virtual Result DeleteDirectoryRecursivelyImpl(const FsPath &path) { return fsFsDeleteDirectoryRecursively(this->base_fs.get(), path.str); } 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(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, const FsPath &path) { FsEntryType type; R_TRY(fsFsGetEntryType(this->base_fs.get(), path.str, &type)); *out = static_cast(static_cast(type)); return ResultSuccess; } virtual Result OpenFileImpl(std::unique_ptr &out_file, const FsPath &path, OpenMode mode) { FsFile f; R_TRY(fsFsOpenFile(this->base_fs.get(), path.str, static_cast(mode), &f)); out_file = std::make_unique(f); return ResultSuccess; } virtual Result OpenDirectoryImpl(std::unique_ptr &out_dir, const FsPath &path, DirectoryOpenMode mode) { FsDir d; R_TRY(fsFsOpenDirectory(this->base_fs.get(), path.str, static_cast(mode), &d)); out_dir = std::make_unique(d); return ResultSuccess; } virtual Result CommitImpl() { return fsFsCommit(this->base_fs.get()); } virtual Result GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) { return fsFsGetFreeSpace(this->base_fs.get(), path.str, out); } virtual Result GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) { return fsFsGetTotalSpace(this->base_fs.get(), path.str, out); } virtual Result CleanDirectoryRecursivelyImpl(const FsPath &path) { return fsFsCleanDirectoryRecursively(this->base_fs.get(), path.str); } 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, const FsPath &path) { return fsFsQueryEntry(this->base_fs.get(), out, out_size, in, in_size, path.str,static_cast(query)); } };