diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/file_sys/archive_backend.h | 30 | ||||
| -rw-r--r-- | src/core/file_sys/archive_romfs.cpp | 50 | ||||
| -rw-r--r-- | src/core/file_sys/archive_romfs.h | 33 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmc.cpp | 41 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmc.h | 30 | ||||
| -rw-r--r-- | src/core/file_sys/file_romfs.cpp | 19 | ||||
| -rw-r--r-- | src/core/file_sys/file_romfs.h | 8 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.cpp | 252 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.h | 26 | ||||
| -rw-r--r-- | src/core/hle/service/fs/fs_user.cpp | 93 | ||||
| -rw-r--r-- | src/core/loader/loader.cpp | 2 |
11 files changed, 197 insertions, 387 deletions
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 8d7a6a057..18c314884 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h | |||
| @@ -220,36 +220,6 @@ public: | |||
| 220 | * @return Opened directory, or nullptr | 220 | * @return Opened directory, or nullptr |
| 221 | */ | 221 | */ |
| 222 | virtual std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const = 0; | 222 | virtual std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const = 0; |
| 223 | |||
| 224 | /** | ||
| 225 | * Read data from the archive | ||
| 226 | * @param offset Offset in bytes to start reading data from | ||
| 227 | * @param length Length in bytes of data to read from archive | ||
| 228 | * @param buffer Buffer to read data into | ||
| 229 | * @return Number of bytes read | ||
| 230 | */ | ||
| 231 | virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; | ||
| 232 | |||
| 233 | /** | ||
| 234 | * Write data to the archive | ||
| 235 | * @param offset Offset in bytes to start writing data to | ||
| 236 | * @param length Length in bytes of data to write to archive | ||
| 237 | * @param buffer Buffer to write data from | ||
| 238 | * @param flush The flush parameters (0 == do not flush) | ||
| 239 | * @return Number of bytes written | ||
| 240 | */ | ||
| 241 | virtual size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) = 0; | ||
| 242 | |||
| 243 | /** | ||
| 244 | * Get the size of the archive in bytes | ||
| 245 | * @return Size of the archive in bytes | ||
| 246 | */ | ||
| 247 | virtual size_t GetSize() const = 0; | ||
| 248 | |||
| 249 | /** | ||
| 250 | * Set the size of the archive in bytes | ||
| 251 | */ | ||
| 252 | virtual void SetSize(const u64 size) = 0; | ||
| 253 | }; | 223 | }; |
| 254 | 224 | ||
| 255 | } // namespace FileSys | 225 | } // namespace FileSys |
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index c515e0dd9..0709b62a1 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 | 2 | // Licensed under GPLv2 |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <memory> | ||
| 6 | |||
| 5 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 6 | 8 | ||
| 7 | #include "core/file_sys/archive_romfs.h" | 9 | #include "core/file_sys/archive_romfs.h" |
| @@ -20,9 +22,6 @@ Archive_RomFS::Archive_RomFS(const Loader::AppLoader& app_loader) { | |||
| 20 | } | 22 | } |
| 21 | } | 23 | } |
| 22 | 24 | ||
| 23 | Archive_RomFS::~Archive_RomFS() { | ||
| 24 | } | ||
| 25 | |||
| 26 | /** | 25 | /** |
| 27 | * Open a file specified by its path, using the specified mode | 26 | * Open a file specified by its path, using the specified mode |
| 28 | * @param path Path relative to the archive | 27 | * @param path Path relative to the archive |
| @@ -30,7 +29,7 @@ Archive_RomFS::~Archive_RomFS() { | |||
| 30 | * @return Opened file, or nullptr | 29 | * @return Opened file, or nullptr |
| 31 | */ | 30 | */ |
| 32 | std::unique_ptr<FileBackend> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { | 31 | std::unique_ptr<FileBackend> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { |
| 33 | return std::unique_ptr<FileBackend>(new File_RomFS); | 32 | return std::make_unique<File_RomFS>(this); |
| 34 | } | 33 | } |
| 35 | 34 | ||
| 36 | /** | 35 | /** |
| @@ -79,48 +78,7 @@ bool Archive_RomFS::RenameDirectory(const FileSys::Path& src_path, const FileSys | |||
| 79 | * @return Opened directory, or nullptr | 78 | * @return Opened directory, or nullptr |
| 80 | */ | 79 | */ |
| 81 | std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) const { | 80 | std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) const { |
| 82 | return std::unique_ptr<DirectoryBackend>(new Directory_RomFS); | 81 | return std::make_unique<Directory_RomFS>(); |
| 83 | } | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Read data from the archive | ||
| 87 | * @param offset Offset in bytes to start reading data from | ||
| 88 | * @param length Length in bytes of data to read from archive | ||
| 89 | * @param buffer Buffer to read data into | ||
| 90 | * @return Number of bytes read | ||
| 91 | */ | ||
| 92 | size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { | ||
| 93 | LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); | ||
| 94 | memcpy(buffer, &raw_data[(u32)offset], length); | ||
| 95 | return length; | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * Write data to the archive | ||
| 100 | * @param offset Offset in bytes to start writing data to | ||
| 101 | * @param length Length in bytes of data to write to archive | ||
| 102 | * @param buffer Buffer to write data from | ||
| 103 | * @param flush The flush parameters (0 == do not flush) | ||
| 104 | * @return Number of bytes written | ||
| 105 | */ | ||
| 106 | size_t Archive_RomFS::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { | ||
| 107 | LOG_WARNING(Service_FS, "Attempted to write to ROMFS."); | ||
| 108 | return 0; | ||
| 109 | } | ||
| 110 | |||
| 111 | /** | ||
| 112 | * Get the size of the archive in bytes | ||
| 113 | * @return Size of the archive in bytes | ||
| 114 | */ | ||
| 115 | size_t Archive_RomFS::GetSize() const { | ||
| 116 | return sizeof(u8) * raw_data.size(); | ||
| 117 | } | ||
| 118 | |||
| 119 | /** | ||
| 120 | * Set the size of the archive in bytes | ||
| 121 | */ | ||
| 122 | void Archive_RomFS::SetSize(const u64 size) { | ||
| 123 | LOG_WARNING(Service_FS, "Attempted to set the size of ROMFS"); | ||
| 124 | } | 82 | } |
| 125 | 83 | ||
| 126 | } // namespace FileSys | 84 | } // namespace FileSys |
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 0390821bf..5b1ee6332 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h | |||
| @@ -20,7 +20,6 @@ namespace FileSys { | |||
| 20 | class Archive_RomFS final : public ArchiveBackend { | 20 | class Archive_RomFS final : public ArchiveBackend { |
| 21 | public: | 21 | public: |
| 22 | Archive_RomFS(const Loader::AppLoader& app_loader); | 22 | Archive_RomFS(const Loader::AppLoader& app_loader); |
| 23 | ~Archive_RomFS() override; | ||
| 24 | 23 | ||
| 25 | std::string GetName() const override { return "RomFS"; } | 24 | std::string GetName() const override { return "RomFS"; } |
| 26 | 25 | ||
| @@ -76,37 +75,9 @@ public: | |||
| 76 | */ | 75 | */ |
| 77 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 76 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 78 | 77 | ||
| 79 | /** | ||
| 80 | * Read data from the archive | ||
| 81 | * @param offset Offset in bytes to start reading data from | ||
| 82 | * @param length Length in bytes of data to read from archive | ||
| 83 | * @param buffer Buffer to read data into | ||
| 84 | * @return Number of bytes read | ||
| 85 | */ | ||
| 86 | size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | ||
| 87 | |||
| 88 | /** | ||
| 89 | * Write data to the archive | ||
| 90 | * @param offset Offset in bytes to start writing data to | ||
| 91 | * @param length Length in bytes of data to write to archive | ||
| 92 | * @param buffer Buffer to write data from | ||
| 93 | * @param flush The flush parameters (0 == do not flush) | ||
| 94 | * @return Number of bytes written | ||
| 95 | */ | ||
| 96 | size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; | ||
| 97 | |||
| 98 | /** | ||
| 99 | * Get the size of the archive in bytes | ||
| 100 | * @return Size of the archive in bytes | ||
| 101 | */ | ||
| 102 | size_t GetSize() const override; | ||
| 103 | |||
| 104 | /** | ||
| 105 | * Set the size of the archive in bytes | ||
| 106 | */ | ||
| 107 | void SetSize(const u64 size) override; | ||
| 108 | |||
| 109 | private: | 78 | private: |
| 79 | friend class File_RomFS; | ||
| 80 | |||
| 110 | std::vector<u8> raw_data; | 81 | std::vector<u8> raw_data; |
| 111 | }; | 82 | }; |
| 112 | 83 | ||
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 43252b98b..9d58668e0 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp | |||
| @@ -106,47 +106,6 @@ std::unique_ptr<DirectoryBackend> Archive_SDMC::OpenDirectory(const Path& path) | |||
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | /** | 108 | /** |
| 109 | * Read data from the archive | ||
| 110 | * @param offset Offset in bytes to start reading archive from | ||
| 111 | * @param length Length in bytes to read data from archive | ||
| 112 | * @param buffer Buffer to read data into | ||
| 113 | * @return Number of bytes read | ||
| 114 | */ | ||
| 115 | size_t Archive_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { | ||
| 116 | LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); | ||
| 117 | return -1; | ||
| 118 | } | ||
| 119 | |||
| 120 | /** | ||
| 121 | * Write data to the archive | ||
| 122 | * @param offset Offset in bytes to start writing data to | ||
| 123 | * @param length Length in bytes of data to write to archive | ||
| 124 | * @param buffer Buffer to write data from | ||
| 125 | * @param flush The flush parameters (0 == do not flush) | ||
| 126 | * @return Number of bytes written | ||
| 127 | */ | ||
| 128 | size_t Archive_SDMC::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { | ||
| 129 | LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); | ||
| 130 | return -1; | ||
| 131 | } | ||
| 132 | |||
| 133 | /** | ||
| 134 | * Get the size of the archive in bytes | ||
| 135 | * @return Size of the archive in bytes | ||
| 136 | */ | ||
| 137 | size_t Archive_SDMC::GetSize() const { | ||
| 138 | LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); | ||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | /** | ||
| 143 | * Set the size of the archive in bytes | ||
| 144 | */ | ||
| 145 | void Archive_SDMC::SetSize(const u64 size) { | ||
| 146 | LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); | ||
| 147 | } | ||
| 148 | |||
| 149 | /** | ||
| 150 | * Getter for the path used for this Archive | 109 | * Getter for the path used for this Archive |
| 151 | * @return Mount point of that passthrough archive | 110 | * @return Mount point of that passthrough archive |
| 152 | */ | 111 | */ |
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 5920051f7..059045245 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h | |||
| @@ -81,36 +81,6 @@ public: | |||
| 81 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 81 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 82 | 82 | ||
| 83 | /** | 83 | /** |
| 84 | * Read data from the archive | ||
| 85 | * @param offset Offset in bytes to start reading archive from | ||
| 86 | * @param length Length in bytes to read data from archive | ||
| 87 | * @param buffer Buffer to read data into | ||
| 88 | * @return Number of bytes read | ||
| 89 | */ | ||
| 90 | size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | ||
| 91 | |||
| 92 | /** | ||
| 93 | * Write data to the archive | ||
| 94 | * @param offset Offset in bytes to start writing data to | ||
| 95 | * @param length Length in bytes of data to write to archive | ||
| 96 | * @param buffer Buffer to write data from | ||
| 97 | * @param flush The flush parameters (0 == do not flush) | ||
| 98 | * @return Number of bytes written | ||
| 99 | */ | ||
| 100 | size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; | ||
| 101 | |||
| 102 | /** | ||
| 103 | * Get the size of the archive in bytes | ||
| 104 | * @return Size of the archive in bytes | ||
| 105 | */ | ||
| 106 | size_t GetSize() const override; | ||
| 107 | |||
| 108 | /** | ||
| 109 | * Set the size of the archive in bytes | ||
| 110 | */ | ||
| 111 | void SetSize(const u64 size) override; | ||
| 112 | |||
| 113 | /** | ||
| 114 | * Getter for the path used for this Archive | 84 | * Getter for the path used for this Archive |
| 115 | * @return Mount point of that passthrough archive | 85 | * @return Mount point of that passthrough archive |
| 116 | */ | 86 | */ |
diff --git a/src/core/file_sys/file_romfs.cpp b/src/core/file_sys/file_romfs.cpp index b55708df4..5f38c2704 100644 --- a/src/core/file_sys/file_romfs.cpp +++ b/src/core/file_sys/file_romfs.cpp | |||
| @@ -5,24 +5,19 @@ | |||
| 5 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 6 | 6 | ||
| 7 | #include "core/file_sys/file_romfs.h" | 7 | #include "core/file_sys/file_romfs.h" |
| 8 | #include "core/file_sys/archive_romfs.h" | ||
| 8 | 9 | ||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 10 | // FileSys namespace | 11 | // FileSys namespace |
| 11 | 12 | ||
| 12 | namespace FileSys { | 13 | namespace FileSys { |
| 13 | 14 | ||
| 14 | File_RomFS::File_RomFS() { | ||
| 15 | } | ||
| 16 | |||
| 17 | File_RomFS::~File_RomFS() { | ||
| 18 | } | ||
| 19 | |||
| 20 | /** | 15 | /** |
| 21 | * Open the file | 16 | * Open the file |
| 22 | * @return true if the file opened correctly | 17 | * @return true if the file opened correctly |
| 23 | */ | 18 | */ |
| 24 | bool File_RomFS::Open() { | 19 | bool File_RomFS::Open() { |
| 25 | return false; | 20 | return true; |
| 26 | } | 21 | } |
| 27 | 22 | ||
| 28 | /** | 23 | /** |
| @@ -33,7 +28,9 @@ bool File_RomFS::Open() { | |||
| 33 | * @return Number of bytes read | 28 | * @return Number of bytes read |
| 34 | */ | 29 | */ |
| 35 | size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { | 30 | size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { |
| 36 | return -1; | 31 | LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); |
| 32 | memcpy(buffer, &archive->raw_data[(u32)offset], length); | ||
| 33 | return length; | ||
| 37 | } | 34 | } |
| 38 | 35 | ||
| 39 | /** | 36 | /** |
| @@ -45,7 +42,8 @@ size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { | |||
| 45 | * @return Number of bytes written | 42 | * @return Number of bytes written |
| 46 | */ | 43 | */ |
| 47 | size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | 44 | size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { |
| 48 | return -1; | 45 | LOG_WARNING(Service_FS, "Attempted to write to ROMFS."); |
| 46 | return 0; | ||
| 49 | } | 47 | } |
| 50 | 48 | ||
| 51 | /** | 49 | /** |
| @@ -53,7 +51,7 @@ size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, co | |||
| 53 | * @return Size of the file in bytes | 51 | * @return Size of the file in bytes |
| 54 | */ | 52 | */ |
| 55 | size_t File_RomFS::GetSize() const { | 53 | size_t File_RomFS::GetSize() const { |
| 56 | return -1; | 54 | return sizeof(u8) * archive->raw_data.size(); |
| 57 | } | 55 | } |
| 58 | 56 | ||
| 59 | /** | 57 | /** |
| @@ -62,6 +60,7 @@ size_t File_RomFS::GetSize() const { | |||
| 62 | * @return true if successful | 60 | * @return true if successful |
| 63 | */ | 61 | */ |
| 64 | bool File_RomFS::SetSize(const u64 size) const { | 62 | bool File_RomFS::SetSize(const u64 size) const { |
| 63 | LOG_WARNING(Service_FS, "Attempted to set the size of ROMFS"); | ||
| 65 | return false; | 64 | return false; |
| 66 | } | 65 | } |
| 67 | 66 | ||
diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h index 4ddaafe21..09fa2e7e3 100644 --- a/src/core/file_sys/file_romfs.h +++ b/src/core/file_sys/file_romfs.h | |||
| @@ -14,10 +14,11 @@ | |||
| 14 | 14 | ||
| 15 | namespace FileSys { | 15 | namespace FileSys { |
| 16 | 16 | ||
| 17 | class Archive_RomFS; | ||
| 18 | |||
| 17 | class File_RomFS final : public FileBackend { | 19 | class File_RomFS final : public FileBackend { |
| 18 | public: | 20 | public: |
| 19 | File_RomFS(); | 21 | File_RomFS(const Archive_RomFS* archive) : archive(archive) {} |
| 20 | ~File_RomFS() override; | ||
| 21 | 22 | ||
| 22 | /** | 23 | /** |
| 23 | * Open the file | 24 | * Open the file |
| @@ -62,6 +63,9 @@ public: | |||
| 62 | * @return true if the file closed correctly | 63 | * @return true if the file closed correctly |
| 63 | */ | 64 | */ |
| 64 | bool Close() const override; | 65 | bool Close() const override; |
| 66 | |||
| 67 | private: | ||
| 68 | const Archive_RomFS* archive; | ||
| 65 | }; | 69 | }; |
| 66 | 70 | ||
| 67 | } // namespace FileSys | 71 | } // namespace FileSys |
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index d04e5b2e7..a4ee7a156 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -2,7 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 | 2 | // Licensed under GPLv2 |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <map> | 5 | #include <memory> |
| 6 | #include <unordered_map> | ||
| 6 | 7 | ||
| 7 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 8 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| @@ -41,74 +42,24 @@ enum class DirectoryCommand : u32 { | |||
| 41 | Close = 0x08020000, | 42 | Close = 0x08020000, |
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | class Archive : public Kernel::Session { | 45 | class Archive { |
| 45 | public: | 46 | public: |
| 46 | std::string GetName() const override { return "Archive: " + backend->GetName(); } | 47 | Archive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) |
| 47 | 48 | : backend(std::move(backend)), id_code(id_code) { | |
| 48 | ArchiveIdCode id_code; ///< Id code of the archive | 49 | } |
| 49 | FileSys::ArchiveBackend* backend; ///< Archive backend interface | ||
| 50 | |||
| 51 | ResultVal<bool> SyncRequest() override { | ||
| 52 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 53 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | ||
| 54 | |||
| 55 | switch (cmd) { | ||
| 56 | // Read from archive... | ||
| 57 | case FileCommand::Read: | ||
| 58 | { | ||
| 59 | u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32); | ||
| 60 | u32 length = cmd_buff[3]; | ||
| 61 | u32 address = cmd_buff[5]; | ||
| 62 | 50 | ||
| 63 | // Number of bytes read | 51 | std::string GetName() const { return "Archive: " + backend->GetName(); } |
| 64 | cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); | ||
| 65 | break; | ||
| 66 | } | ||
| 67 | // Write to archive... | ||
| 68 | case FileCommand::Write: | ||
| 69 | { | ||
| 70 | u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32); | ||
| 71 | u32 length = cmd_buff[3]; | ||
| 72 | u32 flush = cmd_buff[4]; | ||
| 73 | u32 address = cmd_buff[6]; | ||
| 74 | 52 | ||
| 75 | // Number of bytes written | 53 | ArchiveIdCode id_code; ///< Id code of the archive |
| 76 | cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); | 54 | std::unique_ptr<FileSys::ArchiveBackend> backend; ///< Archive backend interface |
| 77 | break; | ||
| 78 | } | ||
| 79 | case FileCommand::GetSize: | ||
| 80 | { | ||
| 81 | u64 filesize = (u64) backend->GetSize(); | ||
| 82 | cmd_buff[2] = (u32) filesize; // Lower word | ||
| 83 | cmd_buff[3] = (u32) (filesize >> 32); // Upper word | ||
| 84 | break; | ||
| 85 | } | ||
| 86 | case FileCommand::SetSize: | ||
| 87 | { | ||
| 88 | backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | case FileCommand::Close: | ||
| 92 | { | ||
| 93 | LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 94 | CloseArchive(id_code); | ||
| 95 | break; | ||
| 96 | } | ||
| 97 | // Unknown command... | ||
| 98 | default: | ||
| 99 | { | ||
| 100 | LOG_ERROR(Service_FS, "Unknown command=0x%08X", cmd); | ||
| 101 | cmd_buff[0] = UnimplementedFunction(ErrorModule::FS).raw; | ||
| 102 | return MakeResult<bool>(false); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | cmd_buff[1] = 0; // No error | ||
| 106 | return MakeResult<bool>(false); | ||
| 107 | } | ||
| 108 | }; | 55 | }; |
| 109 | 56 | ||
| 110 | class File : public Kernel::Session { | 57 | class File : public Kernel::Session { |
| 111 | public: | 58 | public: |
| 59 | File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path) | ||
| 60 | : backend(std::move(backend)), path(path) { | ||
| 61 | } | ||
| 62 | |||
| 112 | std::string GetName() const override { return "Path: " + path.DebugStr(); } | 63 | std::string GetName() const override { return "Path: " + path.DebugStr(); } |
| 113 | 64 | ||
| 114 | FileSys::Path path; ///< Path of the file | 65 | FileSys::Path path; ///< Path of the file |
| @@ -183,6 +134,10 @@ public: | |||
| 183 | 134 | ||
| 184 | class Directory : public Kernel::Session { | 135 | class Directory : public Kernel::Session { |
| 185 | public: | 136 | public: |
| 137 | Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path) | ||
| 138 | : backend(std::move(backend)), path(path) { | ||
| 139 | } | ||
| 140 | |||
| 186 | std::string GetName() const override { return "Directory: " + path.DebugStr(); } | 141 | std::string GetName() const override { return "Directory: " + path.DebugStr(); } |
| 187 | 142 | ||
| 188 | FileSys::Path path; ///< Path of the directory | 143 | FileSys::Path path; ///< Path of the directory |
| @@ -228,105 +183,95 @@ public: | |||
| 228 | 183 | ||
| 229 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 184 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 230 | 185 | ||
| 231 | std::map<ArchiveIdCode, Handle> g_archive_map; ///< Map of file archives by IdCode | 186 | /** |
| 187 | * Map of registered archives, identified by id code. Once an archive is registered here, it is | ||
| 188 | * never removed until the FS service is shut down. | ||
| 189 | */ | ||
| 190 | static std::unordered_map<ArchiveIdCode, std::unique_ptr<Archive>> id_code_map; | ||
| 232 | 191 | ||
| 233 | ResultVal<Handle> OpenArchive(ArchiveIdCode id_code) { | 192 | /** |
| 234 | auto itr = g_archive_map.find(id_code); | 193 | * Map of active archive handles. Values are pointers to the archives in `idcode_map`. |
| 235 | if (itr == g_archive_map.end()) { | 194 | */ |
| 195 | static std::unordered_map<ArchiveHandle, Archive*> handle_map; | ||
| 196 | static ArchiveHandle next_handle; | ||
| 197 | |||
| 198 | static Archive* GetArchive(ArchiveHandle handle) { | ||
| 199 | auto itr = handle_map.find(handle); | ||
| 200 | return (itr == handle_map.end()) ? nullptr : itr->second; | ||
| 201 | } | ||
| 202 | |||
| 203 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) { | ||
| 204 | LOG_TRACE(Service_FS, "Opening archive with id code 0x%08X", id_code); | ||
| 205 | |||
| 206 | auto itr = id_code_map.find(id_code); | ||
| 207 | if (itr == id_code_map.end()) { | ||
| 208 | // TODO: Verify error against hardware | ||
| 236 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | 209 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, |
| 237 | ErrorSummary::NotFound, ErrorLevel::Permanent); | 210 | ErrorSummary::NotFound, ErrorLevel::Permanent); |
| 238 | } | 211 | } |
| 239 | 212 | ||
| 240 | return MakeResult<Handle>(itr->second); | 213 | // This should never even happen in the first place with 64-bit handles, |
| 214 | while (handle_map.count(next_handle) != 0) { | ||
| 215 | ++next_handle; | ||
| 216 | } | ||
| 217 | handle_map.emplace(next_handle, itr->second.get()); | ||
| 218 | return MakeResult<ArchiveHandle>(next_handle++); | ||
| 241 | } | 219 | } |
| 242 | 220 | ||
| 243 | ResultCode CloseArchive(ArchiveIdCode id_code) { | 221 | ResultCode CloseArchive(ArchiveHandle handle) { |
| 244 | auto itr = g_archive_map.find(id_code); | 222 | if (handle_map.erase(handle) == 0) |
| 245 | if (itr == g_archive_map.end()) { | ||
| 246 | LOG_ERROR(Service_FS, "Cannot close archive %d, does not exist!", (int)id_code); | ||
| 247 | return InvalidHandle(ErrorModule::FS); | 223 | return InvalidHandle(ErrorModule::FS); |
| 248 | } | 224 | else |
| 249 | 225 | return RESULT_SUCCESS; | |
| 250 | LOG_TRACE(Service_FS, "Closed archive %d", (int) id_code); | ||
| 251 | return RESULT_SUCCESS; | ||
| 252 | } | 226 | } |
| 253 | 227 | ||
| 254 | /** | 228 | // TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in |
| 255 | * Mounts an archive | 229 | // http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22 |
| 256 | * @param archive Pointer to the archive to mount | 230 | ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) { |
| 257 | */ | 231 | auto result = id_code_map.emplace(id_code, std::make_unique<Archive>(std::move(backend), id_code)); |
| 258 | ResultCode MountArchive(Archive* archive) { | ||
| 259 | ArchiveIdCode id_code = archive->id_code; | ||
| 260 | ResultVal<Handle> archive_handle = OpenArchive(id_code); | ||
| 261 | if (archive_handle.Succeeded()) { | ||
| 262 | LOG_ERROR(Service_FS, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); | ||
| 263 | return archive_handle.Code(); | ||
| 264 | } | ||
| 265 | g_archive_map[id_code] = archive->GetHandle(); | ||
| 266 | LOG_TRACE(Service_FS, "Mounted archive %s", archive->GetName().c_str()); | ||
| 267 | return RESULT_SUCCESS; | ||
| 268 | } | ||
| 269 | 232 | ||
| 270 | ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code) { | 233 | bool inserted = result.second; |
| 271 | Archive* archive = new Archive; | 234 | _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); |
| 272 | Handle handle = Kernel::g_object_pool.Create(archive); | ||
| 273 | archive->id_code = id_code; | ||
| 274 | archive->backend = backend; | ||
| 275 | 235 | ||
| 276 | ResultCode result = MountArchive(archive); | 236 | auto& archive = result.first->second; |
| 277 | if (result.IsError()) { | 237 | LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(), id_code); |
| 278 | return result; | ||
| 279 | } | ||
| 280 | |||
| 281 | return RESULT_SUCCESS; | 238 | return RESULT_SUCCESS; |
| 282 | } | 239 | } |
| 283 | 240 | ||
| 284 | ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { | 241 | ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { |
| 285 | // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create | 242 | Archive* archive = GetArchive(archive_handle); |
| 286 | // the archive file handles at app loading, and then keep them persistent throughout execution. | 243 | if (archive == nullptr) |
| 287 | // Archives file handles are just reused and not actually freed until emulation shut down. | ||
| 288 | // Verify if real hardware works this way, or if new handles are created each time | ||
| 289 | if (path.GetType() == FileSys::Binary) | ||
| 290 | // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend | ||
| 291 | // design. While the functionally of this is OK, our implementation decision to separate | ||
| 292 | // normal files from archive file pointers is very likely wrong. | ||
| 293 | // See https://github.com/citra-emu/citra/issues/205 | ||
| 294 | return MakeResult<Handle>(archive_handle); | ||
| 295 | |||
| 296 | File* file = new File; | ||
| 297 | Handle handle = Kernel::g_object_pool.Create(file); | ||
| 298 | |||
| 299 | Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); | ||
| 300 | if (archive == nullptr) { | ||
| 301 | return InvalidHandle(ErrorModule::FS); | 244 | return InvalidHandle(ErrorModule::FS); |
| 302 | } | ||
| 303 | file->path = path; | ||
| 304 | file->backend = archive->backend->OpenFile(path, mode); | ||
| 305 | 245 | ||
| 306 | if (!file->backend) { | 246 | std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); |
| 247 | if (backend == nullptr) { | ||
| 307 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | 248 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, |
| 308 | ErrorSummary::NotFound, ErrorLevel::Permanent); | 249 | ErrorSummary::NotFound, ErrorLevel::Permanent); |
| 309 | } | 250 | } |
| 310 | 251 | ||
| 252 | auto file = std::make_unique<File>(std::move(backend), path); | ||
| 253 | Handle handle = Kernel::g_object_pool.Create(file.release()); | ||
| 311 | return MakeResult<Handle>(handle); | 254 | return MakeResult<Handle>(handle); |
| 312 | } | 255 | } |
| 313 | 256 | ||
| 314 | ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) { | 257 | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 315 | Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | 258 | Archive* archive = GetArchive(archive_handle); |
| 316 | if (archive == nullptr) | 259 | if (archive == nullptr) |
| 317 | return InvalidHandle(ErrorModule::FS); | 260 | return InvalidHandle(ErrorModule::FS); |
| 261 | |||
| 318 | if (archive->backend->DeleteFile(path)) | 262 | if (archive->backend->DeleteFile(path)) |
| 319 | return RESULT_SUCCESS; | 263 | return RESULT_SUCCESS; |
| 320 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | 264 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description |
| 321 | ErrorSummary::Canceled, ErrorLevel::Status); | 265 | ErrorSummary::Canceled, ErrorLevel::Status); |
| 322 | } | 266 | } |
| 323 | 267 | ||
| 324 | ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, | 268 | ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, |
| 325 | Handle dest_archive_handle, const FileSys::Path& dest_path) { | 269 | ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { |
| 326 | Archive* src_archive = Kernel::g_object_pool.GetFast<Archive>(src_archive_handle); | 270 | Archive* src_archive = GetArchive(src_archive_handle); |
| 327 | Archive* dest_archive = Kernel::g_object_pool.GetFast<Archive>(dest_archive_handle); | 271 | Archive* dest_archive = GetArchive(dest_archive_handle); |
| 328 | if (src_archive == nullptr || dest_archive == nullptr) | 272 | if (src_archive == nullptr || dest_archive == nullptr) |
| 329 | return InvalidHandle(ErrorModule::FS); | 273 | return InvalidHandle(ErrorModule::FS); |
| 274 | |||
| 330 | if (src_archive == dest_archive) { | 275 | if (src_archive == dest_archive) { |
| 331 | if (src_archive->backend->RenameFile(src_path, dest_path)) | 276 | if (src_archive->backend->RenameFile(src_path, dest_path)) |
| 332 | return RESULT_SUCCESS; | 277 | return RESULT_SUCCESS; |
| @@ -334,36 +279,42 @@ ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::P | |||
| 334 | // TODO: Implement renaming across archives | 279 | // TODO: Implement renaming across archives |
| 335 | return UnimplementedFunction(ErrorModule::FS); | 280 | return UnimplementedFunction(ErrorModule::FS); |
| 336 | } | 281 | } |
| 282 | |||
| 283 | // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't | ||
| 284 | // exist or similar. Verify. | ||
| 337 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | 285 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description |
| 338 | ErrorSummary::NothingHappened, ErrorLevel::Status); | 286 | ErrorSummary::NothingHappened, ErrorLevel::Status); |
| 339 | } | 287 | } |
| 340 | 288 | ||
| 341 | ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { | 289 | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 342 | Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | 290 | Archive* archive = GetArchive(archive_handle); |
| 343 | if (archive == nullptr) | 291 | if (archive == nullptr) |
| 344 | return InvalidHandle(ErrorModule::FS); | 292 | return InvalidHandle(ErrorModule::FS); |
| 293 | |||
| 345 | if (archive->backend->DeleteDirectory(path)) | 294 | if (archive->backend->DeleteDirectory(path)) |
| 346 | return RESULT_SUCCESS; | 295 | return RESULT_SUCCESS; |
| 347 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | 296 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description |
| 348 | ErrorSummary::Canceled, ErrorLevel::Status); | 297 | ErrorSummary::Canceled, ErrorLevel::Status); |
| 349 | } | 298 | } |
| 350 | 299 | ||
| 351 | ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { | 300 | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 352 | Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | 301 | Archive* archive = GetArchive(archive_handle); |
| 353 | if (archive == nullptr) | 302 | if (archive == nullptr) |
| 354 | return InvalidHandle(ErrorModule::FS); | 303 | return InvalidHandle(ErrorModule::FS); |
| 304 | |||
| 355 | if (archive->backend->CreateDirectory(path)) | 305 | if (archive->backend->CreateDirectory(path)) |
| 356 | return RESULT_SUCCESS; | 306 | return RESULT_SUCCESS; |
| 357 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | 307 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description |
| 358 | ErrorSummary::Canceled, ErrorLevel::Status); | 308 | ErrorSummary::Canceled, ErrorLevel::Status); |
| 359 | } | 309 | } |
| 360 | 310 | ||
| 361 | ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, | 311 | ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, |
| 362 | Handle dest_archive_handle, const FileSys::Path& dest_path) { | 312 | ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { |
| 363 | Archive* src_archive = Kernel::g_object_pool.GetFast<Archive>(src_archive_handle); | 313 | Archive* src_archive = GetArchive(src_archive_handle); |
| 364 | Archive* dest_archive = Kernel::g_object_pool.GetFast<Archive>(dest_archive_handle); | 314 | Archive* dest_archive = GetArchive(dest_archive_handle); |
| 365 | if (src_archive == nullptr || dest_archive == nullptr) | 315 | if (src_archive == nullptr || dest_archive == nullptr) |
| 366 | return InvalidHandle(ErrorModule::FS); | 316 | return InvalidHandle(ErrorModule::FS); |
| 317 | |||
| 367 | if (src_archive == dest_archive) { | 318 | if (src_archive == dest_archive) { |
| 368 | if (src_archive->backend->RenameDirectory(src_path, dest_path)) | 319 | if (src_archive->backend->RenameDirectory(src_path, dest_path)) |
| 369 | return RESULT_SUCCESS; | 320 | return RESULT_SUCCESS; |
| @@ -371,6 +322,9 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS | |||
| 371 | // TODO: Implement renaming across archives | 322 | // TODO: Implement renaming across archives |
| 372 | return UnimplementedFunction(ErrorModule::FS); | 323 | return UnimplementedFunction(ErrorModule::FS); |
| 373 | } | 324 | } |
| 325 | |||
| 326 | // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't | ||
| 327 | // exist or similar. Verify. | ||
| 374 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | 328 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description |
| 375 | ErrorSummary::NothingHappened, ErrorLevel::Status); | 329 | ErrorSummary::NothingHappened, ErrorLevel::Status); |
| 376 | } | 330 | } |
| @@ -381,44 +335,42 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS | |||
| 381 | * @param path Path to the Directory inside of the Archive | 335 | * @param path Path to the Directory inside of the Archive |
| 382 | * @return Opened Directory object | 336 | * @return Opened Directory object |
| 383 | */ | 337 | */ |
| 384 | ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { | 338 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 385 | Directory* directory = new Directory; | 339 | Archive* archive = GetArchive(archive_handle); |
| 386 | Handle handle = Kernel::g_object_pool.Create(directory); | 340 | if (archive == nullptr) |
| 387 | |||
| 388 | Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); | ||
| 389 | if (archive == nullptr) { | ||
| 390 | return InvalidHandle(ErrorModule::FS); | 341 | return InvalidHandle(ErrorModule::FS); |
| 391 | } | ||
| 392 | directory->path = path; | ||
| 393 | directory->backend = archive->backend->OpenDirectory(path); | ||
| 394 | 342 | ||
| 395 | if (!directory->backend) { | 343 | std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); |
| 344 | if (backend == nullptr) { | ||
| 396 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | 345 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, |
| 397 | ErrorSummary::NotFound, ErrorLevel::Permanent); | 346 | ErrorSummary::NotFound, ErrorLevel::Permanent); |
| 398 | } | 347 | } |
| 399 | 348 | ||
| 349 | auto directory = std::make_unique<Directory>(std::move(backend), path); | ||
| 350 | Handle handle = Kernel::g_object_pool.Create(directory.release()); | ||
| 400 | return MakeResult<Handle>(handle); | 351 | return MakeResult<Handle>(handle); |
| 401 | } | 352 | } |
| 402 | 353 | ||
| 403 | /// Initialize archives | 354 | /// Initialize archives |
| 404 | void ArchiveInit() { | 355 | void ArchiveInit() { |
| 405 | g_archive_map.clear(); | 356 | next_handle = 1; |
| 406 | 357 | ||
| 407 | // TODO(Link Mauve): Add the other archive types (see here for the known types: | 358 | // TODO(Link Mauve): Add the other archive types (see here for the known types: |
| 408 | // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished | 359 | // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished |
| 409 | // archive type is SDMC, so it is the only one getting exposed. | 360 | // archive type is SDMC, so it is the only one getting exposed. |
| 410 | 361 | ||
| 411 | std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); | 362 | std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); |
| 412 | auto archive = new FileSys::Archive_SDMC(sdmc_directory); | 363 | auto archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); |
| 413 | if (archive->Initialize()) | 364 | if (archive->Initialize()) |
| 414 | CreateArchive(archive, ArchiveIdCode::SDMC); | 365 | CreateArchive(std::move(archive), ArchiveIdCode::SDMC); |
| 415 | else | 366 | else |
| 416 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | 367 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); |
| 417 | } | 368 | } |
| 418 | 369 | ||
| 419 | /// Shutdown archives | 370 | /// Shutdown archives |
| 420 | void ArchiveShutdown() { | 371 | void ArchiveShutdown() { |
| 421 | g_archive_map.clear(); | 372 | handle_map.clear(); |
| 373 | id_code_map.clear(); | ||
| 422 | } | 374 | } |
| 423 | 375 | ||
| 424 | } // namespace FS | 376 | } // namespace FS |
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 2c50dfff0..a38de92e3 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -24,25 +24,27 @@ enum class ArchiveIdCode : u32 { | |||
| 24 | SDMCWriteOnly = 0x0000000A, | 24 | SDMCWriteOnly = 0x0000000A, |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | typedef u64 ArchiveHandle; | ||
| 28 | |||
| 27 | /** | 29 | /** |
| 28 | * Opens an archive | 30 | * Opens an archive |
| 29 | * @param id_code IdCode of the archive to open | 31 | * @param id_code IdCode of the archive to open |
| 30 | * @return Handle to the opened archive | 32 | * @return Handle to the opened archive |
| 31 | */ | 33 | */ |
| 32 | ResultVal<Handle> OpenArchive(ArchiveIdCode id_code); | 34 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code); |
| 33 | 35 | ||
| 34 | /** | 36 | /** |
| 35 | * Closes an archive | 37 | * Closes an archive |
| 36 | * @param id_code IdCode of the archive to open | 38 | * @param id_code IdCode of the archive to open |
| 37 | */ | 39 | */ |
| 38 | ResultCode CloseArchive(ArchiveIdCode id_code); | 40 | ResultCode CloseArchive(ArchiveHandle handle); |
| 39 | 41 | ||
| 40 | /** | 42 | /** |
| 41 | * Creates an Archive | 43 | * Creates an Archive |
| 42 | * @param backend File system backend interface to the archive | 44 | * @param backend File system backend interface to the archive |
| 43 | * @param id_code Id code used to access this type of archive | 45 | * @param id_code Id code used to access this type of archive |
| 44 | */ | 46 | */ |
| 45 | ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code); | 47 | ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code); |
| 46 | 48 | ||
| 47 | /** | 49 | /** |
| 48 | * Open a File from an Archive | 50 | * Open a File from an Archive |
| @@ -51,7 +53,7 @@ ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code | |||
| 51 | * @param mode Mode under which to open the File | 53 | * @param mode Mode under which to open the File |
| 52 | * @return Handle to the opened File object | 54 | * @return Handle to the opened File object |
| 53 | */ | 55 | */ |
| 54 | ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); | 56 | ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); |
| 55 | 57 | ||
| 56 | /** | 58 | /** |
| 57 | * Delete a File from an Archive | 59 | * Delete a File from an Archive |
| @@ -59,7 +61,7 @@ ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path | |||
| 59 | * @param path Path to the File inside of the Archive | 61 | * @param path Path to the File inside of the Archive |
| 60 | * @return Whether deletion succeeded | 62 | * @return Whether deletion succeeded |
| 61 | */ | 63 | */ |
| 62 | ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path); | 64 | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); |
| 63 | 65 | ||
| 64 | /** | 66 | /** |
| 65 | * Rename a File between two Archives | 67 | * Rename a File between two Archives |
| @@ -69,8 +71,8 @@ ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& pat | |||
| 69 | * @param dest_path Path to the File inside of the destination Archive | 71 | * @param dest_path Path to the File inside of the destination Archive |
| 70 | * @return Whether rename succeeded | 72 | * @return Whether rename succeeded |
| 71 | */ | 73 | */ |
| 72 | ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, | 74 | ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, |
| 73 | Handle dest_archive_handle, const FileSys::Path& dest_path); | 75 | ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path); |
| 74 | 76 | ||
| 75 | /** | 77 | /** |
| 76 | * Delete a Directory from an Archive | 78 | * Delete a Directory from an Archive |
| @@ -78,7 +80,7 @@ ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::P | |||
| 78 | * @param path Path to the Directory inside of the Archive | 80 | * @param path Path to the Directory inside of the Archive |
| 79 | * @return Whether deletion succeeded | 81 | * @return Whether deletion succeeded |
| 80 | */ | 82 | */ |
| 81 | ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); | 83 | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); |
| 82 | 84 | ||
| 83 | /** | 85 | /** |
| 84 | * Create a Directory from an Archive | 86 | * Create a Directory from an Archive |
| @@ -86,7 +88,7 @@ ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path | |||
| 86 | * @param path Path to the Directory inside of the Archive | 88 | * @param path Path to the Directory inside of the Archive |
| 87 | * @return Whether creation of directory succeeded | 89 | * @return Whether creation of directory succeeded |
| 88 | */ | 90 | */ |
| 89 | ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); | 91 | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); |
| 90 | 92 | ||
| 91 | /** | 93 | /** |
| 92 | * Rename a Directory between two Archives | 94 | * Rename a Directory between two Archives |
| @@ -96,8 +98,8 @@ ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path | |||
| 96 | * @param dest_path Path to the Directory inside of the destination Archive | 98 | * @param dest_path Path to the Directory inside of the destination Archive |
| 97 | * @return Whether rename succeeded | 99 | * @return Whether rename succeeded |
| 98 | */ | 100 | */ |
| 99 | ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, | 101 | ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, |
| 100 | Handle dest_archive_handle, const FileSys::Path& dest_path); | 102 | ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path); |
| 101 | 103 | ||
| 102 | /** | 104 | /** |
| 103 | * Open a Directory from an Archive | 105 | * Open a Directory from an Archive |
| @@ -105,7 +107,7 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS | |||
| 105 | * @param path Path to the Directory inside of the Archive | 107 | * @param path Path to the Directory inside of the Archive |
| 106 | * @return Handle to the opened File object | 108 | * @return Handle to the opened File object |
| 107 | */ | 109 | */ |
| 108 | ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); | 110 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); |
| 109 | 111 | ||
| 110 | /// Initialize archives | 112 | /// Initialize archives |
| 111 | void ArchiveInit(); | 113 | void ArchiveInit(); |
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index eda7cb8ab..0f75d5e3a 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/common.h" | 5 | #include "common/common.h" |
| 6 | #include "common/scope_exit.h" | ||
| 6 | 7 | ||
| 7 | #include "common/string_util.h" | 8 | #include "common/string_util.h" |
| 8 | #include "core/hle/service/fs/archive.h" | 9 | #include "core/hle/service/fs/archive.h" |
| @@ -16,6 +17,10 @@ | |||
| 16 | namespace Service { | 17 | namespace Service { |
| 17 | namespace FS { | 18 | namespace FS { |
| 18 | 19 | ||
| 20 | static ArchiveHandle MakeArchiveHandle(u32 low_word, u32 high_word) { | ||
| 21 | return (u64)low_word | ((u64)high_word << 32); | ||
| 22 | } | ||
| 23 | |||
| 19 | static void Initialize(Service::Interface* self) { | 24 | static void Initialize(Service::Interface* self) { |
| 20 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 25 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 21 | 26 | ||
| @@ -62,6 +67,7 @@ static void OpenFile(Service::Interface* self) { | |||
| 62 | if (handle.Succeeded()) { | 67 | if (handle.Succeeded()) { |
| 63 | cmd_buff[3] = *handle; | 68 | cmd_buff[3] = *handle; |
| 64 | } else { | 69 | } else { |
| 70 | cmd_buff[3] = 0; | ||
| 65 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | 71 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); |
| 66 | } | 72 | } |
| 67 | } | 73 | } |
| @@ -106,25 +112,25 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 106 | if (archive_path.GetType() != FileSys::Empty) { | 112 | if (archive_path.GetType() != FileSys::Empty) { |
| 107 | LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); | 113 | LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); |
| 108 | cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | 114 | cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; |
| 115 | cmd_buff[3] = 0; | ||
| 109 | return; | 116 | return; |
| 110 | } | 117 | } |
| 111 | 118 | ||
| 112 | // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it | 119 | ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id); |
| 113 | // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here? | ||
| 114 | ResultVal<Handle> archive_handle = OpenArchive(archive_id); | ||
| 115 | cmd_buff[1] = archive_handle.Code().raw; | ||
| 116 | if (archive_handle.Failed()) { | 120 | if (archive_handle.Failed()) { |
| 117 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); | 121 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); |
| 122 | cmd_buff[1] = archive_handle.Code().raw; | ||
| 123 | cmd_buff[3] = 0; | ||
| 118 | return; | 124 | return; |
| 119 | } | 125 | } |
| 120 | // cmd_buff[2] isn't used according to 3dmoo's implementation. | 126 | SCOPE_EXIT({ CloseArchive(*archive_handle); }); |
| 121 | cmd_buff[3] = *archive_handle; | ||
| 122 | 127 | ||
| 123 | ResultVal<Handle> handle = OpenFileFromArchive(*archive_handle, file_path, mode); | 128 | ResultVal<Handle> handle = OpenFileFromArchive(*archive_handle, file_path, mode); |
| 124 | cmd_buff[1] = handle.Code().raw; | 129 | cmd_buff[1] = handle.Code().raw; |
| 125 | if (handle.Succeeded()) { | 130 | if (handle.Succeeded()) { |
| 126 | cmd_buff[3] = *handle; | 131 | cmd_buff[3] = *handle; |
| 127 | } else { | 132 | } else { |
| 133 | cmd_buff[3] = 0; | ||
| 128 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | 134 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); |
| 129 | } | 135 | } |
| 130 | } | 136 | } |
| @@ -140,12 +146,10 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 140 | * Outputs: | 146 | * Outputs: |
| 141 | * 1 : Result of function, 0 on success, otherwise error code | 147 | * 1 : Result of function, 0 on success, otherwise error code |
| 142 | */ | 148 | */ |
| 143 | void DeleteFile(Service::Interface* self) { | 149 | static void DeleteFile(Service::Interface* self) { |
| 144 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 150 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 145 | 151 | ||
| 146 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | 152 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 147 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 148 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 149 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 153 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 150 | u32 filename_size = cmd_buff[5]; | 154 | u32 filename_size = cmd_buff[5]; |
| 151 | u32 filename_ptr = cmd_buff[7]; | 155 | u32 filename_ptr = cmd_buff[7]; |
| @@ -174,15 +178,13 @@ void DeleteFile(Service::Interface* self) { | |||
| 174 | * Outputs: | 178 | * Outputs: |
| 175 | * 1 : Result of function, 0 on success, otherwise error code | 179 | * 1 : Result of function, 0 on success, otherwise error code |
| 176 | */ | 180 | */ |
| 177 | void RenameFile(Service::Interface* self) { | 181 | static void RenameFile(Service::Interface* self) { |
| 178 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 182 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 179 | 183 | ||
| 180 | // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to | 184 | ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 181 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 182 | Handle src_archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 183 | auto src_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 185 | auto src_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 184 | u32 src_filename_size = cmd_buff[5]; | 186 | u32 src_filename_size = cmd_buff[5]; |
| 185 | Handle dest_archive_handle = static_cast<Handle>(cmd_buff[7]); | 187 | ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);; |
| 186 | auto dest_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[8]); | 188 | auto dest_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[8]); |
| 187 | u32 dest_filename_size = cmd_buff[9]; | 189 | u32 dest_filename_size = cmd_buff[9]; |
| 188 | u32 src_filename_ptr = cmd_buff[11]; | 190 | u32 src_filename_ptr = cmd_buff[11]; |
| @@ -209,12 +211,10 @@ void RenameFile(Service::Interface* self) { | |||
| 209 | * Outputs: | 211 | * Outputs: |
| 210 | * 1 : Result of function, 0 on success, otherwise error code | 212 | * 1 : Result of function, 0 on success, otherwise error code |
| 211 | */ | 213 | */ |
| 212 | void DeleteDirectory(Service::Interface* self) { | 214 | static void DeleteDirectory(Service::Interface* self) { |
| 213 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 215 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 214 | 216 | ||
| 215 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | 217 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 216 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 217 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 218 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 218 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 219 | u32 dirname_size = cmd_buff[5]; | 219 | u32 dirname_size = cmd_buff[5]; |
| 220 | u32 dirname_ptr = cmd_buff[7]; | 220 | u32 dirname_ptr = cmd_buff[7]; |
| @@ -241,9 +241,7 @@ void DeleteDirectory(Service::Interface* self) { | |||
| 241 | static void CreateDirectory(Service::Interface* self) { | 241 | static void CreateDirectory(Service::Interface* self) { |
| 242 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 242 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 243 | 243 | ||
| 244 | // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to | 244 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 245 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 246 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 247 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 245 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 248 | u32 dirname_size = cmd_buff[5]; | 246 | u32 dirname_size = cmd_buff[5]; |
| 249 | u32 dirname_ptr = cmd_buff[8]; | 247 | u32 dirname_ptr = cmd_buff[8]; |
| @@ -271,15 +269,13 @@ static void CreateDirectory(Service::Interface* self) { | |||
| 271 | * Outputs: | 269 | * Outputs: |
| 272 | * 1 : Result of function, 0 on success, otherwise error code | 270 | * 1 : Result of function, 0 on success, otherwise error code |
| 273 | */ | 271 | */ |
| 274 | void RenameDirectory(Service::Interface* self) { | 272 | static void RenameDirectory(Service::Interface* self) { |
| 275 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 273 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 276 | 274 | ||
| 277 | // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to | 275 | ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 278 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 279 | Handle src_archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 280 | auto src_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 276 | auto src_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 281 | u32 src_dirname_size = cmd_buff[5]; | 277 | u32 src_dirname_size = cmd_buff[5]; |
| 282 | Handle dest_archive_handle = static_cast<Handle>(cmd_buff[7]); | 278 | ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]); |
| 283 | auto dest_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[8]); | 279 | auto dest_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[8]); |
| 284 | u32 dest_dirname_size = cmd_buff[9]; | 280 | u32 dest_dirname_size = cmd_buff[9]; |
| 285 | u32 src_dirname_ptr = cmd_buff[11]; | 281 | u32 src_dirname_ptr = cmd_buff[11]; |
| @@ -295,12 +291,23 @@ void RenameDirectory(Service::Interface* self) { | |||
| 295 | cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; | 291 | cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; |
| 296 | } | 292 | } |
| 297 | 293 | ||
| 294 | /** | ||
| 295 | * FS_User::OpenDirectory service function | ||
| 296 | * Inputs: | ||
| 297 | * 1 : Archive handle low word | ||
| 298 | * 2 : Archive handle high word | ||
| 299 | * 3 : Low path type | ||
| 300 | * 4 : Low path size | ||
| 301 | * 7 : (LowPathSize << 14) | 2 | ||
| 302 | * 8 : Low path data pointer | ||
| 303 | * Outputs: | ||
| 304 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 305 | * 3 : Directory handle | ||
| 306 | */ | ||
| 298 | static void OpenDirectory(Service::Interface* self) { | 307 | static void OpenDirectory(Service::Interface* self) { |
| 299 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 308 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 300 | 309 | ||
| 301 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | 310 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); |
| 302 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 303 | Handle archive_handle = static_cast<Handle>(cmd_buff[2]); | ||
| 304 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); | 311 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); |
| 305 | u32 dirname_size = cmd_buff[4]; | 312 | u32 dirname_size = cmd_buff[4]; |
| 306 | u32 dirname_ptr = cmd_buff[6]; | 313 | u32 dirname_ptr = cmd_buff[6]; |
| @@ -348,16 +355,34 @@ static void OpenArchive(Service::Interface* self) { | |||
| 348 | return; | 355 | return; |
| 349 | } | 356 | } |
| 350 | 357 | ||
| 351 | ResultVal<Handle> handle = OpenArchive(archive_id); | 358 | ResultVal<ArchiveHandle> handle = OpenArchive(archive_id); |
| 352 | cmd_buff[1] = handle.Code().raw; | 359 | cmd_buff[1] = handle.Code().raw; |
| 353 | if (handle.Succeeded()) { | 360 | if (handle.Succeeded()) { |
| 354 | // cmd_buff[2] isn't used according to 3dmoo's implementation. | 361 | cmd_buff[2] = *handle & 0xFFFFFFFF; |
| 355 | cmd_buff[3] = *handle; | 362 | cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF; |
| 356 | } else { | 363 | } else { |
| 364 | cmd_buff[2] = cmd_buff[3] = 0; | ||
| 357 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); | 365 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); |
| 358 | } | 366 | } |
| 359 | } | 367 | } |
| 360 | 368 | ||
| 369 | /** | ||
| 370 | * FS_User::CloseArchive service function | ||
| 371 | * Inputs: | ||
| 372 | * 0 : 0x080E0080 | ||
| 373 | * 1 : Archive handle low word | ||
| 374 | * 2 : Archive handle high word | ||
| 375 | * Outputs: | ||
| 376 | * 0 : ??? TODO(yuriks): Verify return header | ||
| 377 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 378 | */ | ||
| 379 | static void CloseArchive(Service::Interface* self) { | ||
| 380 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 381 | |||
| 382 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); | ||
| 383 | cmd_buff[1] = CloseArchive(archive_handle).raw; | ||
| 384 | } | ||
| 385 | |||
| 361 | /* | 386 | /* |
| 362 | * FS_User::IsSdmcDetected service function | 387 | * FS_User::IsSdmcDetected service function |
| 363 | * Outputs: | 388 | * Outputs: |
| @@ -389,7 +414,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { | |||
| 389 | {0x080B0102, OpenDirectory, "OpenDirectory"}, | 414 | {0x080B0102, OpenDirectory, "OpenDirectory"}, |
| 390 | {0x080C00C2, OpenArchive, "OpenArchive"}, | 415 | {0x080C00C2, OpenArchive, "OpenArchive"}, |
| 391 | {0x080D0144, nullptr, "ControlArchive"}, | 416 | {0x080D0144, nullptr, "ControlArchive"}, |
| 392 | {0x080E0080, nullptr, "CloseArchive"}, | 417 | {0x080E0080, CloseArchive, "CloseArchive"}, |
| 393 | {0x080F0180, nullptr, "FormatThisUserSaveData"}, | 418 | {0x080F0180, nullptr, "FormatThisUserSaveData"}, |
| 394 | {0x08100200, nullptr, "CreateSystemSaveData"}, | 419 | {0x08100200, nullptr, "CreateSystemSaveData"}, |
| 395 | {0x08110040, nullptr, "DeleteSystemSaveData"}, | 420 | {0x08110040, nullptr, "DeleteSystemSaveData"}, |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 49f8c458d..463dacca3 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -74,7 +74,7 @@ ResultStatus LoadFile(const std::string& filename) { | |||
| 74 | 74 | ||
| 75 | // Load application and RomFS | 75 | // Load application and RomFS |
| 76 | if (ResultStatus::Success == app_loader.Load()) { | 76 | if (ResultStatus::Success == app_loader.Load()) { |
| 77 | Service::FS::CreateArchive(new FileSys::Archive_RomFS(app_loader), Service::FS::ArchiveIdCode::RomFS); | 77 | Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); |
| 78 | return ResultStatus::Success; | 78 | return ResultStatus::Success; |
| 79 | } | 79 | } |
| 80 | break; | 80 | break; |