diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/file_sys/directory.h | 37 | ||||
| -rw-r--r-- | src/core/file_sys/disk_filesystem.cpp | 109 | ||||
| -rw-r--r-- | src/core/file_sys/disk_filesystem.h | 27 | ||||
| -rw-r--r-- | src/core/file_sys/filesystem.h | 8 | ||||
| -rw-r--r-- | src/core/file_sys/romfs_filesystem.cpp | 5 | ||||
| -rw-r--r-- | src/core/file_sys/romfs_filesystem.h | 10 | ||||
| -rw-r--r-- | src/core/file_sys/sdmc_factory.cpp | 40 | ||||
| -rw-r--r-- | src/core/file_sys/sdmc_factory.h | 31 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/filesystem.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/filesystem.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 102 |
12 files changed, 329 insertions, 48 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0a25a52e4..39cdb55f1 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -22,6 +22,8 @@ add_library(core STATIC | |||
| 22 | file_sys/romfs_filesystem.h | 22 | file_sys/romfs_filesystem.h |
| 23 | file_sys/savedata_factory.cpp | 23 | file_sys/savedata_factory.cpp |
| 24 | file_sys/savedata_factory.h | 24 | file_sys/savedata_factory.h |
| 25 | file_sys/sdmc_factory.cpp | ||
| 26 | file_sys/sdmc_factory.h | ||
| 25 | file_sys/storage.h | 27 | file_sys/storage.h |
| 26 | frontend/emu_window.cpp | 28 | frontend/emu_window.cpp |
| 27 | frontend/emu_window.h | 29 | frontend/emu_window.h |
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h index 5a40bf472..c7639795e 100644 --- a/src/core/file_sys/directory.h +++ b/src/core/file_sys/directory.h | |||
| @@ -6,34 +6,28 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/file_sys/filesystem.h" | ||
| 10 | 12 | ||
| 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 12 | // FileSys namespace | 14 | // FileSys namespace |
| 13 | 15 | ||
| 14 | namespace FileSys { | 16 | namespace FileSys { |
| 15 | 17 | ||
| 16 | // Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format | 18 | // Structure of a directory entry, from |
| 17 | const size_t FILENAME_LENGTH = 0x20C / 2; | 19 | // http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry |
| 20 | const size_t FILENAME_LENGTH = 0x300; | ||
| 18 | struct Entry { | 21 | struct Entry { |
| 19 | char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated) | 22 | char filename[FILENAME_LENGTH]; |
| 20 | std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated) | 23 | INSERT_PADDING_BYTES(4); |
| 21 | char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD) | 24 | EntryType type; |
| 22 | std::array<char, 4> | 25 | INSERT_PADDING_BYTES(3); |
| 23 | extension; // 8.3 file extension (set to spaces for directories, null-terminated) | 26 | u64 file_size; |
| 24 | char unknown2; // unknown (always 0x01) | ||
| 25 | char unknown3; // unknown (0x00 or 0x08) | ||
| 26 | char is_directory; // directory flag | ||
| 27 | char is_hidden; // hidden flag | ||
| 28 | char is_archive; // archive flag | ||
| 29 | char is_read_only; // read-only flag | ||
| 30 | u64 file_size; // file size (for files only) | ||
| 31 | }; | 27 | }; |
| 32 | static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); | 28 | static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x310 bytes long!"); |
| 33 | static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry."); | 29 | static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry."); |
| 34 | static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry."); | 30 | static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry."); |
| 35 | static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry."); | ||
| 36 | static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry."); | ||
| 37 | 31 | ||
| 38 | class DirectoryBackend : NonCopyable { | 32 | class DirectoryBackend : NonCopyable { |
| 39 | public: | 33 | public: |
| @@ -46,7 +40,10 @@ public: | |||
| 46 | * @param entries Buffer to read data into | 40 | * @param entries Buffer to read data into |
| 47 | * @return Number of entries listed | 41 | * @return Number of entries listed |
| 48 | */ | 42 | */ |
| 49 | virtual u32 Read(const u32 count, Entry* entries) = 0; | 43 | virtual u64 Read(const u64 count, Entry* entries) = 0; |
| 44 | |||
| 45 | /// Returns the number of entries still left to read. | ||
| 46 | virtual u64 GetEntryCount() const = 0; | ||
| 50 | 47 | ||
| 51 | /** | 48 | /** |
| 52 | * Close the directory | 49 | * Close the directory |
diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp index 22b17ba04..3a4b45721 100644 --- a/src/core/file_sys/disk_filesystem.cpp +++ b/src/core/file_sys/disk_filesystem.cpp | |||
| @@ -11,16 +11,43 @@ | |||
| 11 | 11 | ||
| 12 | namespace FileSys { | 12 | namespace FileSys { |
| 13 | 13 | ||
| 14 | static std::string ModeFlagsToString(Mode mode) { | ||
| 15 | std::string mode_str; | ||
| 16 | u32 mode_flags = static_cast<u32>(mode); | ||
| 17 | |||
| 18 | // Calculate the correct open mode for the file. | ||
| 19 | if ((mode_flags & static_cast<u32>(Mode::Read)) && | ||
| 20 | (mode_flags & static_cast<u32>(Mode::Write))) { | ||
| 21 | if (mode_flags & static_cast<u32>(Mode::Append)) | ||
| 22 | mode_str = "a+"; | ||
| 23 | else | ||
| 24 | mode_str = "r+"; | ||
| 25 | } else { | ||
| 26 | if (mode_flags & static_cast<u32>(Mode::Read)) | ||
| 27 | mode_str = "r"; | ||
| 28 | else if (mode_flags & static_cast<u32>(Mode::Append)) | ||
| 29 | mode_str = "a"; | ||
| 30 | else if (mode_flags & static_cast<u32>(Mode::Write)) | ||
| 31 | mode_str = "w"; | ||
| 32 | } | ||
| 33 | |||
| 34 | mode_str += "b"; | ||
| 35 | |||
| 36 | return mode_str; | ||
| 37 | } | ||
| 38 | |||
| 14 | std::string Disk_FileSystem::GetName() const { | 39 | std::string Disk_FileSystem::GetName() const { |
| 15 | return "Disk"; | 40 | return "Disk"; |
| 16 | } | 41 | } |
| 17 | 42 | ||
| 18 | ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path, | 43 | ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path, |
| 19 | Mode mode) const { | 44 | Mode mode) const { |
| 20 | ASSERT_MSG(mode == Mode::Read || mode == Mode::Write, "Other file modes are not supported"); | 45 | |
| 46 | // Calculate the correct open mode for the file. | ||
| 47 | std::string mode_str = ModeFlagsToString(mode); | ||
| 21 | 48 | ||
| 22 | std::string full_path = base_directory + path; | 49 | std::string full_path = base_directory + path; |
| 23 | auto file = std::make_shared<FileUtil::IOFile>(full_path, mode == Mode::Read ? "rb" : "wb"); | 50 | auto file = std::make_shared<FileUtil::IOFile>(full_path, mode_str.c_str()); |
| 24 | 51 | ||
| 25 | if (!file->IsOpen()) { | 52 | if (!file->IsOpen()) { |
| 26 | return ERROR_PATH_NOT_FOUND; | 53 | return ERROR_PATH_NOT_FOUND; |
| @@ -75,8 +102,15 @@ ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const | |||
| 75 | return ResultCode(-1); | 102 | return ResultCode(-1); |
| 76 | } | 103 | } |
| 77 | 104 | ||
| 78 | ResultCode Disk_FileSystem::CreateDirectory(const Path& path) const { | 105 | ResultCode Disk_FileSystem::CreateDirectory(const std::string& path) const { |
| 79 | LOG_WARNING(Service_FS, "(STUBBED) called"); | 106 | // TODO(Subv): Perform path validation to prevent escaping the emulator sandbox. |
| 107 | std::string full_path = base_directory + path; | ||
| 108 | |||
| 109 | if (FileUtil::CreateDir(full_path)) { | ||
| 110 | return RESULT_SUCCESS; | ||
| 111 | } | ||
| 112 | |||
| 113 | LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", full_path.c_str()); | ||
| 80 | // TODO(wwylele): Use correct error code | 114 | // TODO(wwylele): Use correct error code |
| 81 | return ResultCode(-1); | 115 | return ResultCode(-1); |
| 82 | } | 116 | } |
| @@ -88,8 +122,17 @@ ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& de | |||
| 88 | } | 122 | } |
| 89 | 123 | ||
| 90 | ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory( | 124 | ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory( |
| 91 | const Path& path) const { | 125 | const std::string& path) const { |
| 92 | return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<Disk_Directory>()); | 126 | |
| 127 | std::string full_path = base_directory + path; | ||
| 128 | |||
| 129 | if (!FileUtil::IsDirectory(full_path)) { | ||
| 130 | // TODO(Subv): Find the correct error code for this. | ||
| 131 | return ResultCode(-1); | ||
| 132 | } | ||
| 133 | |||
| 134 | auto directory = std::make_unique<Disk_Directory>(full_path); | ||
| 135 | return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory)); | ||
| 93 | } | 136 | } |
| 94 | 137 | ||
| 95 | u64 Disk_FileSystem::GetFreeSpaceSize() const { | 138 | u64 Disk_FileSystem::GetFreeSpaceSize() const { |
| @@ -103,8 +146,10 @@ ResultVal<FileSys::EntryType> Disk_FileSystem::GetEntryType(const std::string& p | |||
| 103 | return ERROR_PATH_NOT_FOUND; | 146 | return ERROR_PATH_NOT_FOUND; |
| 104 | } | 147 | } |
| 105 | 148 | ||
| 106 | // TODO(Subv): Find out the EntryType values | 149 | if (FileUtil::IsDirectory(full_path)) |
| 107 | UNIMPLEMENTED_MSG("Unimplemented GetEntryType"); | 150 | return MakeResult(EntryType::Directory); |
| 151 | |||
| 152 | return MakeResult(EntryType::File); | ||
| 108 | } | 153 | } |
| 109 | 154 | ||
| 110 | ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { | 155 | ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { |
| @@ -133,14 +178,50 @@ bool Disk_Storage::SetSize(const u64 size) const { | |||
| 133 | return false; | 178 | return false; |
| 134 | } | 179 | } |
| 135 | 180 | ||
| 136 | u32 Disk_Directory::Read(const u32 count, Entry* entries) { | 181 | Disk_Directory::Disk_Directory(const std::string& path) : directory() { |
| 137 | LOG_WARNING(Service_FS, "(STUBBED) called"); | 182 | unsigned size = FileUtil::ScanDirectoryTree(path, directory); |
| 138 | return 0; | 183 | directory.size = size; |
| 184 | directory.isDirectory = true; | ||
| 185 | children_iterator = directory.children.begin(); | ||
| 139 | } | 186 | } |
| 140 | 187 | ||
| 141 | bool Disk_Directory::Close() const { | 188 | u64 Disk_Directory::Read(const u64 count, Entry* entries) { |
| 142 | LOG_WARNING(Service_FS, "(STUBBED) called"); | 189 | u64 entries_read = 0; |
| 143 | return true; | 190 | |
| 191 | while (entries_read < count && children_iterator != directory.children.cend()) { | ||
| 192 | const FileUtil::FSTEntry& file = *children_iterator; | ||
| 193 | const std::string& filename = file.virtualName; | ||
| 194 | Entry& entry = entries[entries_read]; | ||
| 195 | |||
| 196 | LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, | ||
| 197 | file.isDirectory); | ||
| 198 | |||
| 199 | // TODO(Link Mauve): use a proper conversion to UTF-16. | ||
| 200 | for (size_t j = 0; j < FILENAME_LENGTH; ++j) { | ||
| 201 | entry.filename[j] = filename[j]; | ||
| 202 | if (!filename[j]) | ||
| 203 | break; | ||
| 204 | } | ||
| 205 | |||
| 206 | if (file.isDirectory) { | ||
| 207 | entry.file_size = 0; | ||
| 208 | entry.type = EntryType::Directory; | ||
| 209 | } else { | ||
| 210 | entry.file_size = file.size; | ||
| 211 | entry.type = EntryType::File; | ||
| 212 | } | ||
| 213 | |||
| 214 | ++entries_read; | ||
| 215 | ++children_iterator; | ||
| 216 | } | ||
| 217 | return entries_read; | ||
| 218 | } | ||
| 219 | |||
| 220 | u64 Disk_Directory::GetEntryCount() const { | ||
| 221 | // We convert the children iterator into a const_iterator to allow template argument deduction | ||
| 222 | // in std::distance. | ||
| 223 | std::vector<FileUtil::FSTEntry>::const_iterator current = children_iterator; | ||
| 224 | return std::distance(current, directory.children.end()); | ||
| 144 | } | 225 | } |
| 145 | 226 | ||
| 146 | } // namespace FileSys | 227 | } // namespace FileSys |
diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h index 53767b949..742d7db1a 100644 --- a/src/core/file_sys/disk_filesystem.h +++ b/src/core/file_sys/disk_filesystem.h | |||
| @@ -30,9 +30,10 @@ public: | |||
| 30 | ResultCode DeleteDirectory(const Path& path) const override; | 30 | ResultCode DeleteDirectory(const Path& path) const override; |
| 31 | ResultCode DeleteDirectoryRecursively(const Path& path) const override; | 31 | ResultCode DeleteDirectoryRecursively(const Path& path) const override; |
| 32 | ResultCode CreateFile(const std::string& path, u64 size) const override; | 32 | ResultCode CreateFile(const std::string& path, u64 size) const override; |
| 33 | ResultCode CreateDirectory(const Path& path) const override; | 33 | ResultCode CreateDirectory(const std::string& path) const override; |
| 34 | ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; | 34 | ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; |
| 35 | ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; | 35 | ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory( |
| 36 | const std::string& path) const override; | ||
| 36 | u64 GetFreeSpaceSize() const override; | 37 | u64 GetFreeSpaceSize() const override; |
| 37 | ResultVal<EntryType> GetEntryType(const std::string& path) const override; | 38 | ResultVal<EntryType> GetEntryType(const std::string& path) const override; |
| 38 | 39 | ||
| @@ -59,8 +60,26 @@ private: | |||
| 59 | 60 | ||
| 60 | class Disk_Directory : public DirectoryBackend { | 61 | class Disk_Directory : public DirectoryBackend { |
| 61 | public: | 62 | public: |
| 62 | u32 Read(const u32 count, Entry* entries) override; | 63 | Disk_Directory(const std::string& path); |
| 63 | bool Close() const override; | 64 | |
| 65 | ~Disk_Directory() override { | ||
| 66 | Close(); | ||
| 67 | } | ||
| 68 | |||
| 69 | u64 Read(const u64 count, Entry* entries) override; | ||
| 70 | u64 GetEntryCount() const override; | ||
| 71 | |||
| 72 | bool Close() const override { | ||
| 73 | return true; | ||
| 74 | } | ||
| 75 | |||
| 76 | protected: | ||
| 77 | u32 total_entries_in_directory; | ||
| 78 | FileUtil::FSTEntry directory; | ||
| 79 | |||
| 80 | // We need to remember the last entry we returned, so a subsequent call to Read will continue | ||
| 81 | // from the next one. This iterator will always point to the next unread entry. | ||
| 82 | std::vector<FileUtil::FSTEntry>::iterator children_iterator; | ||
| 64 | }; | 83 | }; |
| 65 | 84 | ||
| 66 | } // namespace FileSys | 85 | } // namespace FileSys |
diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h index 94ad2abf2..399427ca2 100644 --- a/src/core/file_sys/filesystem.h +++ b/src/core/file_sys/filesystem.h | |||
| @@ -27,7 +27,7 @@ enum LowPathType : u32 { | |||
| 27 | Wchar = 4, | 27 | Wchar = 4, |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | enum EntryType : u32 { | 30 | enum EntryType : u8 { |
| 31 | Directory = 0, | 31 | Directory = 0, |
| 32 | File = 1, | 32 | File = 1, |
| 33 | }; | 33 | }; |
| @@ -35,6 +35,7 @@ enum EntryType : u32 { | |||
| 35 | enum class Mode : u32 { | 35 | enum class Mode : u32 { |
| 36 | Read = 1, | 36 | Read = 1, |
| 37 | Write = 2, | 37 | Write = 2, |
| 38 | Append = 4, | ||
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | class Path { | 41 | class Path { |
| @@ -103,7 +104,7 @@ public: | |||
| 103 | * @param path Path relative to the archive | 104 | * @param path Path relative to the archive |
| 104 | * @return Result of the operation | 105 | * @return Result of the operation |
| 105 | */ | 106 | */ |
| 106 | virtual ResultCode CreateDirectory(const Path& path) const = 0; | 107 | virtual ResultCode CreateDirectory(const std::string& path) const = 0; |
| 107 | 108 | ||
| 108 | /** | 109 | /** |
| 109 | * Delete a directory specified by its path | 110 | * Delete a directory specified by its path |
| @@ -149,7 +150,8 @@ public: | |||
| 149 | * @param path Path relative to the archive | 150 | * @param path Path relative to the archive |
| 150 | * @return Opened directory, or error code | 151 | * @return Opened directory, or error code |
| 151 | */ | 152 | */ |
| 152 | virtual ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const = 0; | 153 | virtual ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory( |
| 154 | const std::string& path) const = 0; | ||
| 153 | 155 | ||
| 154 | /** | 156 | /** |
| 155 | * Get the free space | 157 | * Get the free space |
diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp index f1f9b4d04..0c6cc3157 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 | |||
| 55 | return ResultCode(-1); | 55 | return ResultCode(-1); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | ResultCode RomFS_FileSystem::CreateDirectory(const Path& path) const { | 58 | ResultCode RomFS_FileSystem::CreateDirectory(const std::string& path) const { |
| 59 | LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).", | 59 | LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).", |
| 60 | GetName().c_str()); | 60 | GetName().c_str()); |
| 61 | // TODO(wwylele): Use correct error code | 61 | // TODO(wwylele): Use correct error code |
| @@ -70,7 +70,8 @@ ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& d | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory( | 72 | ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory( |
| 73 | const Path& path) const { | 73 | const std::string& path) const { |
| 74 | LOG_WARNING(Service_FS, "Opening Directory in a ROMFS archive"); | ||
| 74 | return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>()); | 75 | return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>()); |
| 75 | } | 76 | } |
| 76 | 77 | ||
diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h index cedd70645..3f94c04d0 100644 --- a/src/core/file_sys/romfs_filesystem.h +++ b/src/core/file_sys/romfs_filesystem.h | |||
| @@ -36,9 +36,10 @@ public: | |||
| 36 | ResultCode DeleteDirectory(const Path& path) const override; | 36 | ResultCode DeleteDirectory(const Path& path) const override; |
| 37 | ResultCode DeleteDirectoryRecursively(const Path& path) const override; | 37 | ResultCode DeleteDirectoryRecursively(const Path& path) const override; |
| 38 | ResultCode CreateFile(const std::string& path, u64 size) const override; | 38 | ResultCode CreateFile(const std::string& path, u64 size) const override; |
| 39 | ResultCode CreateDirectory(const Path& path) const override; | 39 | ResultCode CreateDirectory(const std::string& path) const override; |
| 40 | ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; | 40 | ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; |
| 41 | ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; | 41 | ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory( |
| 42 | const std::string& path) const override; | ||
| 42 | u64 GetFreeSpaceSize() const override; | 43 | u64 GetFreeSpaceSize() const override; |
| 43 | ResultVal<EntryType> GetEntryType(const std::string& path) const override; | 44 | ResultVal<EntryType> GetEntryType(const std::string& path) const override; |
| 44 | 45 | ||
| @@ -70,7 +71,10 @@ private: | |||
| 70 | 71 | ||
| 71 | class ROMFSDirectory : public DirectoryBackend { | 72 | class ROMFSDirectory : public DirectoryBackend { |
| 72 | public: | 73 | public: |
| 73 | u32 Read(const u32 count, Entry* entries) override { | 74 | u64 Read(const u64 count, Entry* entries) override { |
| 75 | return 0; | ||
| 76 | } | ||
| 77 | u64 GetEntryCount() const override { | ||
| 74 | return 0; | 78 | return 0; |
| 75 | } | 79 | } |
| 76 | bool Close() const override { | 80 | bool Close() const override { |
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp new file mode 100644 index 000000000..00e80d2a7 --- /dev/null +++ b/src/core/file_sys/sdmc_factory.cpp | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cinttypes> | ||
| 6 | #include <memory> | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "common/string_util.h" | ||
| 10 | #include "core/core.h" | ||
| 11 | #include "core/file_sys/disk_filesystem.h" | ||
| 12 | #include "core/file_sys/sdmc_factory.h" | ||
| 13 | |||
| 14 | namespace FileSys { | ||
| 15 | |||
| 16 | SDMC_Factory::SDMC_Factory(std::string sd_directory) : sd_directory(std::move(sd_directory)) {} | ||
| 17 | |||
| 18 | ResultVal<std::unique_ptr<FileSystemBackend>> SDMC_Factory::Open(const Path& path) { | ||
| 19 | // Create the SD Card directory if it doesn't already exist. | ||
| 20 | if (!FileUtil::IsDirectory(sd_directory)) { | ||
| 21 | FileUtil::CreateFullPath(sd_directory); | ||
| 22 | } | ||
| 23 | |||
| 24 | auto archive = std::make_unique<Disk_FileSystem>(sd_directory); | ||
| 25 | return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive)); | ||
| 26 | } | ||
| 27 | |||
| 28 | ResultCode SDMC_Factory::Format(const Path& path) { | ||
| 29 | LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str()); | ||
| 30 | // TODO(Subv): Find the right error code for this | ||
| 31 | return ResultCode(-1); | ||
| 32 | } | ||
| 33 | |||
| 34 | ResultVal<ArchiveFormatInfo> SDMC_Factory::GetFormatInfo(const Path& path) const { | ||
| 35 | LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||
| 36 | // TODO(bunnei): Find the right error code for this | ||
| 37 | return ResultCode(-1); | ||
| 38 | } | ||
| 39 | |||
| 40 | } // 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 000000000..93becda25 --- /dev/null +++ b/src/core/file_sys/sdmc_factory.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/file_sys/filesystem.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 12 | |||
| 13 | namespace FileSys { | ||
| 14 | |||
| 15 | /// File system interface to the SDCard archive | ||
| 16 | class SDMC_Factory final : public FileSystemFactory { | ||
| 17 | public: | ||
| 18 | explicit SDMC_Factory(std::string sd_directory); | ||
| 19 | |||
| 20 | std::string GetName() const override { | ||
| 21 | return "SDMC_Factory"; | ||
| 22 | } | ||
| 23 | ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override; | ||
| 24 | ResultCode Format(const Path& path) override; | ||
| 25 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 26 | |||
| 27 | private: | ||
| 28 | std::string sd_directory; | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // namespace FileSys | ||
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index ef05955b9..945832e98 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "common/file_util.h" | 6 | #include "common/file_util.h" |
| 7 | #include "core/file_sys/filesystem.h" | 7 | #include "core/file_sys/filesystem.h" |
| 8 | #include "core/file_sys/savedata_factory.h" | 8 | #include "core/file_sys/savedata_factory.h" |
| 9 | #include "core/file_sys/sdmc_factory.h" | ||
| 9 | #include "core/hle/service/filesystem/filesystem.h" | 10 | #include "core/hle/service/filesystem/filesystem.h" |
| 10 | #include "core/hle/service/filesystem/fsp_srv.h" | 11 | #include "core/hle/service/filesystem/fsp_srv.h" |
| 11 | 12 | ||
| @@ -60,9 +61,13 @@ void RegisterFileSystems() { | |||
| 60 | filesystem_map.clear(); | 61 | filesystem_map.clear(); |
| 61 | 62 | ||
| 62 | std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); | 63 | std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); |
| 64 | std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX); | ||
| 63 | 65 | ||
| 64 | auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory)); | 66 | auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory)); |
| 65 | RegisterFileSystem(std::move(savedata), Type::SaveData); | 67 | RegisterFileSystem(std::move(savedata), Type::SaveData); |
| 68 | |||
| 69 | auto sdcard = std::make_unique<FileSys::SDMC_Factory>(std::move(sd_directory)); | ||
| 70 | RegisterFileSystem(std::move(sdcard), Type::SDMC); | ||
| 66 | } | 71 | } |
| 67 | 72 | ||
| 68 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 73 | 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 8d30e94a1..56d26146e 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -26,6 +26,7 @@ namespace FileSystem { | |||
| 26 | enum class Type { | 26 | enum class Type { |
| 27 | RomFS = 1, | 27 | RomFS = 1, |
| 28 | SaveData = 2, | 28 | SaveData = 2, |
| 29 | SDMC = 3, | ||
| 29 | }; | 30 | }; |
| 30 | 31 | ||
| 31 | /** | 32 | /** |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index e5ce41671..41b8cbfd2 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <cinttypes> | 5 | #include <cinttypes> |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/file_sys/directory.h" | ||
| 8 | #include "core/file_sys/filesystem.h" | 9 | #include "core/file_sys/filesystem.h" |
| 9 | #include "core/file_sys/storage.h" | 10 | #include "core/file_sys/storage.h" |
| 10 | #include "core/hle/ipc_helpers.h" | 11 | #include "core/hle/ipc_helpers.h" |
| @@ -151,14 +152,66 @@ private: | |||
| 151 | } | 152 | } |
| 152 | }; | 153 | }; |
| 153 | 154 | ||
| 155 | class IDirectory final : public ServiceFramework<IDirectory> { | ||
| 156 | public: | ||
| 157 | explicit IDirectory(std::unique_ptr<FileSys::DirectoryBackend>&& backend) | ||
| 158 | : ServiceFramework("IDirectory"), backend(std::move(backend)) { | ||
| 159 | static const FunctionInfo functions[] = { | ||
| 160 | {0, &IDirectory::Read, "Read"}, | ||
| 161 | {1, &IDirectory::GetEntryCount, "GetEntryCount"}, | ||
| 162 | }; | ||
| 163 | RegisterHandlers(functions); | ||
| 164 | } | ||
| 165 | |||
| 166 | private: | ||
| 167 | std::unique_ptr<FileSys::DirectoryBackend> backend; | ||
| 168 | |||
| 169 | void Read(Kernel::HLERequestContext& ctx) { | ||
| 170 | IPC::RequestParser rp{ctx}; | ||
| 171 | const u64 unk = rp.Pop<u64>(); | ||
| 172 | |||
| 173 | LOG_DEBUG(Service_FS, "called, unk=0x%llx", unk); | ||
| 174 | |||
| 175 | // Calculate how many entries we can fit in the output buffer | ||
| 176 | u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); | ||
| 177 | |||
| 178 | // Read the data from the Directory backend | ||
| 179 | std::vector<FileSys::Entry> entries(count_entries); | ||
| 180 | u64 read_entries = backend->Read(count_entries, entries.data()); | ||
| 181 | |||
| 182 | // Convert the data into a byte array | ||
| 183 | std::vector<u8> output(entries.size() * sizeof(FileSys::Entry)); | ||
| 184 | std::memcpy(output.data(), entries.data(), output.size()); | ||
| 185 | |||
| 186 | // Write the data to memory | ||
| 187 | ctx.WriteBuffer(output); | ||
| 188 | |||
| 189 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 190 | rb.Push(RESULT_SUCCESS); | ||
| 191 | rb.Push(read_entries); | ||
| 192 | } | ||
| 193 | |||
| 194 | void GetEntryCount(Kernel::HLERequestContext& ctx) { | ||
| 195 | LOG_DEBUG(Service_FS, "called"); | ||
| 196 | |||
| 197 | u64 count = backend->GetEntryCount(); | ||
| 198 | |||
| 199 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 200 | rb.Push(RESULT_SUCCESS); | ||
| 201 | rb.Push(count); | ||
| 202 | } | ||
| 203 | }; | ||
| 204 | |||
| 154 | class IFileSystem final : public ServiceFramework<IFileSystem> { | 205 | class IFileSystem final : public ServiceFramework<IFileSystem> { |
| 155 | public: | 206 | public: |
| 156 | explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend) | 207 | explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend) |
| 157 | : ServiceFramework("IFileSystem"), backend(std::move(backend)) { | 208 | : ServiceFramework("IFileSystem"), backend(std::move(backend)) { |
| 158 | static const FunctionInfo functions[] = { | 209 | static const FunctionInfo functions[] = { |
| 159 | {0, &IFileSystem::CreateFile, "CreateFile"}, | 210 | {0, &IFileSystem::CreateFile, "CreateFile"}, |
| 211 | {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, | ||
| 160 | {7, &IFileSystem::GetEntryType, "GetEntryType"}, | 212 | {7, &IFileSystem::GetEntryType, "GetEntryType"}, |
| 161 | {8, &IFileSystem::OpenFile, "OpenFile"}, | 213 | {8, &IFileSystem::OpenFile, "OpenFile"}, |
| 214 | {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, | ||
| 162 | {10, &IFileSystem::Commit, "Commit"}, | 215 | {10, &IFileSystem::Commit, "Commit"}, |
| 163 | }; | 216 | }; |
| 164 | RegisterHandlers(functions); | 217 | RegisterHandlers(functions); |
| @@ -182,6 +235,20 @@ public: | |||
| 182 | rb.Push(backend->CreateFile(name, size)); | 235 | rb.Push(backend->CreateFile(name, size)); |
| 183 | } | 236 | } |
| 184 | 237 | ||
| 238 | void CreateDirectory(Kernel::HLERequestContext& ctx) { | ||
| 239 | IPC::RequestParser rp{ctx}; | ||
| 240 | |||
| 241 | auto file_buffer = ctx.ReadBuffer(); | ||
| 242 | auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); | ||
| 243 | |||
| 244 | std::string name(file_buffer.begin(), end); | ||
| 245 | |||
| 246 | LOG_DEBUG(Service_FS, "called directory %s", name.c_str()); | ||
| 247 | |||
| 248 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 249 | rb.Push(backend->CreateDirectory(name)); | ||
| 250 | } | ||
| 251 | |||
| 185 | void OpenFile(Kernel::HLERequestContext& ctx) { | 252 | void OpenFile(Kernel::HLERequestContext& ctx) { |
| 186 | IPC::RequestParser rp{ctx}; | 253 | IPC::RequestParser rp{ctx}; |
| 187 | 254 | ||
| @@ -208,6 +275,33 @@ public: | |||
| 208 | rb.PushIpcInterface<IFile>(std::move(file)); | 275 | rb.PushIpcInterface<IFile>(std::move(file)); |
| 209 | } | 276 | } |
| 210 | 277 | ||
| 278 | void OpenDirectory(Kernel::HLERequestContext& ctx) { | ||
| 279 | IPC::RequestParser rp{ctx}; | ||
| 280 | |||
| 281 | auto file_buffer = ctx.ReadBuffer(); | ||
| 282 | auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); | ||
| 283 | |||
| 284 | std::string name(file_buffer.begin(), end); | ||
| 285 | |||
| 286 | // TODO(Subv): Implement this filter. | ||
| 287 | u32 filter_flags = rp.Pop<u32>(); | ||
| 288 | |||
| 289 | LOG_DEBUG(Service_FS, "called directory %s filter %u", name.c_str(), filter_flags); | ||
| 290 | |||
| 291 | auto result = backend->OpenDirectory(name); | ||
| 292 | if (result.Failed()) { | ||
| 293 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 294 | rb.Push(result.Code()); | ||
| 295 | return; | ||
| 296 | } | ||
| 297 | |||
| 298 | auto directory = std::move(result.Unwrap()); | ||
| 299 | |||
| 300 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 301 | rb.Push(RESULT_SUCCESS); | ||
| 302 | rb.PushIpcInterface<IDirectory>(std::move(directory)); | ||
| 303 | } | ||
| 304 | |||
| 211 | void GetEntryType(Kernel::HLERequestContext& ctx) { | 305 | void GetEntryType(Kernel::HLERequestContext& ctx) { |
| 212 | IPC::RequestParser rp{ctx}; | 306 | IPC::RequestParser rp{ctx}; |
| 213 | 307 | ||
| @@ -274,10 +368,14 @@ void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) { | |||
| 274 | } | 368 | } |
| 275 | 369 | ||
| 276 | void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { | 370 | void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { |
| 277 | LOG_WARNING(Service_FS, "(STUBBED) called"); | 371 | LOG_DEBUG(Service_FS, "called"); |
| 278 | 372 | ||
| 279 | IPC::ResponseBuilder rb{ctx, 2}; | 373 | FileSys::Path unused; |
| 374 | auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap(); | ||
| 375 | |||
| 376 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 280 | rb.Push(RESULT_SUCCESS); | 377 | rb.Push(RESULT_SUCCESS); |
| 378 | rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); | ||
| 281 | } | 379 | } |
| 282 | 380 | ||
| 283 | void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { | 381 | void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { |