mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	FS.Archive: Clean up treatment of archives and their handles
- Refactor FS::Archive internals to make Archive creation and lifetime management clearer. - Remove the "Archive as a File" hack. - Implement 64-bit Archive handles.
This commit is contained in:
		
							parent
							
								
									0931a42af0
								
							
						
					
					
						commit
						83e6e4ffec
					
				
					 11 changed files with 208 additions and 398 deletions
				
			
		|  | @ -220,36 +220,6 @@ public: | |||
|      * @return Opened directory, or nullptr | ||||
|      */ | ||||
|     virtual std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Read data from the archive | ||||
|      * @param offset Offset in bytes to start reading data from | ||||
|      * @param length Length in bytes of data to read from archive | ||||
|      * @param buffer Buffer to read data into | ||||
|      * @return Number of bytes read | ||||
|      */ | ||||
|     virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Write data to the archive | ||||
|      * @param offset Offset in bytes to start writing data to | ||||
|      * @param length Length in bytes of data to write to archive | ||||
|      * @param buffer Buffer to write data from | ||||
|      * @param flush  The flush parameters (0 == do not flush) | ||||
|      * @return Number of bytes written | ||||
|      */ | ||||
|     virtual size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Get the size of the archive in bytes | ||||
|      * @return Size of the archive in bytes | ||||
|      */ | ||||
|     virtual size_t GetSize() const = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Set the size of the archive in bytes | ||||
|      */ | ||||
|     virtual void SetSize(const u64 size) = 0; | ||||
| }; | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
|  |  | |||
|  | @ -2,6 +2,8 @@ | |||
| // Licensed under GPLv2
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| #include "core/file_sys/archive_romfs.h" | ||||
|  | @ -20,9 +22,6 @@ Archive_RomFS::Archive_RomFS(const Loader::AppLoader& app_loader) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| Archive_RomFS::~Archive_RomFS() { | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Open a file specified by its path, using the specified mode | ||||
|  * @param path Path relative to the archive | ||||
|  | @ -30,7 +29,7 @@ Archive_RomFS::~Archive_RomFS() { | |||
|  * @return Opened file, or nullptr | ||||
|  */ | ||||
| std::unique_ptr<FileBackend> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { | ||||
|     return std::unique_ptr<FileBackend>(new File_RomFS); | ||||
|     return std::make_unique<File_RomFS>(this); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -79,48 +78,7 @@ bool Archive_RomFS::RenameDirectory(const FileSys::Path& src_path, const FileSys | |||
|  * @return Opened directory, or nullptr | ||||
|  */ | ||||
| std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) const { | ||||
|     return std::unique_ptr<DirectoryBackend>(new Directory_RomFS); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Read data from the archive | ||||
|  * @param offset Offset in bytes to start reading data from | ||||
|  * @param length Length in bytes of data to read from archive | ||||
|  * @param buffer Buffer to read data into | ||||
|  * @return Number of bytes read | ||||
|  */ | ||||
| size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { | ||||
|     LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); | ||||
|     memcpy(buffer, &raw_data[(u32)offset], length); | ||||
|     return length; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Write data to the archive | ||||
|  * @param offset Offset in bytes to start writing data to | ||||
|  * @param length Length in bytes of data to write to archive | ||||
|  * @param buffer Buffer to write data from | ||||
|  * @param flush  The flush parameters (0 == do not flush) | ||||
|  * @return Number of bytes written | ||||
|  */ | ||||
| size_t Archive_RomFS::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { | ||||
|     LOG_WARNING(Service_FS, "Attempted to write to ROMFS."); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Get the size of the archive in bytes | ||||
|  * @return Size of the archive in bytes | ||||
|  */ | ||||
| size_t Archive_RomFS::GetSize() const { | ||||
|     return sizeof(u8) * raw_data.size(); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Set the size of the archive in bytes | ||||
|  */ | ||||
| void Archive_RomFS::SetSize(const u64 size) { | ||||
|     LOG_WARNING(Service_FS, "Attempted to set the size of ROMFS"); | ||||
|     return std::make_unique<Directory_RomFS>(); | ||||
| } | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
|  |  | |||
|  | @ -20,7 +20,6 @@ namespace FileSys { | |||
| class Archive_RomFS final : public ArchiveBackend { | ||||
| public: | ||||
|     Archive_RomFS(const Loader::AppLoader& app_loader); | ||||
|     ~Archive_RomFS() override; | ||||
| 
 | ||||
|     std::string GetName() const override { return "RomFS"; } | ||||
| 
 | ||||
|  | @ -76,37 +75,9 @@ public: | |||
|      */ | ||||
|     std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Read data from the archive | ||||
|      * @param offset Offset in bytes to start reading data from | ||||
|      * @param length Length in bytes of data to read from archive | ||||
|      * @param buffer Buffer to read data into | ||||
|      * @return Number of bytes read | ||||
|      */ | ||||
|     size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Write data to the archive | ||||
|      * @param offset Offset in bytes to start writing data to | ||||
|      * @param length Length in bytes of data to write to archive | ||||
|      * @param buffer Buffer to write data from | ||||
|      * @param flush  The flush parameters (0 == do not flush) | ||||
|      * @return Number of bytes written | ||||
|      */ | ||||
|     size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Get the size of the archive in bytes | ||||
|      * @return Size of the archive in bytes | ||||
|      */ | ||||
|     size_t GetSize() const override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Set the size of the archive in bytes | ||||
|      */ | ||||
|     void SetSize(const u64 size) override; | ||||
| 
 | ||||
| private: | ||||
|     friend class File_RomFS; | ||||
| 
 | ||||
|     std::vector<u8> raw_data; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -105,47 +105,6 @@ std::unique_ptr<DirectoryBackend> Archive_SDMC::OpenDirectory(const Path& path) | |||
|     return std::unique_ptr<DirectoryBackend>(directory); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Read data from the archive | ||||
|  * @param offset Offset in bytes to start reading archive from | ||||
|  * @param length Length in bytes to read data from archive | ||||
|  * @param buffer Buffer to read data into | ||||
|  * @return Number of bytes read | ||||
|  */ | ||||
| size_t Archive_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { | ||||
|     LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Write data to the archive | ||||
|  * @param offset Offset in bytes to start writing data to | ||||
|  * @param length Length in bytes of data to write to archive | ||||
|  * @param buffer Buffer to write data from | ||||
|  * @param flush  The flush parameters (0 == do not flush) | ||||
|  * @return Number of bytes written | ||||
|  */ | ||||
| size_t Archive_SDMC::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { | ||||
|     LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Get the size of the archive in bytes | ||||
|  * @return Size of the archive in bytes | ||||
|  */ | ||||
| size_t Archive_SDMC::GetSize() const { | ||||
|     LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Set the size of the archive in bytes | ||||
|  */ | ||||
| void Archive_SDMC::SetSize(const u64 size) { | ||||
|     LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Getter for the path used for this Archive | ||||
|  * @return Mount point of that passthrough archive | ||||
|  |  | |||
|  | @ -80,36 +80,6 @@ public: | |||
|      */ | ||||
|     std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Read data from the archive | ||||
|      * @param offset Offset in bytes to start reading archive from | ||||
|      * @param length Length in bytes to read data from archive | ||||
|      * @param buffer Buffer to read data into | ||||
|      * @return Number of bytes read | ||||
|      */ | ||||
|     size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Write data to the archive | ||||
|      * @param offset Offset in bytes to start writing data to | ||||
|      * @param length Length in bytes of data to write to archive | ||||
|      * @param buffer Buffer to write data from | ||||
|      * @param flush  The flush parameters (0 == do not flush) | ||||
|      * @return Number of bytes written | ||||
|      */ | ||||
|     size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Get the size of the archive in bytes | ||||
|      * @return Size of the archive in bytes | ||||
|      */ | ||||
|     size_t GetSize() const override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Set the size of the archive in bytes | ||||
|      */ | ||||
|     void SetSize(const u64 size) override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Getter for the path used for this Archive | ||||
|      * @return Mount point of that passthrough archive | ||||
|  |  | |||
|  | @ -5,24 +5,19 @@ | |||
| #include "common/common_types.h" | ||||
| 
 | ||||
| #include "core/file_sys/file_romfs.h" | ||||
| #include "core/file_sys/archive_romfs.h" | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| // FileSys namespace
 | ||||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| File_RomFS::File_RomFS() { | ||||
| } | ||||
| 
 | ||||
| File_RomFS::~File_RomFS() { | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Open the file | ||||
|  * @return true if the file opened correctly | ||||
|  */ | ||||
| bool File_RomFS::Open() { | ||||
|     return false; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -33,7 +28,9 @@ bool File_RomFS::Open() { | |||
|  * @return Number of bytes read | ||||
|  */ | ||||
| size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { | ||||
|     return -1; | ||||
|     LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); | ||||
|     memcpy(buffer, &archive->raw_data[(u32)offset], length); | ||||
|     return length; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -45,7 +42,8 @@ size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { | |||
|  * @return Number of bytes written | ||||
|  */ | ||||
| size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | ||||
|     return -1; | ||||
|     LOG_WARNING(Service_FS, "Attempted to write to ROMFS."); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -53,7 +51,7 @@ size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, co | |||
|  * @return Size of the file in bytes | ||||
|  */ | ||||
| size_t File_RomFS::GetSize() const { | ||||
|     return -1; | ||||
|     return sizeof(u8) * archive->raw_data.size(); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -62,6 +60,7 @@ size_t File_RomFS::GetSize() const { | |||
|  * @return true if successful | ||||
|  */ | ||||
| bool File_RomFS::SetSize(const u64 size) const { | ||||
|     LOG_WARNING(Service_FS, "Attempted to set the size of ROMFS"); | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,10 +14,11 @@ | |||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| class Archive_RomFS; | ||||
| 
 | ||||
| class File_RomFS final : public FileBackend { | ||||
| public: | ||||
|     File_RomFS(); | ||||
|     ~File_RomFS() override; | ||||
|     File_RomFS(const Archive_RomFS* archive) : archive(archive) {} | ||||
| 
 | ||||
|     /**
 | ||||
|      * Open the file | ||||
|  | @ -62,6 +63,9 @@ public: | |||
|      * @return true if the file closed correctly | ||||
|      */ | ||||
|     bool Close() const override; | ||||
| 
 | ||||
| private: | ||||
|     const Archive_RomFS* archive; | ||||
| }; | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
|  |  | |||
|  | @ -2,7 +2,8 @@ | |||
| // Licensed under GPLv2
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <map> | ||||
| #include <memory> | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "common/file_util.h" | ||||
|  | @ -41,74 +42,24 @@ enum class DirectoryCommand : u32 { | |||
|     Close           = 0x08020000, | ||||
| }; | ||||
| 
 | ||||
| class Archive : public Kernel::Session { | ||||
| class Archive { | ||||
| public: | ||||
|     std::string GetName() const override { return "Archive: " + backend->GetName(); } | ||||
| 
 | ||||
|     ArchiveIdCode id_code;      ///< Id code of the archive
 | ||||
|     FileSys::ArchiveBackend* backend;  ///< Archive backend interface
 | ||||
| 
 | ||||
|     ResultVal<bool> SyncRequest() override { | ||||
|         u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
|         FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | ||||
| 
 | ||||
|         switch (cmd) { | ||||
|         // Read from archive...
 | ||||
|         case FileCommand::Read: | ||||
|         { | ||||
|             u64 offset  = cmd_buff[1] | ((u64)cmd_buff[2] << 32); | ||||
|             u32 length  = cmd_buff[3]; | ||||
|             u32 address = cmd_buff[5]; | ||||
| 
 | ||||
|             // Number of bytes read
 | ||||
|             cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); | ||||
|             break; | ||||
|         } | ||||
|         // Write to archive...
 | ||||
|         case FileCommand::Write: | ||||
|         { | ||||
|             u64 offset  = cmd_buff[1] | ((u64)cmd_buff[2] << 32); | ||||
|             u32 length  = cmd_buff[3]; | ||||
|             u32 flush   = cmd_buff[4]; | ||||
|             u32 address = cmd_buff[6]; | ||||
| 
 | ||||
|             // Number of bytes written
 | ||||
|             cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); | ||||
|             break; | ||||
|         } | ||||
|         case FileCommand::GetSize: | ||||
|         { | ||||
|             u64 filesize = (u64) backend->GetSize(); | ||||
|             cmd_buff[2]  = (u32) filesize;         // Lower word
 | ||||
|             cmd_buff[3]  = (u32) (filesize >> 32); // Upper word
 | ||||
|             break; | ||||
|         } | ||||
|         case FileCommand::SetSize: | ||||
|         { | ||||
|             backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); | ||||
|             break; | ||||
|         } | ||||
|         case FileCommand::Close: | ||||
|         { | ||||
|             LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | ||||
|             CloseArchive(id_code); | ||||
|             break; | ||||
|         } | ||||
|         // Unknown command...
 | ||||
|         default: | ||||
|         { | ||||
|             LOG_ERROR(Service_FS, "Unknown command=0x%08X", cmd); | ||||
|             cmd_buff[0] = UnimplementedFunction(ErrorModule::FS).raw; | ||||
|             return MakeResult<bool>(false); | ||||
|         } | ||||
|         } | ||||
|         cmd_buff[1] = 0; // No error
 | ||||
|         return MakeResult<bool>(false); | ||||
|     Archive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) | ||||
|             : backend(std::move(backend)), id_code(id_code) { | ||||
|     } | ||||
| 
 | ||||
|     std::string GetName() const { return "Archive: " + backend->GetName(); } | ||||
| 
 | ||||
|     ArchiveIdCode id_code; ///< Id code of the archive
 | ||||
|     std::unique_ptr<FileSys::ArchiveBackend> backend; ///< Archive backend interface
 | ||||
| }; | ||||
| 
 | ||||
| class File : public Kernel::Session { | ||||
| public: | ||||
|     File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path) | ||||
|             : backend(std::move(backend)), path(path) { | ||||
|     } | ||||
| 
 | ||||
|     std::string GetName() const override { return "Path: " + path.DebugStr(); } | ||||
| 
 | ||||
|     FileSys::Path path; ///< Path of the file
 | ||||
|  | @ -183,6 +134,10 @@ public: | |||
| 
 | ||||
| class Directory : public Kernel::Session { | ||||
| public: | ||||
|     Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path) | ||||
|             : backend(std::move(backend)), path(path) { | ||||
|     } | ||||
| 
 | ||||
|     std::string GetName() const override { return "Directory: " + path.DebugStr(); } | ||||
| 
 | ||||
|     FileSys::Path path; ///< Path of the directory
 | ||||
|  | @ -228,105 +183,95 @@ public: | |||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| std::map<ArchiveIdCode, Handle> g_archive_map; ///< Map of file archives by IdCode
 | ||||
| 
 | ||||
| ResultVal<Handle> OpenArchive(ArchiveIdCode id_code) { | ||||
|     auto itr = g_archive_map.find(id_code); | ||||
|     if (itr == g_archive_map.end()) { | ||||
|         return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | ||||
|                 ErrorSummary::NotFound, ErrorLevel::Permanent); | ||||
|     } | ||||
| 
 | ||||
|     return MakeResult<Handle>(itr->second); | ||||
| } | ||||
| 
 | ||||
| ResultCode CloseArchive(ArchiveIdCode id_code) { | ||||
|     auto itr = g_archive_map.find(id_code); | ||||
|     if (itr == g_archive_map.end()) { | ||||
|         LOG_ERROR(Service_FS, "Cannot close archive %d, does not exist!", (int)id_code); | ||||
|         return InvalidHandle(ErrorModule::FS); | ||||
|     } | ||||
| 
 | ||||
|     LOG_TRACE(Service_FS, "Closed archive %d", (int) id_code); | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| /**
 | ||||
|  * Map of registered archives, identified by id code. Once an archive is registered here, it is | ||||
|  * never removed until the FS service is shut down. | ||||
|  */ | ||||
| static std::unordered_map<ArchiveIdCode, std::unique_ptr<Archive>> id_code_map; | ||||
| 
 | ||||
| /**
 | ||||
|  * Mounts an archive | ||||
|  * @param archive Pointer to the archive to mount | ||||
|  * Map of active archive handles. Values are pointers to the archives in `idcode_map`. | ||||
|  */ | ||||
| ResultCode MountArchive(Archive* archive) { | ||||
|     ArchiveIdCode id_code = archive->id_code; | ||||
|     ResultVal<Handle> archive_handle = OpenArchive(id_code); | ||||
|     if (archive_handle.Succeeded()) { | ||||
|         LOG_ERROR(Service_FS, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); | ||||
|         return archive_handle.Code(); | ||||
|     } | ||||
|     g_archive_map[id_code] = archive->GetHandle(); | ||||
|     LOG_TRACE(Service_FS, "Mounted archive %s", archive->GetName().c_str()); | ||||
|     return RESULT_SUCCESS; | ||||
| static std::unordered_map<ArchiveHandle, Archive*> handle_map; | ||||
| static ArchiveHandle next_handle; | ||||
| 
 | ||||
| static Archive* GetArchive(ArchiveHandle handle) { | ||||
|     auto itr = handle_map.find(handle); | ||||
|     return (itr == handle_map.end()) ? nullptr : itr->second; | ||||
| } | ||||
| 
 | ||||
| ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code) { | ||||
|     Archive* archive = new Archive; | ||||
|     Handle handle = Kernel::g_object_pool.Create(archive); | ||||
|     archive->id_code = id_code; | ||||
|     archive->backend = backend; | ||||
| ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) { | ||||
|     LOG_TRACE(Service_FS, "Opening archive with id code 0x%08X", id_code); | ||||
| 
 | ||||
|     ResultCode result = MountArchive(archive); | ||||
|     if (result.IsError()) { | ||||
|         return result; | ||||
|     } | ||||
|      | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
|     File* file = new File; | ||||
|     Handle handle = Kernel::g_object_pool.Create(file); | ||||
| 
 | ||||
|     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) { | ||||
|     auto itr = id_code_map.find(id_code); | ||||
|     if (itr == id_code_map.end()) { | ||||
|         // TODO: Verify error against hardware
 | ||||
|         return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | ||||
|                 ErrorSummary::NotFound, ErrorLevel::Permanent); | ||||
|     } | ||||
| 
 | ||||
|     // This should never even happen in the first place with 64-bit handles, 
 | ||||
|     while (handle_map.count(next_handle) != 0) { | ||||
|         ++next_handle; | ||||
|     } | ||||
|     handle_map.emplace(next_handle, itr->second.get()); | ||||
|     return MakeResult<ArchiveHandle>(next_handle++); | ||||
| } | ||||
| 
 | ||||
| ResultCode CloseArchive(ArchiveHandle handle) { | ||||
|     if (handle_map.erase(handle) == 0) | ||||
|         return InvalidHandle(ErrorModule::FS); | ||||
|     else | ||||
|         return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| // TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in
 | ||||
| // http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22
 | ||||
| ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) { | ||||
|     auto result = id_code_map.emplace(id_code, std::make_unique<Archive>(std::move(backend), id_code)); | ||||
| 
 | ||||
|     bool inserted = result.second; | ||||
|     _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); | ||||
| 
 | ||||
|     auto& archive = result.first->second; | ||||
|     LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(), id_code); | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { | ||||
|     Archive* archive = GetArchive(archive_handle); | ||||
|     if (archive == nullptr) | ||||
|         return InvalidHandle(ErrorModule::FS); | ||||
| 
 | ||||
|     std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); | ||||
|     if (backend == nullptr) { | ||||
|         return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | ||||
|                           ErrorSummary::NotFound, ErrorLevel::Permanent); | ||||
|     } | ||||
| 
 | ||||
|     auto file = std::make_unique<File>(std::move(backend), path); | ||||
|     Handle handle = Kernel::g_object_pool.Create(file.release()); | ||||
|     return MakeResult<Handle>(handle); | ||||
| } | ||||
| 
 | ||||
| ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) { | ||||
|     Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | ||||
| ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||||
|     Archive* archive = GetArchive(archive_handle); | ||||
|     if (archive == nullptr) | ||||
|         return InvalidHandle(ErrorModule::FS); | ||||
| 
 | ||||
|     if (archive->backend->DeleteFile(path)) | ||||
|         return RESULT_SUCCESS; | ||||
|     return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
 | ||||
|                       ErrorSummary::Canceled, ErrorLevel::Status); | ||||
| } | ||||
| 
 | ||||
| ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, | ||||
|                                      Handle dest_archive_handle, const FileSys::Path& dest_path) { | ||||
|     Archive* src_archive = Kernel::g_object_pool.GetFast<Archive>(src_archive_handle); | ||||
|     Archive* dest_archive = Kernel::g_object_pool.GetFast<Archive>(dest_archive_handle); | ||||
| ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, | ||||
|                                      ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { | ||||
|     Archive* src_archive = GetArchive(src_archive_handle); | ||||
|     Archive* dest_archive = GetArchive(dest_archive_handle); | ||||
|     if (src_archive == nullptr || dest_archive == nullptr) | ||||
|         return InvalidHandle(ErrorModule::FS); | ||||
| 
 | ||||
|     if (src_archive == dest_archive) { | ||||
|         if (src_archive->backend->RenameFile(src_path, dest_path)) | ||||
|             return RESULT_SUCCESS; | ||||
|  | @ -334,36 +279,42 @@ ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::P | |||
|         // TODO: Implement renaming across archives
 | ||||
|         return UnimplementedFunction(ErrorModule::FS); | ||||
|     } | ||||
| 
 | ||||
|     // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
 | ||||
|     // exist or similar. Verify.
 | ||||
|     return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
 | ||||
|                       ErrorSummary::NothingHappened, ErrorLevel::Status); | ||||
| } | ||||
| 
 | ||||
| ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { | ||||
|     Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | ||||
| ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||||
|     Archive* archive = GetArchive(archive_handle); | ||||
|     if (archive == nullptr) | ||||
|         return InvalidHandle(ErrorModule::FS); | ||||
| 
 | ||||
|     if (archive->backend->DeleteDirectory(path)) | ||||
|         return RESULT_SUCCESS; | ||||
|     return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
 | ||||
|                       ErrorSummary::Canceled, ErrorLevel::Status); | ||||
| } | ||||
| 
 | ||||
| ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { | ||||
|     Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | ||||
| ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||||
|     Archive* archive = GetArchive(archive_handle); | ||||
|     if (archive == nullptr) | ||||
|         return InvalidHandle(ErrorModule::FS); | ||||
| 
 | ||||
|     if (archive->backend->CreateDirectory(path)) | ||||
|         return RESULT_SUCCESS; | ||||
|     return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
 | ||||
|                       ErrorSummary::Canceled, ErrorLevel::Status); | ||||
| } | ||||
| 
 | ||||
| ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, | ||||
|                                           Handle dest_archive_handle, const FileSys::Path& dest_path) { | ||||
|     Archive* src_archive = Kernel::g_object_pool.GetFast<Archive>(src_archive_handle); | ||||
|     Archive* dest_archive = Kernel::g_object_pool.GetFast<Archive>(dest_archive_handle); | ||||
| ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, | ||||
|                                           ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { | ||||
|     Archive* src_archive = GetArchive(src_archive_handle); | ||||
|     Archive* dest_archive = GetArchive(dest_archive_handle); | ||||
|     if (src_archive == nullptr || dest_archive == nullptr) | ||||
|         return InvalidHandle(ErrorModule::FS); | ||||
| 
 | ||||
|     if (src_archive == dest_archive) { | ||||
|         if (src_archive->backend->RenameDirectory(src_path, dest_path)) | ||||
|             return RESULT_SUCCESS; | ||||
|  | @ -371,6 +322,9 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS | |||
|         // TODO: Implement renaming across archives
 | ||||
|         return UnimplementedFunction(ErrorModule::FS); | ||||
|     } | ||||
| 
 | ||||
|     // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
 | ||||
|     // exist or similar. Verify.
 | ||||
|     return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
 | ||||
|                       ErrorSummary::NothingHappened, ErrorLevel::Status); | ||||
| } | ||||
|  | @ -381,44 +335,42 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS | |||
|  * @param path Path to the Directory inside of the Archive | ||||
|  * @return Opened Directory object | ||||
|  */ | ||||
| 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.Get<Archive>(archive_handle); | ||||
|     if (archive == nullptr) { | ||||
| ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||||
|     Archive* archive = GetArchive(archive_handle); | ||||
|     if (archive == nullptr) | ||||
|         return InvalidHandle(ErrorModule::FS); | ||||
|     } | ||||
|     directory->path = path; | ||||
|     directory->backend = archive->backend->OpenDirectory(path); | ||||
| 
 | ||||
|     if (!directory->backend) { | ||||
|     std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); | ||||
|     if (backend == nullptr) { | ||||
|         return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | ||||
|                           ErrorSummary::NotFound, ErrorLevel::Permanent); | ||||
|     } | ||||
| 
 | ||||
|     auto directory = std::make_unique<Directory>(std::move(backend), path); | ||||
|     Handle handle = Kernel::g_object_pool.Create(directory.release()); | ||||
|     return MakeResult<Handle>(handle); | ||||
| } | ||||
| 
 | ||||
| /// Initialize archives
 | ||||
| void ArchiveInit() { | ||||
|     g_archive_map.clear(); | ||||
|     next_handle = 1; | ||||
| 
 | ||||
|     // TODO(Link Mauve): Add the other archive types (see here for the known types:
 | ||||
|     // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes).  Currently the only half-finished
 | ||||
|     // archive type is SDMC, so it is the only one getting exposed.
 | ||||
| 
 | ||||
|     std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); | ||||
|     auto archive = new FileSys::Archive_SDMC(sdmc_directory); | ||||
|     auto archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); | ||||
|     if (archive->Initialize()) | ||||
|         CreateArchive(archive, ArchiveIdCode::SDMC); | ||||
|         CreateArchive(std::move(archive), ArchiveIdCode::SDMC); | ||||
|     else | ||||
|         LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | ||||
| } | ||||
| 
 | ||||
| /// Shutdown archives
 | ||||
| void ArchiveShutdown() { | ||||
|     g_archive_map.clear(); | ||||
|     handle_map.clear(); | ||||
|     id_code_map.clear(); | ||||
| } | ||||
| 
 | ||||
| } // namespace FS
 | ||||
|  |  | |||
|  | @ -24,25 +24,27 @@ enum class ArchiveIdCode : u32 { | |||
|     SDMCWriteOnly       = 0x0000000A, | ||||
| }; | ||||
| 
 | ||||
| typedef u64 ArchiveHandle; | ||||
| 
 | ||||
| /**
 | ||||
|  * Opens an archive | ||||
|  * @param id_code IdCode of the archive to open | ||||
|  * @return Handle to the opened archive | ||||
|  */ | ||||
| ResultVal<Handle> OpenArchive(ArchiveIdCode id_code); | ||||
| ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code); | ||||
| 
 | ||||
| /**
 | ||||
|  * Closes an archive | ||||
|  * @param id_code IdCode of the archive to open | ||||
|  */ | ||||
| ResultCode CloseArchive(ArchiveIdCode id_code); | ||||
| ResultCode CloseArchive(ArchiveHandle handle); | ||||
| 
 | ||||
| /**
 | ||||
|  * Creates an Archive | ||||
|  * @param backend File system backend interface to the archive | ||||
|  * @param id_code Id code used to access this type of archive | ||||
|  */ | ||||
| ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code); | ||||
| ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code); | ||||
| 
 | ||||
