diff options
author | Zach Hilman <DarkLordZach@users.noreply.github.com> | 2018-07-19 03:07:11 +0200 |
---|---|---|
committer | bunnei <bunneidev@gmail.com> | 2018-07-19 03:07:11 +0200 |
commit | 29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef (patch) | |
tree | 3202e2ce55ab6387a4ca366a509eccdd963434c3 /src/core/hle/service/filesystem/filesystem.cpp | |
parent | Merge pull request #683 from DarkLordZach/touch (diff) | |
download | yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.tar yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.tar.gz yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.tar.bz2 yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.tar.lz yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.tar.xz yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.tar.zst yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.zip |
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/service/filesystem/filesystem.cpp | 209 |
1 files changed, 199 insertions, 10 deletions
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 902256757..ec528ef40 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -2,17 +2,204 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <boost/container/flat_map.hpp> +#pragma optimize("", off) + +#include "common/assert.h" #include "common/file_util.h" +#include "core/core.h" #include "core/file_sys/errors.h" -#include "core/file_sys/filesystem.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/sdmc_factory.h" +#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs_real.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_srv.h" namespace Service::FileSystem { +// Size of emulated sd card free space, reported in bytes. +// Just using 32GB because thats reasonable +// TODO(DarkLordZach): Eventually make this configurable in settings. +constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000; + +static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, + const std::string& dir_name) { + if (dir_name == "." || dir_name == "" || dir_name == "/" || dir_name == "\\") + return base; + + return base->GetDirectoryRelative(dir_name); +} + +VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_) + : backing(backing_) {} + +std::string VfsDirectoryServiceWrapper::GetName() const { + return backing->GetName(); +} + +ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path, u64 size) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + auto file = dir->CreateFile(FileUtil::GetFilename(path)); + if (file == nullptr) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + if (!file->Resize(size)) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (path == "/" || path == "\\") { + // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but... + return RESULT_SUCCESS; + } + if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr) + return FileSys::ERROR_PATH_NOT_FOUND; + if (!backing->DeleteFile(FileUtil::GetFilename(path))) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty()) + dir = backing; + auto new_dir = dir->CreateSubdirectory(FileUtil::GetFilename(path)); + if (new_dir == nullptr) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path, + const std::string& dest_path) const { + auto src = backing->GetFileRelative(src_path); + if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { + // Use more-optimized vfs implementation rename. + if (src == nullptr) + return FileSys::ERROR_PATH_NOT_FOUND; + if (!src->Rename(FileUtil::GetFilename(dest_path))) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + return RESULT_SUCCESS; + } + + // Move by hand -- TODO(DarkLordZach): Optimize + auto c_res = CreateFile(dest_path, src->GetSize()); + if (c_res != RESULT_SUCCESS) + return c_res; + + auto dest = backing->GetFileRelative(dest_path); + ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found."); + + ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(), + "Could not write all of the bytes but everything else has succeded."); + + if (!src->GetContainingDirectory()->DeleteFile(FileUtil::GetFilename(src_path))) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + + return RESULT_SUCCESS; +} + +ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path, + const std::string& dest_path) const { + auto src = GetDirectoryRelativeWrapped(backing, src_path); + if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { + // Use more-optimized vfs implementation rename. + if (src == nullptr) + return FileSys::ERROR_PATH_NOT_FOUND; + if (!src->Rename(FileUtil::GetFilename(dest_path))) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + return RESULT_SUCCESS; + } + + // TODO(DarkLordZach): Implement renaming across the tree (move). + ASSERT_MSG(false, + "Could not rename directory with path \"{}\" to new path \"{}\" because parent dirs " + "don't match -- UNIMPLEMENTED", + src_path, dest_path); + + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); +} + +ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path, + FileSys::Mode mode) const { + auto npath = path; + while (npath.size() > 0 && (npath[0] == '/' || npath[0] == '\\')) + npath = npath.substr(1); + auto file = backing->GetFileRelative(npath); + if (file == nullptr) + return FileSys::ERROR_PATH_NOT_FOUND; + + if (mode == FileSys::Mode::Append) { + return MakeResult<FileSys::VirtualFile>( + std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize())); + } + + return MakeResult<FileSys::VirtualFile>(file); +} + +ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path) { + auto dir = GetDirectoryRelativeWrapped(backing, path); + if (dir == nullptr) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + return MakeResult(dir); +} + +u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const { + if (backing->IsWritable()) + return EMULATED_SD_REPORTED_SIZE; + + return 0; +} + +ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType( + const std::string& path) const { + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (dir == nullptr) + return FileSys::ERROR_PATH_NOT_FOUND; + auto filename = FileUtil::GetFilename(path); + if (dir->GetFile(filename) != nullptr) + return MakeResult(FileSys::EntryType::File); + if (dir->GetSubdirectory(filename) != nullptr) + return MakeResult(FileSys::EntryType::Directory); + return FileSys::ERROR_PATH_NOT_FOUND; +} + /** * Map of registered file systems, identified by type. Once an file system is registered here, it * is never removed until UnregisterFileSystems is called. @@ -42,7 +229,7 @@ ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) { return RESULT_SUCCESS; } -ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id) { +ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id) { LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}", title_id); if (romfs_factory == nullptr) { @@ -53,19 +240,19 @@ ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id) { return romfs_factory->Open(title_id); } -ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSaveData( - FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct) { +ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, + FileSys::SaveDataDescriptor save_struct) { LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", - static_cast<u8>(space), SaveStructDebugInfo(save_struct)); + static_cast<u8>(space), save_struct.DebugInfo()); if (save_data_factory == nullptr) { - return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SaveDataNotFound); + return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound); } return save_data_factory->Open(space, save_struct); } -ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC() { +ResultVal<FileSys::VirtualDir> OpenSDMC() { LOG_TRACE(Service_FS, "Opening SDMC"); if (sdmc_factory == nullptr) { @@ -80,8 +267,10 @@ void RegisterFileSystems() { save_data_factory = nullptr; sdmc_factory = nullptr; - std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); - std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX); + auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>( + FileUtil::GetUserPath(D_NAND_IDX), FileSys::Mode::Write); + auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>( + FileUtil::GetUserPath(D_SDMC_IDX), FileSys::Mode::Write); auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); save_data_factory = std::move(savedata); |