diff options
Diffstat (limited to 'src/core/hle/kernel/archive.cpp')
-rw-r--r-- | src/core/hle/kernel/archive.cpp | 229 |
1 files changed, 111 insertions, 118 deletions
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp index 764082d7..e273444c 100644 --- a/src/core/hle/kernel/archive.cpp +++ b/src/core/hle/kernel/archive.cpp @@ -9,8 +9,9 @@ #include "core/file_sys/archive.h" #include "core/file_sys/archive_sdmc.h" #include "core/file_sys/directory.h" -#include "core/hle/service/service.h" #include "core/hle/kernel/archive.h" +#include "core/hle/result.h" +#include "core/hle/service/service.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Kernel namespace @@ -51,15 +52,10 @@ public: std::string name; ///< Name of archive (optional) FileSys::Archive* backend; ///< Archive backend interface - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { u32* cmd_buff = Service::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); - + switch (cmd) { // Read from archive... case FileCommand::Read: @@ -99,7 +95,6 @@ public: case FileCommand::Close: { DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); - Kernel::g_object_pool.Destroy<Archive>(GetHandle()); CloseArchive(backend->GetIdCode()); break; } @@ -107,42 +102,32 @@ public: default: { ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); - return -1; + return UnimplementedFunction(ErrorModule::FS); } } cmd_buff[1] = 0; // No error - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::FS); } }; class File : public Object { public: std::string GetTypeName() const override { return "File"; } - std::string GetName() const override { return path; } + std::string GetName() const override { return path.DebugStr(); } static Kernel::HandleType GetStaticHandleType() { return HandleType::File; } Kernel::HandleType GetHandleType() const override { return HandleType::File; } - std::string path; ///< Path of the file + FileSys::Path path; ///< Path of the file std::unique_ptr<FileSys::File> backend; ///< File backend interface - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { u32* cmd_buff = Service::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); switch (cmd) { @@ -184,7 +169,8 @@ public: case FileCommand::SetSize: { u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); + DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", + GetTypeName().c_str(), GetName().c_str(), size); backend->SetSize(size); break; } @@ -199,42 +185,33 @@ public: // Unknown command... default: ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); - cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. - return -1; + ResultCode error = UnimplementedFunction(ErrorModule::FS); + cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. + return error; } cmd_buff[1] = 0; // No error - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::FS); } }; class Directory : public Object { public: std::string GetTypeName() const override { return "Directory"; } - std::string GetName() const override { return path; } + std::string GetName() const override { return path.DebugStr(); } static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; } Kernel::HandleType GetHandleType() const override { return HandleType::Directory; } - std::string path; ///< Path of the directory + FileSys::Path path; ///< Path of the directory std::unique_ptr<FileSys::Directory> backend; ///< File backend interface - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { u32* cmd_buff = Service::GetCommandBuffer(); DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); switch (cmd) { @@ -244,8 +221,9 @@ public: { u32 count = cmd_buff[1]; u32 address = cmd_buff[3]; - FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); - DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); + auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); + DEBUG_LOG(KERNEL, "Read %s %s: count=%d", + GetTypeName().c_str(), GetName().c_str(), count); // Number of entries actually read cmd_buff[2] = backend->Read(count, entries); @@ -262,22 +240,18 @@ public: // Unknown command... default: ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); - cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. - return -1; + ResultCode error = UnimplementedFunction(ErrorModule::FS); + cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. + return error; } cmd_buff[1] = 0; // No error - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::FS); } }; @@ -285,108 +259,124 @@ public: std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode -/** - * Opens an archive - * @param id_code IdCode of the archive to open - * @return Handle to archive if it exists, otherwise a null handle (0) - */ -Handle OpenArchive(FileSys::Archive::IdCode id_code) { +ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) { auto itr = g_archive_map.find(id_code); if (itr == g_archive_map.end()) { - return 0; + return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Permanent); } - return itr->second; + + return MakeResult<Handle>(itr->second); } -/** - * Closes an archive - * @param id_code IdCode of the archive to open - * @return Result of operation, 0 on success, otherwise error code - */ -Result CloseArchive(FileSys::Archive::IdCode id_code) { - if (1 != g_archive_map.erase(id_code)) { - ERROR_LOG(KERNEL, "Cannot close archive %d", (int) id_code); - return -1; +ResultCode CloseArchive(FileSys::Archive::IdCode id_code) { + auto itr = g_archive_map.find(id_code); + if (itr == g_archive_map.end()) { + ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); + return InvalidHandle(ErrorModule::FS); } INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); - return 0; + return RESULT_SUCCESS; } /** * Mounts an archive * @param archive Pointer to the archive to mount - * @return Result of operation, 0 on success, otherwise error code */ -Result MountArchive(Archive* archive) { +ResultCode MountArchive(Archive* archive) { FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); - if (0 != OpenArchive(id_code)) { + ResultVal<Handle> archive_handle = OpenArchive(id_code); + if (archive_handle.Succeeded()) { ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); - return -1; + return archive_handle.Code(); } g_archive_map[id_code] = archive->GetHandle(); INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); - return 0; + return RESULT_SUCCESS; } -/** - * Creates an Archive - * @param handle Handle to newly created archive object - * @param backend File system backend interface to the archive - * @param name Optional name of Archive - * @return Newly created Archive object - */ -Archive* CreateArchive(Handle& handle, FileSys::Archive* backend, const std::string& name) { +ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) { Archive* archive = new Archive; - handle = Kernel::g_object_pool.Create(archive); + Handle handle = Kernel::g_object_pool.Create(archive); archive->name = name; archive->backend = backend; - MountArchive(archive); + ResultCode result = MountArchive(archive); + if (result.IsError()) { + return result; + } - return archive; + return RESULT_SUCCESS; } -/** - * Creates an Archive - * @param backend File system backend interface to the archive - * @param name Optional name of Archive - * @return Handle to newly created Archive object - */ -Handle CreateArchive(FileSys::Archive* backend, const std::string& name) { - Handle handle; - CreateArchive(handle, backend, name); - return handle; -} +ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { + // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create + // the archive file handles at app loading, and then keep them persistent throughout execution. + // Archives file handles are just reused and not actually freed until emulation shut down. + // Verify if real hardware works this way, or if new handles are created each time + if (path.GetType() == FileSys::Binary) + // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend + // design. While the functionally of this is OK, our implementation decision to separate + // normal files from archive file pointers is very likely wrong. + // See https://github.com/citra-emu/citra/issues/205 + return MakeResult<Handle>(archive_handle); -/** - * Open a File from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the File inside of the Archive - * @param mode Mode under which to open the File - * @return Opened File object - */ -Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const FileSys::Mode mode) { File* file = new File; Handle handle = Kernel::g_object_pool.Create(file); - Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); + if (archive == nullptr) { + return InvalidHandle(ErrorModule::FS); + } file->path = path; file->backend = archive->backend->OpenFile(path, mode); - if (!file->backend) + if (!file->backend) { + return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Permanent); + } + + return MakeResult<Handle>(handle); +} + +/** + * Delete a File from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the File inside of the Archive + * @return Whether deletion succeeded + */ +Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) { + Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + if (archive == nullptr) + return -1; + if (archive->backend->DeleteFile(path)) return 0; + return -1; +} - return handle; +/** + * Delete a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether deletion succeeded + */ +Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { + Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + if (archive == nullptr) + return -1; + if (archive->backend->DeleteDirectory(path)) + return 0; + return -1; } /** * Create a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive - * @return Opened Directory object + * @return Whether creation succeeded */ -Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path) { +Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); if (archive == nullptr) return -1; @@ -401,15 +391,18 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path * @param path Path to the Directory inside of the Archive * @return Opened Directory object */ -Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& path) { +ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { Directory* directory = new Directory; Handle handle = Kernel::g_object_pool.Create(directory); - Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); + if (archive == nullptr) { + return InvalidHandle(ErrorModule::FS); + } directory->path = path; directory->backend = archive->backend->OpenDirectory(path); - return handle; + return MakeResult<Handle>(handle); } /// Initialize archives |