| /**
 | ||||
|  * Open a File from an Archive | ||||
|  | @ -51,7 +53,7 @@ ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code | |||
|  * @param mode Mode under which to open the File | ||||
|  * @return Handle to the opened File object | ||||
|  */ | ||||
| ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); | ||||
| ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); | ||||
| 
 | ||||
| /**
 | ||||
|  * Delete a File from an Archive | ||||
|  | @ -59,7 +61,7 @@ ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path | |||
|  * @param path Path to the File inside of the Archive | ||||
|  * @return Whether deletion succeeded | ||||
|  */ | ||||
| ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path); | ||||
| ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | ||||
| 
 | ||||
| /**
 | ||||
|  * Rename a File between two Archives | ||||
|  | @ -69,8 +71,8 @@ ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& pat | |||
|  * @param dest_path Path to the File inside of the destination Archive | ||||
|  * @return Whether rename succeeded | ||||
|  */ | ||||
| ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, | ||||
|                                      Handle dest_archive_handle, const FileSys::Path& dest_path); | ||||
| ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, | ||||
|                                      ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path); | ||||
| 
 | ||||
| /**
 | ||||
|  * Delete a Directory from an Archive | ||||
|  | @ -78,7 +80,7 @@ ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::P | |||
|  * @param path Path to the Directory inside of the Archive | ||||
|  * @return Whether deletion succeeded | ||||
|  */ | ||||
| ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); | ||||
| ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | ||||
| 
 | ||||
