From c4ca802b9dc7f0d3f3aed5aa937240bf85370c15 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Mar 2018 21:17:15 -0500 Subject: [PATCH 01/10] FS: Added an SDMC archive factory and registered it to the SDMC archive on startup. --- src/core/CMakeLists.txt | 2 + src/core/file_sys/sdmc_factory.cpp | 40 +++++++++++++++++++ src/core/file_sys/sdmc_factory.h | 31 ++++++++++++++ .../hle/service/filesystem/filesystem.cpp | 5 +++ src/core/hle/service/filesystem/filesystem.h | 1 + 5 files changed, 79 insertions(+) create mode 100644 src/core/file_sys/sdmc_factory.cpp create mode 100644 src/core/file_sys/sdmc_factory.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index faaa50e4d0..d2275d9a94 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -22,6 +22,8 @@ add_library(core STATIC file_sys/romfs_filesystem.h file_sys/savedata_factory.cpp file_sys/savedata_factory.h + file_sys/sdmc_factory.cpp + file_sys/sdmc_factory.h file_sys/storage.h frontend/emu_window.cpp frontend/emu_window.h diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp new file mode 100644 index 0000000000..00e80d2a7f --- /dev/null +++ b/src/core/file_sys/sdmc_factory.cpp @@ -0,0 +1,40 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "common/common_types.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/file_sys/disk_filesystem.h" +#include "core/file_sys/sdmc_factory.h" + +namespace FileSys { + +SDMC_Factory::SDMC_Factory(std::string sd_directory) : sd_directory(std::move(sd_directory)) {} + +ResultVal> SDMC_Factory::Open(const Path& path) { + // Create the SD Card directory if it doesn't already exist. + if (!FileUtil::IsDirectory(sd_directory)) { + FileUtil::CreateFullPath(sd_directory); + } + + auto archive = std::make_unique(sd_directory); + return MakeResult>(std::move(archive)); +} + +ResultCode SDMC_Factory::Format(const Path& path) { + LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str()); + // TODO(Subv): Find the right error code for this + return ResultCode(-1); +} + +ResultVal SDMC_Factory::GetFormatInfo(const Path& path) const { + LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); + // TODO(bunnei): Find the right error code for this + return ResultCode(-1); +} + +} // namespace FileSys diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h new file mode 100644 index 0000000000..93becda255 --- /dev/null +++ b/src/core/file_sys/sdmc_factory.h @@ -0,0 +1,31 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/common_types.h" +#include "core/file_sys/filesystem.h" +#include "core/hle/result.h" + +namespace FileSys { + +/// File system interface to the SDCard archive +class SDMC_Factory final : public FileSystemFactory { +public: + explicit SDMC_Factory(std::string sd_directory); + + std::string GetName() const override { + return "SDMC_Factory"; + } + ResultVal> Open(const Path& path) override; + ResultCode Format(const Path& path) override; + ResultVal GetFormatInfo(const Path& path) const override; + +private: + std::string sd_directory; +}; + +} // namespace FileSys diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index ef05955b95..945832e981 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -6,6 +6,7 @@ #include "common/file_util.h" #include "core/file_sys/filesystem.h" #include "core/file_sys/savedata_factory.h" +#include "core/file_sys/sdmc_factory.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_srv.h" @@ -60,9 +61,13 @@ void RegisterFileSystems() { filesystem_map.clear(); std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); + std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX); auto savedata = std::make_unique(std::move(nand_directory)); RegisterFileSystem(std::move(savedata), Type::SaveData); + + auto sdcard = std::make_unique(std::move(sd_directory)); + RegisterFileSystem(std::move(sdcard), Type::SDMC); } void InstallInterfaces(SM::ServiceManager& service_manager) { diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 8d30e94a13..56d26146e9 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -26,6 +26,7 @@ namespace FileSystem { enum class Type { RomFS = 1, SaveData = 2, + SDMC = 3, }; /** From 808704c78cd2bb39523e488687eb3743ca443847 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Mar 2018 21:21:49 -0500 Subject: [PATCH 02/10] FS: Implement MountSdCard. --- src/core/hle/service/filesystem/fsp_srv.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 97b3fa290a..720ac99301 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -274,10 +274,14 @@ void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) { } void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); + LOG_DEBUG(Service_FS, "called"); - IPC::ResponseBuilder rb{ctx, 2}; + FileSys::Path unused; + auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::move(filesystem)); } void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { From fc44261dd1304c7dd1f38999a13ef9734c23b69a Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Mar 2018 22:57:34 -0500 Subject: [PATCH 03/10] FS: Support the file Append open mode. --- src/core/file_sys/disk_filesystem.cpp | 24 ++++++++++++++++++++++-- src/core/file_sys/filesystem.h | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp index 22b17ba045..9d456e0bf0 100644 --- a/src/core/file_sys/disk_filesystem.cpp +++ b/src/core/file_sys/disk_filesystem.cpp @@ -17,10 +17,30 @@ std::string Disk_FileSystem::GetName() const { ResultVal> Disk_FileSystem::OpenFile(const std::string& path, Mode mode) const { - ASSERT_MSG(mode == Mode::Read || mode == Mode::Write, "Other file modes are not supported"); + + std::string mode_str = ""; + u32 mode_flags = static_cast(mode); + + // Calculate the correct open mode for the file. + if ((mode_flags & static_cast(Mode::Read)) && + (mode_flags & static_cast(Mode::Write))) { + if (mode_flags & static_cast(Mode::Append)) + mode_str = "a+"; + else + mode_str = "r+"; + } else { + if (mode_flags & static_cast(Mode::Read)) + mode_str = "r"; + else if (mode_flags & static_cast(Mode::Append)) + mode_str = "a"; + else if (mode_flags & static_cast(Mode::Write)) + mode_str = "w"; + } + + mode_str += "b"; std::string full_path = base_directory + path; - auto file = std::make_shared(full_path, mode == Mode::Read ? "rb" : "wb"); + auto file = std::make_shared(full_path, mode_str.c_str()); if (!file->IsOpen()) { return ERROR_PATH_NOT_FOUND; diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h index 94ad2abf29..4c9993efa2 100644 --- a/src/core/file_sys/filesystem.h +++ b/src/core/file_sys/filesystem.h @@ -35,6 +35,7 @@ enum EntryType : u32 { enum class Mode : u32 { Read = 1, Write = 2, + Append = 4, }; class Path { From a9ba2c2000d9f2e4c6018aa6fc1e754eca82f72c Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Mar 2018 22:58:55 -0500 Subject: [PATCH 04/10] FS: Updated the Directory Entry structure to match the Switch. --- src/core/file_sys/directory.h | 37 ++++++++++----------- src/core/file_sys/disk_filesystem.cpp | 48 +++++++++++++++++++++++---- src/core/file_sys/disk_filesystem.h | 22 ++++++++++-- src/core/file_sys/filesystem.h | 2 +- src/core/file_sys/romfs_filesystem.h | 5 ++- 5 files changed, 84 insertions(+), 30 deletions(-) diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h index 5a40bf472d..c7639795ed 100644 --- a/src/core/file_sys/directory.h +++ b/src/core/file_sys/directory.h @@ -6,34 +6,28 @@ #include #include +#include "common/common_funcs.h" #include "common/common_types.h" +#include "core/file_sys/filesystem.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // FileSys namespace namespace FileSys { -// Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format -const size_t FILENAME_LENGTH = 0x20C / 2; +// Structure of a directory entry, from +// http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry +const size_t FILENAME_LENGTH = 0x300; struct Entry { - char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated) - std::array short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated) - char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD) - std::array - extension; // 8.3 file extension (set to spaces for directories, null-terminated) - char unknown2; // unknown (always 0x01) - char unknown3; // unknown (0x00 or 0x08) - char is_directory; // directory flag - char is_hidden; // hidden flag - char is_archive; // archive flag - char is_read_only; // read-only flag - u64 file_size; // file size (for files only) + char filename[FILENAME_LENGTH]; + INSERT_PADDING_BYTES(4); + EntryType type; + INSERT_PADDING_BYTES(3); + u64 file_size; }; -static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); -static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry."); -static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry."); -static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry."); -static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry."); +static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x310 bytes long!"); +static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry."); +static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry."); class DirectoryBackend : NonCopyable { public: @@ -46,7 +40,10 @@ public: * @param entries Buffer to read data into * @return Number of entries listed */ - virtual u32 Read(const u32 count, Entry* entries) = 0; + virtual u64 Read(const u64 count, Entry* entries) = 0; + + /// Returns the number of entries still left to read. + virtual u64 GetEntryCount() const = 0; /** * Close the directory diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp index 9d456e0bf0..e2092b9dfa 100644 --- a/src/core/file_sys/disk_filesystem.cpp +++ b/src/core/file_sys/disk_filesystem.cpp @@ -153,14 +153,50 @@ bool Disk_Storage::SetSize(const u64 size) const { return false; } -u32 Disk_Directory::Read(const u32 count, Entry* entries) { - LOG_WARNING(Service_FS, "(STUBBED) called"); - return 0; +Disk_Directory::Disk_Directory(const std::string& path) : directory() { + unsigned size = FileUtil::ScanDirectoryTree(path, directory); + directory.size = size; + directory.isDirectory = true; + children_iterator = directory.children.begin(); } -bool Disk_Directory::Close() const { - LOG_WARNING(Service_FS, "(STUBBED) called"); - return true; +u64 Disk_Directory::Read(const u64 count, Entry* entries) { + u64 entries_read = 0; + + while (entries_read < count && children_iterator != directory.children.cend()) { + const FileUtil::FSTEntry& file = *children_iterator; + const std::string& filename = file.virtualName; + Entry& entry = entries[entries_read]; + + LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, + file.isDirectory); + + // TODO(Link Mauve): use a proper conversion to UTF-16. + for (size_t j = 0; j < FILENAME_LENGTH; ++j) { + entry.filename[j] = filename[j]; + if (!filename[j]) + break; + } + + if (file.isDirectory) { + entry.file_size = 0; + entry.type = EntryType::Directory; + } else { + entry.file_size = file.size; + entry.type = EntryType::File; + } + + ++entries_read; + ++children_iterator; + } + return entries_read; +} + +u64 Disk_Directory::GetEntryCount() const { + // We convert the children iterator into a const_iterator to allow template argument deduction + // in std::distance. + std::vector::const_iterator current = children_iterator; + return std::distance(current, directory.children.end()); } } // namespace FileSys diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h index 53767b949f..29383dbf76 100644 --- a/src/core/file_sys/disk_filesystem.h +++ b/src/core/file_sys/disk_filesystem.h @@ -59,8 +59,26 @@ private: class Disk_Directory : public DirectoryBackend { public: - u32 Read(const u32 count, Entry* entries) override; - bool Close() const override; + Disk_Directory(const std::string& path); + + ~Disk_Directory() override { + Close(); + } + + u64 Read(const u64 count, Entry* entries) override; + u64 GetEntryCount() const override; + + bool Close() const override { + return true; + } + +protected: + u32 total_entries_in_directory; + FileUtil::FSTEntry directory; + + // We need to remember the last entry we returned, so a subsequent call to Read will continue + // from the next one. This iterator will always point to the next unread entry. + std::vector::iterator children_iterator; }; } // namespace FileSys diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h index 4c9993efa2..5c91a46c2f 100644 --- a/src/core/file_sys/filesystem.h +++ b/src/core/file_sys/filesystem.h @@ -27,7 +27,7 @@ enum LowPathType : u32 { Wchar = 4, }; -enum EntryType : u32 { +enum EntryType : u8 { Directory = 0, File = 1, }; diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h index cedd706456..be52f20ef4 100644 --- a/src/core/file_sys/romfs_filesystem.h +++ b/src/core/file_sys/romfs_filesystem.h @@ -70,7 +70,10 @@ private: class ROMFSDirectory : public DirectoryBackend { public: - u32 Read(const u32 count, Entry* entries) override { + u64 Read(const u64 count, Entry* entries) override { + return 0; + } + u64 GetEntryCount() const override { return 0; } bool Close() const override { From e1d7b9fc2c8780552b40e8415104b4205efe2de7 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Mar 2018 22:59:38 -0500 Subject: [PATCH 05/10] FS: Implement DiskFileSystem::GetEntryType for existing files/directories. --- src/core/file_sys/disk_filesystem.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp index e2092b9dfa..e02b20fafb 100644 --- a/src/core/file_sys/disk_filesystem.cpp +++ b/src/core/file_sys/disk_filesystem.cpp @@ -123,8 +123,10 @@ ResultVal Disk_FileSystem::GetEntryType(const std::string& p return ERROR_PATH_NOT_FOUND; } - // TODO(Subv): Find out the EntryType values - UNIMPLEMENTED_MSG("Unimplemented GetEntryType"); + if (FileUtil::IsDirectory(full_path)) + return MakeResult(EntryType::Directory); + + return MakeResult(EntryType::File); } ResultVal Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { From 6d90d99d12c6a1e7ec27831d93052a30c0e689b5 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Mar 2018 23:00:37 -0500 Subject: [PATCH 06/10] FS: Implement DiskFileSystem's OpenDirectory interface. --- src/core/file_sys/disk_filesystem.cpp | 13 +++++++++++-- src/core/file_sys/disk_filesystem.h | 3 ++- src/core/file_sys/filesystem.h | 3 ++- src/core/file_sys/romfs_filesystem.cpp | 3 ++- src/core/file_sys/romfs_filesystem.h | 3 ++- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp index e02b20fafb..f620b7961d 100644 --- a/src/core/file_sys/disk_filesystem.cpp +++ b/src/core/file_sys/disk_filesystem.cpp @@ -108,8 +108,17 @@ ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& de } ResultVal> Disk_FileSystem::OpenDirectory( - const Path& path) const { - return MakeResult>(std::make_unique()); + const std::string& path) const { + + std::string full_path = base_directory + path; + + if (!FileUtil::IsDirectory(full_path)) { + // TODO(Subv): Find the correct error code for this. + return ResultCode(-1); + } + + auto directory = std::make_unique(full_path); + return MakeResult>(std::move(directory)); } u64 Disk_FileSystem::GetFreeSpaceSize() const { diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h index 29383dbf76..72a0afedf9 100644 --- a/src/core/file_sys/disk_filesystem.h +++ b/src/core/file_sys/disk_filesystem.h @@ -32,7 +32,8 @@ public: ResultCode CreateFile(const std::string& path, u64 size) const override; ResultCode CreateDirectory(const Path& path) const override; ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; - ResultVal> OpenDirectory(const Path& path) const override; + ResultVal> OpenDirectory( + const std::string& path) const override; u64 GetFreeSpaceSize() const override; ResultVal GetEntryType(const std::string& path) const override; diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h index 5c91a46c2f..22ad241430 100644 --- a/src/core/file_sys/filesystem.h +++ b/src/core/file_sys/filesystem.h @@ -150,7 +150,8 @@ public: * @param path Path relative to the archive * @return Opened directory, or error code */ - virtual ResultVal> OpenDirectory(const Path& path) const = 0; + virtual ResultVal> OpenDirectory( + const std::string& path) const = 0; /** * Get the free space diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp index f1f9b4d040..169f0d4f66 100644 --- a/src/core/file_sys/romfs_filesystem.cpp +++ b/src/core/file_sys/romfs_filesystem.cpp @@ -70,7 +70,8 @@ ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& d } ResultVal> RomFS_FileSystem::OpenDirectory( - const Path& path) const { + const std::string& path) const { + LOG_WARNING(Service_FS, "Opening Directory in a ROMFS archive"); return MakeResult>(std::make_unique()); } diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h index be52f20ef4..ee41c2d020 100644 --- a/src/core/file_sys/romfs_filesystem.h +++ b/src/core/file_sys/romfs_filesystem.h @@ -38,7 +38,8 @@ public: ResultCode CreateFile(const std::string& path, u64 size) const override; ResultCode CreateDirectory(const Path& path) const override; ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; - ResultVal> OpenDirectory(const Path& path) const override; + ResultVal> OpenDirectory( + const std::string& path) const override; u64 GetFreeSpaceSize() const override; ResultVal GetEntryType(const std::string& path) const override; From 21bac2d7d757df18f184a8d79393ab8f91c0fc03 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Mar 2018 23:01:47 -0500 Subject: [PATCH 07/10] FS: Added the IDirectory IPC interface and implemented its two functions. --- src/core/hle/service/filesystem/fsp_srv.cpp | 51 +++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 720ac99301..5536991bca 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -5,6 +5,7 @@ #include #include "common/logging/log.h" #include "core/core.h" +#include "core/file_sys/directory.h" #include "core/file_sys/filesystem.h" #include "core/file_sys/storage.h" #include "core/hle/ipc_helpers.h" @@ -151,6 +152,56 @@ private: } }; +class IDirectory final : public ServiceFramework { +public: + explicit IDirectory(std::unique_ptr&& backend) + : ServiceFramework("IDirectory"), backend(std::move(backend)) { + static const FunctionInfo functions[] = { + {0, &IDirectory::Read, "Read"}, + {1, &IDirectory::GetEntryCount, "GetEntryCount"}, + }; + RegisterHandlers(functions); + } + +private: + std::unique_ptr backend; + + void Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 unk = rp.Pop(); + + LOG_DEBUG(Service_FS, "called, unk=0x%llx", unk); + + // Calculate how many entries we can fit in the output buffer + u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); + + // Read the data from the Directory backend + std::vector entries(count_entries); + u64 read_entries = backend->Read(count_entries, entries.data()); + + // Convert the data into a byte array + std::vector output(entries.size() * sizeof(FileSys::Entry)); + std::memcpy(output.data(), entries.data(), output.size()); + + // Write the data to memory + ctx.WriteBuffer(output); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(read_entries); + } + + void GetEntryCount(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + u64 count = backend->GetEntryCount(); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(count); + } +}; + class IFileSystem final : public ServiceFramework { public: explicit IFileSystem(std::unique_ptr&& backend) From 0485ee499f9e00fb2ec1926876d6e50c9b22447b Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 19 Mar 2018 23:02:30 -0500 Subject: [PATCH 08/10] FS: Implemented IFileSystem's OpenDirectory function. Note that the filter parameter is not yet implemented. --- src/core/hle/service/filesystem/fsp_srv.cpp | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 5536991bca..6f539316e5 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -210,6 +210,7 @@ public: {0, &IFileSystem::CreateFile, "CreateFile"}, {7, &IFileSystem::GetEntryType, "GetEntryType"}, {8, &IFileSystem::OpenFile, "OpenFile"}, + {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, {10, &IFileSystem::Commit, "Commit"}, }; RegisterHandlers(functions); @@ -259,6 +260,33 @@ public: rb.PushIpcInterface(std::move(file)); } + void OpenDirectory(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); + + std::string name(file_buffer.begin(), end); + + // TODO(Subv): Implement this filter. + u32 filter_flags = rp.Pop(); + + LOG_DEBUG(Service_FS, "called directory %s filter %u", name.c_str(), filter_flags); + + auto result = backend->OpenDirectory(name); + if (result.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result.Code()); + return; + } + + auto directory = std::move(result.Unwrap()); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::move(directory)); + } + void GetEntryType(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; From eff3f60b73343365ad65638f55591965df6f7e25 Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 21 Mar 2018 09:36:26 -0500 Subject: [PATCH 09/10] FS: Implemented IFileSystem::CreateDirectory. --- src/core/file_sys/disk_filesystem.cpp | 13 ++++++++++--- src/core/file_sys/disk_filesystem.h | 2 +- src/core/file_sys/filesystem.h | 2 +- src/core/file_sys/romfs_filesystem.cpp | 2 +- src/core/file_sys/romfs_filesystem.h | 2 +- src/core/hle/service/filesystem/fsp_srv.cpp | 15 +++++++++++++++ 6 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp index f620b7961d..9383bf856b 100644 --- a/src/core/file_sys/disk_filesystem.cpp +++ b/src/core/file_sys/disk_filesystem.cpp @@ -18,7 +18,7 @@ std::string Disk_FileSystem::GetName() const { ResultVal> Disk_FileSystem::OpenFile(const std::string& path, Mode mode) const { - std::string mode_str = ""; + std::string mode_str; u32 mode_flags = static_cast(mode); // Calculate the correct open mode for the file. @@ -95,8 +95,15 @@ ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const return ResultCode(-1); } -ResultCode Disk_FileSystem::CreateDirectory(const Path& path) const { - LOG_WARNING(Service_FS, "(STUBBED) called"); +ResultCode Disk_FileSystem::CreateDirectory(const std::string& path) const { + // TODO(Subv): Perform path validation to prevent escaping the emulator sandbox. + std::string full_path = base_directory + path; + + if (FileUtil::CreateDir(full_path)) { + return RESULT_SUCCESS; + } + + LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", full_path.c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h index 72a0afedf9..742d7db1a1 100644 --- a/src/core/file_sys/disk_filesystem.h +++ b/src/core/file_sys/disk_filesystem.h @@ -30,7 +30,7 @@ public: ResultCode DeleteDirectory(const Path& path) const override; ResultCode DeleteDirectoryRecursively(const Path& path) const override; ResultCode CreateFile(const std::string& path, u64 size) const override; - ResultCode CreateDirectory(const Path& path) const override; + ResultCode CreateDirectory(const std::string& path) const override; ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; ResultVal> OpenDirectory( const std::string& path) const override; diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h index 22ad241430..399427ca23 100644 --- a/src/core/file_sys/filesystem.h +++ b/src/core/file_sys/filesystem.h @@ -104,7 +104,7 @@ public: * @param path Path relative to the archive * @return Result of the operation */ - virtual ResultCode CreateDirectory(const Path& path) const = 0; + virtual ResultCode CreateDirectory(const std::string& path) const = 0; /** * Delete a directory specified by its path diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp index 169f0d4f66..0c6cc3157d 100644 --- a/src/core/file_sys/romfs_filesystem.cpp +++ b/src/core/file_sys/romfs_filesystem.cpp @@ -55,7 +55,7 @@ ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const return ResultCode(-1); } -ResultCode RomFS_FileSystem::CreateDirectory(const Path& path) const { +ResultCode RomFS_FileSystem::CreateDirectory(const std::string& path) const { LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h index ee41c2d020..3f94c04d0d 100644 --- a/src/core/file_sys/romfs_filesystem.h +++ b/src/core/file_sys/romfs_filesystem.h @@ -36,7 +36,7 @@ public: ResultCode DeleteDirectory(const Path& path) const override; ResultCode DeleteDirectoryRecursively(const Path& path) const override; ResultCode CreateFile(const std::string& path, u64 size) const override; - ResultCode CreateDirectory(const Path& path) const override; + ResultCode CreateDirectory(const std::string& path) const override; ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; ResultVal> OpenDirectory( const std::string& path) const override; diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 6f539316e5..cbb7552d91 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -208,6 +208,7 @@ public: : ServiceFramework("IFileSystem"), backend(std::move(backend)) { static const FunctionInfo functions[] = { {0, &IFileSystem::CreateFile, "CreateFile"}, + {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, {7, &IFileSystem::GetEntryType, "GetEntryType"}, {8, &IFileSystem::OpenFile, "OpenFile"}, {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, @@ -234,6 +235,20 @@ public: rb.Push(backend->CreateFile(name, size)); } + void CreateDirectory(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto file_buffer = ctx.ReadBuffer(); + auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); + + std::string name(file_buffer.begin(), end); + + LOG_DEBUG(Service_FS, "called directory %s", name.c_str()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend->CreateDirectory(name)); + } + void OpenFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; From 4c06d55a81304d0e658adf441d8bdb90a32ba228 Mon Sep 17 00:00:00 2001 From: Subv Date: Fri, 23 Mar 2018 11:09:09 -0500 Subject: [PATCH 10/10] FS: Move the file open mode calculation to a separate function. --- src/core/file_sys/disk_filesystem.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp index 9383bf856b..3a4b45721d 100644 --- a/src/core/file_sys/disk_filesystem.cpp +++ b/src/core/file_sys/disk_filesystem.cpp @@ -11,13 +11,7 @@ namespace FileSys { -std::string Disk_FileSystem::GetName() const { - return "Disk"; -} - -ResultVal> Disk_FileSystem::OpenFile(const std::string& path, - Mode mode) const { - +static std::string ModeFlagsToString(Mode mode) { std::string mode_str; u32 mode_flags = static_cast(mode); @@ -39,6 +33,19 @@ ResultVal> Disk_FileSystem::OpenFile(const std:: mode_str += "b"; + return mode_str; +} + +std::string Disk_FileSystem::GetName() const { + return "Disk"; +} + +ResultVal> Disk_FileSystem::OpenFile(const std::string& path, + Mode mode) const { + + // Calculate the correct open mode for the file. + std::string mode_str = ModeFlagsToString(mode); + std::string full_path = base_directory + path; auto file = std::make_shared(full_path, mode_str.c_str());