| /**
 | ||||
|  * Create a Directory from an Archive | ||||
|  | @ -86,7 +88,7 @@ ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path | |||
|  * @param path Path to the Directory inside of the Archive | ||||
|  * @return Whether creation of directory succeeded | ||||
|  */ | ||||
| ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); | ||||
| ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | ||||
| 
 | ||||
| /**
 | ||||
|  * Rename a Directory between two Archives | ||||
|  | @ -96,8 +98,8 @@ ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path | |||
|  * @param dest_path Path to the Directory inside of the destination Archive | ||||
|  * @return Whether rename succeeded | ||||
|  */ | ||||
| ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, | ||||
|                                           Handle dest_archive_handle, const FileSys::Path& dest_path); | ||||
| ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, | ||||
|                                           ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path); | ||||
| 
 | ||||
| /**
 | ||||
|  * Open a Directory from an Archive | ||||
|  | @ -105,7 +107,7 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS | |||
|  * @param path Path to the Directory inside of the Archive | ||||
|  * @return Handle to the opened File object | ||||
|  */ | ||||
| ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); | ||||
| ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | ||||
| 
 | ||||
| /// Initialize archives
 | ||||
| void ArchiveInit(); | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/common.h" | ||||
| #include "common/scope_exit.h" | ||||
| 
 | ||||
| #include "common/string_util.h" | ||||
| #include "core/hle/service/fs/archive.h" | ||||
|  | @ -16,6 +17,10 @@ | |||
| namespace Service { | ||||
| namespace FS { | ||||
| 
 | ||||
| static ArchiveHandle MakeArchiveHandle(u32 low_word, u32 high_word) { | ||||
|     return (u64)low_word | ((u64)high_word << 32); | ||||
| } | ||||
| 
 | ||||
| static void Initialize(Service::Interface* self) { | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|  | @ -62,6 +67,7 @@ static void OpenFile(Service::Interface* self) { | |||
|     if (handle.Succeeded()) { | ||||
|         cmd_buff[3] = *handle; | ||||
|     } else { | ||||
|         cmd_buff[3] = 0; | ||||
|         LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | ||||
|     } | ||||
| } | ||||
|  | @ -106,25 +112,25 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
|     if (archive_path.GetType() != FileSys::Empty) { | ||||
|         LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); | ||||
|         cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | ||||
|         cmd_buff[3] = 0; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it
 | ||||
|     // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here?
 | ||||
|     ResultVal<Handle> archive_handle = OpenArchive(archive_id); | ||||
|     cmd_buff[1] = archive_handle.Code().raw; | ||||
|     ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id); | ||||
|     if (archive_handle.Failed()) { | ||||
|         LOG_ERROR(Service_FS, "failed to get a handle for archive"); | ||||
|         cmd_buff[1] = archive_handle.Code().raw; | ||||
|         cmd_buff[3] = 0; | ||||
|         return; | ||||
|     } | ||||
|     // cmd_buff[2] isn't used according to 3dmoo's implementation.
 | ||||
|     cmd_buff[3] = *archive_handle; | ||||
|     SCOPE_EXIT({ CloseArchive(*archive_handle); }); | ||||
| 
 | ||||
|     ResultVal<Handle> handle = OpenFileFromArchive(*archive_handle, file_path, mode); | ||||
|     cmd_buff[1] = handle.Code().raw; | ||||
|     if (handle.Succeeded()) { | ||||
|         cmd_buff[3] = *handle; | ||||
|     } else { | ||||
|         cmd_buff[3] = 0; | ||||
|         LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | ||||
|     } | ||||
| } | ||||
|  | @ -140,12 +146,10 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
|  *  Outputs: | ||||
|  *      1 : Result of function, 0 on success, otherwise error code | ||||
|  */ | ||||
| void DeleteFile(Service::Interface* self) { | ||||
| static void DeleteFile(Service::Interface* self) { | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
 | ||||
|     // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case.
 | ||||
|     Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||||
|     ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); | ||||
|     auto filename_type    = static_cast<FileSys::LowPathType>(cmd_buff[4]); | ||||
|     u32 filename_size     = cmd_buff[5]; | ||||
|     u32 filename_ptr      = cmd_buff[7]; | ||||
|  | @ -174,15 +178,13 @@ void DeleteFile(Service::Interface* self) { | |||
|  *  Outputs: | ||||
|  *      1 : Result of function, 0 on success, otherwise error code | ||||
|  */ | ||||
| void RenameFile(Service::Interface* self) { | ||||
| static void RenameFile(Service::Interface* self) { | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to
 | ||||
|     // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case.
 | ||||
|     Handle src_archive_handle  = static_cast<Handle>(cmd_buff[3]); | ||||
|     ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); | ||||
|     auto src_filename_type     = static_cast<FileSys::LowPathType>(cmd_buff[4]); | ||||
|     u32 src_filename_size      = cmd_buff[5]; | ||||
|     Handle dest_archive_handle = static_cast<Handle>(cmd_buff[7]); | ||||
|     ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);; | ||||
|     auto dest_filename_type    = static_cast<FileSys::LowPathType>(cmd_buff[8]); | ||||
|     u32 dest_filename_size     = cmd_buff[9]; | ||||
|     u32 src_filename_ptr       = cmd_buff[11]; | ||||
|  | @ -209,12 +211,10 @@ void RenameFile(Service::Interface* self) { | |||
|  *  Outputs: | ||||
|  *      1 : Result of function, 0 on success, otherwise error code | ||||
|  */ | ||||
| void DeleteDirectory(Service::Interface* self) { | ||||
| static void DeleteDirectory(Service::Interface* self) { | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
 | ||||
|     // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case.
 | ||||
|     Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||||
|     ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); | ||||
|     auto dirname_type     = static_cast<FileSys::LowPathType>(cmd_buff[4]); | ||||
|     u32 dirname_size      = cmd_buff[5]; | ||||
|     u32 dirname_ptr       = cmd_buff[7]; | ||||
|  | @ -241,9 +241,7 @@ void DeleteDirectory(Service::Interface* self) { | |||
| static void CreateDirectory(Service::Interface* self) { | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to
 | ||||
|     // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case.
 | ||||
|     Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||||
|     ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); | ||||
|     auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | ||||
|     u32 dirname_size = cmd_buff[5]; | ||||
|     u32 dirname_ptr = cmd_buff[8]; | ||||
|  | @ -271,15 +269,13 @@ static void CreateDirectory(Service::Interface* self) { | |||
|  *  Outputs: | ||||
|  *      1 : Result of function, 0 on success, otherwise error code | ||||
|  */ | ||||
| void RenameDirectory(Service::Interface* self) { | ||||
| static void RenameDirectory(Service::Interface* self) { | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to
 | ||||
|     // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case.
 | ||||
|     Handle src_archive_handle  = static_cast<Handle>(cmd_buff[3]); | ||||
|     ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); | ||||
|     auto src_dirname_type      = static_cast<FileSys::LowPathType>(cmd_buff[4]); | ||||
|     u32 src_dirname_size       = cmd_buff[5]; | ||||
|     Handle dest_archive_handle = static_cast<Handle>(cmd_buff[7]); | ||||
|     ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]); | ||||
|     auto dest_dirname_type     = static_cast<FileSys::LowPathType>(cmd_buff[8]); | ||||
|     u32 dest_dirname_size      = cmd_buff[9]; | ||||
|     u32 src_dirname_ptr        = cmd_buff[11]; | ||||
|  | @ -295,12 +291,23 @@ void RenameDirectory(Service::Interface* self) { | |||
|     cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * FS_User::OpenDirectory service function | ||||
|  *  Inputs: | ||||
|  *      1 : Archive handle low word | ||||
|  *      2 : Archive handle high word | ||||
|  *      3 : Low path type | ||||
|  *      4 : Low path size | ||||
|  *      7 : (LowPathSize << 14) | 2 | ||||
|  *      8 : Low path data pointer | ||||
|  *  Outputs: | ||||
|  *      1 : Result of function, 0 on success, otherwise error code | ||||
|  *      3 : Directory handle | ||||
|  */ | ||||
| static void OpenDirectory(Service::Interface* self) { | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
 | ||||
|     // 3dmoo's or ctrulib's implementations.  Triple check if it's really the case.
 | ||||
|     Handle archive_handle = static_cast<Handle>(cmd_buff[2]); | ||||
|     ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); | ||||
|     auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); | ||||
|     u32 dirname_size = cmd_buff[4]; | ||||
|     u32 dirname_ptr = cmd_buff[6]; | ||||
|  | @ -348,16 +355,34 @@ static void OpenArchive(Service::Interface* self) { | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     ResultVal<Handle> handle = OpenArchive(archive_id); | ||||
|     ResultVal<ArchiveHandle> handle = OpenArchive(archive_id); | ||||
|     cmd_buff[1] = handle.Code().raw; | ||||
|     if (handle.Succeeded()) { | ||||
|         // cmd_buff[2] isn't used according to 3dmoo's implementation.
 | ||||
|         cmd_buff[3] = *handle; | ||||
|         cmd_buff[2] = *handle & 0xFFFFFFFF; | ||||
|         cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF; | ||||
|     } else { | ||||
|         cmd_buff[2] = cmd_buff[3] = 0; | ||||
|         LOG_ERROR(Service_FS, "failed to get a handle for archive"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * FS_User::CloseArchive service function | ||||
|  *  Inputs: | ||||
|  *      0 : 0x080E0080 | ||||
|  *      1 : Archive handle low word | ||||
|  *      2 : Archive handle high word | ||||
|  *  Outputs: | ||||
|  *      0 : ??? TODO(yuriks): Verify return header | ||||
|  *      1 : Result of function, 0 on success, otherwise error code | ||||
|  */ | ||||
| static void CloseArchive(Service::Interface* self) { | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); | ||||
|     cmd_buff[1] = CloseArchive(archive_handle).raw; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| * FS_User::IsSdmcDetected service function | ||||
| *  Outputs: | ||||
|  | @ -389,7 +414,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { | |||
|     {0x080B0102, OpenDirectory,         "OpenDirectory"}, | ||||
|     {0x080C00C2, OpenArchive,           "OpenArchive"}, | ||||
|     {0x080D0144, nullptr,               "ControlArchive"}, | ||||
|     {0x080E0080, nullptr,               "CloseArchive"}, | ||||
|     {0x080E0080, CloseArchive,          "CloseArchive"}, | ||||
|     {0x080F0180, nullptr,               "FormatThisUserSaveData"}, | ||||
|     {0x08100200, nullptr,               "CreateSystemSaveData"}, | ||||
|     {0x08110040, nullptr,               "DeleteSystemSaveData"}, | ||||
|  |  | |||
|  | @ -74,7 +74,7 @@ ResultStatus LoadFile(const std::string& filename) { | |||
| 
 | ||||
|         // Load application and RomFS
 | ||||
|         if (ResultStatus::Success == app_loader.Load()) { | ||||
|             Service::FS::CreateArchive(new FileSys::Archive_RomFS(app_loader), Service::FS::ArchiveIdCode::RomFS); | ||||
|             Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); | ||||
|             return ResultStatus::Success; | ||||
|         } | ||||
|         break; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue