mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	HLE/FS: Implemented GetFormatInfo
Format information is currently only implemented for the ExtSaveData, SharedExtSaveData and SaveData archives, the information is stored in a file alongside the root folder of the archive.
This commit is contained in:
		
							parent
							
								
									9b2d643451
								
							
						
					
					
						commit
						d26c6b3212
					
				
					 19 changed files with 257 additions and 62 deletions
				
			
		|  | @ -62,6 +62,14 @@ private: | ||||||
|     std::u16string u16str; |     std::u16string u16str; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct ArchiveFormatInfo { | ||||||
|  |     u32 total_size; ///< The pre-defined size of the archive, as specified in the Create or Format call
 | ||||||
|  |     u32 number_directories; ///< The pre-defined number of directories in the archive, as specified in the Create or Format call
 | ||||||
|  |     u32 number_files; ///< The pre-defined number of files in the archive, as specified in the Create or Format call
 | ||||||
|  |     u8 duplicate_data; ///< Whether the archive should duplicate the data, as specified in the Create or Format call
 | ||||||
|  | }; | ||||||
|  | static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD"); | ||||||
|  | 
 | ||||||
| class ArchiveBackend : NonCopyable { | class ArchiveBackend : NonCopyable { | ||||||
| public: | public: | ||||||
|     virtual ~ArchiveBackend() { |     virtual ~ArchiveBackend() { | ||||||
|  | @ -159,9 +167,17 @@ public: | ||||||
|     /**
 |     /**
 | ||||||
|      * Deletes the archive contents and then re-creates the base folder |      * Deletes the archive contents and then re-creates the base folder | ||||||
|      * @param path Path to the archive |      * @param path Path to the archive | ||||||
|  |      * @param format_info Format information for the new archive | ||||||
|      * @return ResultCode of the operation, 0 on success |      * @return ResultCode of the operation, 0 on success | ||||||
|      */ |      */ | ||||||
|     virtual ResultCode Format(const Path& path) = 0; |     virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) = 0; | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * Retrieves the format info about the archive with the specified path | ||||||
|  |      * @param path Path to the archive | ||||||
|  |      * @return Format information about the archive or error code | ||||||
|  |      */ | ||||||
|  |     virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const = 0; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  |  | ||||||
|  | @ -82,13 +82,45 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons | ||||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); |     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path) { | ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | ||||||
|     // These folders are always created with the ExtSaveData
 |     // These folders are always created with the ExtSaveData
 | ||||||
|     std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/"; |     std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/"; | ||||||
|     std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/"; |     std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/"; | ||||||
|     FileUtil::CreateFullPath(user_path); |     FileUtil::CreateFullPath(user_path); | ||||||
|     FileUtil::CreateFullPath(boss_path); |     FileUtil::CreateFullPath(boss_path); | ||||||
|  | 
 | ||||||
|  |     // Write the format metadata
 | ||||||
|  |     std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata"; | ||||||
|  |     FileUtil::IOFile file(metadata_path, "wb"); | ||||||
|  | 
 | ||||||
|  |     if (file.IsOpen()) { | ||||||
|  |         file.WriteBytes(&format_info, sizeof(format_info)); | ||||||
|         return RESULT_SUCCESS; |         return RESULT_SUCCESS; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // TODO(Subv): Find the correct error code
 | ||||||
|  |     return ResultCode(-1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path) const { | ||||||
|  |     std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata"; | ||||||
|  |     FileUtil::IOFile file(metadata_path, "rb"); | ||||||
|  | 
 | ||||||
|  |     if (file.IsOpen()) { | ||||||
|  |         ArchiveFormatInfo info; | ||||||
|  |         file.ReadBytes(&info, sizeof(info)); | ||||||
|  |         return MakeResult<ArchiveFormatInfo>(info); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LOG_ERROR(Service_FS, "Could not open metadata information for archive"); | ||||||
|  |     // TODO(Subv): Verify error code
 | ||||||
|  |     return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, u8* icon_data, u32 icon_size) { | ||||||
|  |     std::string game_path = FileSys::GetExtSaveDataPath(GetMountPoint(), path); | ||||||
|  |     FileUtil::IOFile icon_file(game_path + "icon", "wb+"); | ||||||
|  |     icon_file.WriteBytes(icon_data, icon_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  |  | ||||||
|  | @ -31,10 +31,19 @@ public: | ||||||
|     std::string GetName() const override { return "ExtSaveData"; } |     std::string GetName() const override { return "ExtSaveData"; } | ||||||
| 
 | 
 | ||||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; |     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||||
|     ResultCode Format(const Path& path) override; |     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||||
|  |     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||||
| 
 | 
 | ||||||
|     const std::string& GetMountPoint() const { return mount_point; } |     const std::string& GetMountPoint() const { return mount_point; } | ||||||
| 
 | 
 | ||||||
|  |     /*
 | ||||||
|  |      * Writes the SMDH icon of the ExtSaveData to file | ||||||
|  |      * @param path Path of this ExtSaveData | ||||||
|  |      * @param icon_data Binary data of the icon | ||||||
|  |      * @param icon_size Size of the icon data | ||||||
|  |      */ | ||||||
|  |     void WriteIcon(const Path& path, u8* icon_data, u32 icon_size); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     /**
 |     /**
 | ||||||
|      * This holds the full directory path for this archive, it is only set after a successful call |      * This holds the full directory path for this archive, it is only set after a successful call | ||||||
|  |  | ||||||
|  | @ -29,11 +29,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path | ||||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); |     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode ArchiveFactory_RomFS::Format(const Path& path) { | ResultCode ArchiveFactory_RomFS::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | ||||||
|     LOG_ERROR(Service_FS, "Attempted to format a RomFS archive."); |     LOG_ERROR(Service_FS, "Attempted to format a RomFS archive."); | ||||||
|     // TODO: Verify error code
 |     // TODO: Verify error code
 | ||||||
|     return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, |     return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, | ||||||
|             ErrorSummary::NotSupported, ErrorLevel::Permanent); |             ErrorSummary::NotSupported, ErrorLevel::Permanent); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultVal<ArchiveFormatInfo> ArchiveFactory_RomFS::GetFormatInfo(const Path& path) const { | ||||||
|  |     // TODO(Subv): Implement
 | ||||||
|  |     LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||||||
|  |     return ResultCode(-1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  |  | ||||||
|  | @ -26,7 +26,8 @@ public: | ||||||
| 
 | 
 | ||||||
|     std::string GetName() const override { return "RomFS"; } |     std::string GetName() const override { return "RomFS"; } | ||||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; |     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||||
|     ResultCode Format(const Path& path) override; |     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||||
|  |     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::shared_ptr<FileUtil::IOFile> romfs_file; |     std::shared_ptr<FileUtil::IOFile> romfs_file; | ||||||
|  |  | ||||||
|  | @ -31,6 +31,12 @@ static std::string GetSaveDataPath(const std::string& mount_location, u64 progra | ||||||
|     return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, low); |     return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, low); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static std::string GetSaveDataMetadataPath(const std::string& mount_location, u64 program_id) { | ||||||
|  |     u32 high = program_id >> 32; | ||||||
|  |     u32 low = program_id & 0xFFFFFFFF; | ||||||
|  |     return Common::StringFromFormat("%s%08x/%08x/data/00000001.metadata", mount_location.c_str(), high, low); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory) | ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory) | ||||||
|         : mount_point(GetSaveDataContainerPath(sdmc_directory)) { |         : mount_point(GetSaveDataContainerPath(sdmc_directory)) { | ||||||
|     LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); |     LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); | ||||||
|  | @ -51,11 +57,35 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const P | ||||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); |     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode ArchiveFactory_SaveData::Format(const Path& path) { | ResultCode ArchiveFactory_SaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | ||||||
|     std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id); |     std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id); | ||||||
|     FileUtil::DeleteDirRecursively(concrete_mount_point); |     FileUtil::DeleteDirRecursively(concrete_mount_point); | ||||||
|     FileUtil::CreateFullPath(concrete_mount_point); |     FileUtil::CreateFullPath(concrete_mount_point); | ||||||
|  | 
 | ||||||
|  |     // Write the format metadata
 | ||||||
|  |     std::string metadata_path = GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id); | ||||||
|  |     FileUtil::IOFile file(metadata_path, "wb"); | ||||||
|  | 
 | ||||||
|  |     if (file.IsOpen()) { | ||||||
|  |         file.WriteBytes(&format_info, sizeof(format_info)); | ||||||
|  |         return RESULT_SUCCESS; | ||||||
|  |     } | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const { | ||||||
|  |     std::string metadata_path = GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id); | ||||||
|  |     FileUtil::IOFile file(metadata_path, "rb"); | ||||||
|  | 
 | ||||||
|  |     if (file.IsOpen()) { | ||||||
|  |         ArchiveFormatInfo info; | ||||||
|  |         file.ReadBytes(&info, sizeof(info)); | ||||||
|  |         return MakeResult<ArchiveFormatInfo>(info); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LOG_ERROR(Service_FS, "Could not open metadata information for archive"); | ||||||
|  |     // TODO(Subv): Verify error code
 | ||||||
|  |     return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  |  | ||||||
|  | @ -23,7 +23,9 @@ public: | ||||||
|     std::string GetName() const override { return "SaveData"; } |     std::string GetName() const override { return "SaveData"; } | ||||||
| 
 | 
 | ||||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; |     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||||
|     ResultCode Format(const Path& path) override; |     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||||
|  | 
 | ||||||
|  |     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::string mount_point; |     std::string mount_point; | ||||||
|  |  | ||||||
|  | @ -48,11 +48,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(co | ||||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); |     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path) { | ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | ||||||
|     LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive."); |     LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive."); | ||||||
|     // TODO: Verify error code
 |     // TODO: Verify error code
 | ||||||
|     return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, |     return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, | ||||||
|         ErrorSummary::NotSupported, ErrorLevel::Permanent); |         ErrorSummary::NotSupported, ErrorLevel::Permanent); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveDataCheck::GetFormatInfo(const Path& path) const { | ||||||
|  |     // TODO(Subv): Implement
 | ||||||
|  |     LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||||||
|  |     return ResultCode(-1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  |  | ||||||
|  | @ -23,7 +23,8 @@ public: | ||||||
|     std::string GetName() const override { return "SaveDataCheck"; } |     std::string GetName() const override { return "SaveDataCheck"; } | ||||||
| 
 | 
 | ||||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; |     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||||
|     ResultCode Format(const Path& path) override; |     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||||
|  |     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::string mount_point; |     std::string mount_point; | ||||||
|  |  | ||||||
|  | @ -40,9 +40,14 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path& | ||||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); |     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode ArchiveFactory_SDMC::Format(const Path& path) { | ResultCode ArchiveFactory_SDMC::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | ||||||
|     // This is kind of an undesirable operation, so let's just ignore it. :)
 |     // This is kind of an undesirable operation, so let's just ignore it. :)
 | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path) const { | ||||||
|  |     // TODO(Subv): Implement
 | ||||||
|  |     LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||||||
|  |     return ResultCode(-1); | ||||||
|  | } | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  |  | ||||||
|  | @ -29,7 +29,8 @@ public: | ||||||
|     std::string GetName() const override { return "SDMC"; } |     std::string GetName() const override { return "SDMC"; } | ||||||
| 
 | 
 | ||||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; |     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||||
|     ResultCode Format(const Path& path) override; |     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||||
|  |     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::string sdmc_directory; |     std::string sdmc_directory; | ||||||
|  |  | ||||||
|  | @ -63,11 +63,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c | ||||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); |     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path) { | ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | ||||||
|     std::string fullpath = GetSystemSaveDataPath(base_path, path); |     std::string fullpath = GetSystemSaveDataPath(base_path, path); | ||||||
|     FileUtil::DeleteDirRecursively(fullpath); |     FileUtil::DeleteDirRecursively(fullpath); | ||||||
|     FileUtil::CreateFullPath(fullpath); |     FileUtil::CreateFullPath(fullpath); | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const Path& path) const { | ||||||
|  |     // TODO(Subv): Implement
 | ||||||
|  |     LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||||||
|  |     return ResultCode(-1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  |  | ||||||
|  | @ -23,7 +23,8 @@ public: | ||||||
|     ArchiveFactory_SystemSaveData(const std::string& mount_point); |     ArchiveFactory_SystemSaveData(const std::string& mount_point); | ||||||
| 
 | 
 | ||||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; |     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||||
|     ResultCode Format(const Path& path) override; |     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||||
|  |     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||||
| 
 | 
 | ||||||
|     std::string GetName() const override { return "SystemSaveData"; } |     std::string GetName() const override { return "SystemSaveData"; } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ enum class ErrorDescription : u32 { | ||||||
|     FS_InvalidOpenFlags = 230, |     FS_InvalidOpenFlags = 230, | ||||||
|     FS_NotAFile = 250, |     FS_NotAFile = 250, | ||||||
|     FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
 |     FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
 | ||||||
|  |     FS_InvalidPath = 702, | ||||||
|     InvalidSection = 1000, |     InvalidSection = 1000, | ||||||
|     TooLarge = 1001, |     TooLarge = 1001, | ||||||
|     NotAuthorized = 1002, |     NotAuthorized = 1002, | ||||||
|  |  | ||||||
|  | @ -407,7 +407,7 @@ void Init() { | ||||||
|     // If the archive didn't exist, create the files inside
 |     // If the archive didn't exist, create the files inside
 | ||||||
|     if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { |     if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { | ||||||
|         // Format the archive to create the directories
 |         // Format the archive to create the directories
 | ||||||
|         Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); |         Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, FileSys::ArchiveFormatInfo(), archive_path); | ||||||
| 
 | 
 | ||||||
|         // Open it again to get a valid archive now that the folder exists
 |         // Open it again to get a valid archive now that the folder exists
 | ||||||
|         archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); |         archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); | ||||||
|  |  | ||||||
|  | @ -421,49 +421,45 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { | ||||||
|     return MakeResult<u64>(archive->GetFreeBytes()); |     return MakeResult<u64>(archive->GetFreeBytes()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { | ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path) { | ||||||
|     auto archive_itr = id_code_map.find(id_code); |     auto archive_itr = id_code_map.find(id_code); | ||||||
|     if (archive_itr == id_code_map.end()) { |     if (archive_itr == id_code_map.end()) { | ||||||
|         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
 |         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return archive_itr->second->Format(path); |     return archive_itr->second->Format(path, format_info); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size) { | ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path) { | ||||||
|  |     auto archive = id_code_map.find(id_code); | ||||||
|  |     if (archive == id_code_map.end()) { | ||||||
|  |         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return archive->second->GetFormatInfo(archive_path); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info) { | ||||||
|     // Construct the binary path to the archive first
 |     // Construct the binary path to the archive first
 | ||||||
|     FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); |     FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); | ||||||
| 
 | 
 | ||||||
|     std::string media_type_directory; |     auto archive = id_code_map.find(media_type == MediaType::NAND ? ArchiveIdCode::SharedExtSaveData : ArchiveIdCode::ExtSaveData); | ||||||
|     if (media_type == MediaType::NAND) { | 
 | ||||||
|         media_type_directory = FileUtil::GetUserPath(D_NAND_IDX); |     if (archive == id_code_map.end()) { | ||||||
|     } else if (media_type == MediaType::SDMC) { |         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
 | ||||||
|         media_type_directory = FileUtil::GetUserPath(D_SDMC_IDX); |  | ||||||
|     } else { |  | ||||||
|         LOG_ERROR(Service_FS, "Unsupported media type %u", media_type); |  | ||||||
|         return ResultCode(-1); // TODO(Subv): Find the right error code
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); |     auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get()); | ||||||
|     std::string game_path = FileSys::GetExtSaveDataPath(base_path, path); | 
 | ||||||
|     // These two folders are always created with the ExtSaveData
 |     ResultCode result = ext_savedata->Format(path, format_info); | ||||||
|     std::string user_path = game_path + "user/"; |     if (result.IsError()) | ||||||
|     std::string boss_path = game_path + "boss/"; |         return result; | ||||||
|     if (!FileUtil::CreateFullPath(user_path)) |  | ||||||
|         return ResultCode(-1); // TODO(Subv): Find the right error code
 |  | ||||||
|     if (!FileUtil::CreateFullPath(boss_path)) |  | ||||||
|         return ResultCode(-1); // TODO(Subv): Find the right error code
 |  | ||||||
| 
 | 
 | ||||||
|     u8* smdh_icon = Memory::GetPointer(icon_buffer); |     u8* smdh_icon = Memory::GetPointer(icon_buffer); | ||||||
|     if (!smdh_icon) |     if (!smdh_icon) | ||||||
|         return ResultCode(-1); // TODO(Subv): Find the right error code
 |         return ResultCode(-1); // TODO(Subv): Find the right error code
 | ||||||
| 
 | 
 | ||||||
|     // Create the icon
 |     ext_savedata->WriteIcon(path, smdh_icon, icon_size); | ||||||
|     FileUtil::IOFile icon_file(game_path + "icon", "wb+"); |  | ||||||
|     if (!icon_file.IsGood()) |  | ||||||
|         return ResultCode(-1); // TODO(Subv): Find the right error code
 |  | ||||||
| 
 |  | ||||||
|     icon_file.WriteBytes(smdh_icon, icon_size); |  | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -177,10 +177,20 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle); | ||||||
|  * Erases the contents of the physical folder that contains the archive |  * Erases the contents of the physical folder that contains the archive | ||||||
|  * identified by the specified id code and path |  * identified by the specified id code and path | ||||||
|  * @param id_code The id of the archive to format |  * @param id_code The id of the archive to format | ||||||
|  |  * @param format_info Format information about the new archive | ||||||
|  * @param path The path to the archive, if relevant. |  * @param path The path to the archive, if relevant. | ||||||
|  * @return ResultCode 0 on success or the corresponding code on error |  * @return ResultCode 0 on success or the corresponding code on error | ||||||
|  */ |  */ | ||||||
| ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = FileSys::Path()); | ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path = FileSys::Path()); | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Retrieves the format info about the archive of the specified type and path. | ||||||
|  |  * The format info is supplied by the client code when creating archives. | ||||||
|  |  * @param id_code The id of the archive | ||||||
|  |  * @param archive_path The path of the archive, if relevant | ||||||
|  |  * @return The format info of the archive, or the corresponding error code if failed. | ||||||
|  |  */ | ||||||
|  | ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Creates a blank SharedExtSaveData archive for the specified extdata ID |  * Creates a blank SharedExtSaveData archive for the specified extdata ID | ||||||
|  | @ -189,9 +199,10 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = File | ||||||
|  * @param low The low word of the extdata id to create |  * @param low The low word of the extdata id to create | ||||||
|  * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData |  * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData | ||||||
|  * @param icon_size Size of the SMDH icon |  * @param icon_size Size of the SMDH icon | ||||||
|  |  * @param format_info Format information about the new archive | ||||||
|  * @return ResultCode 0 on success or the corresponding code on error |  * @return ResultCode 0 on success or the corresponding code on error | ||||||
|  */ |  */ | ||||||
| ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size); | ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Deletes the SharedExtSaveData archive for the specified extdata ID |  * Deletes the SharedExtSaveData archive for the specified extdata ID | ||||||
|  |  | ||||||
|  | @ -443,17 +443,22 @@ static void IsSdmcWriteable(Service::Interface* self) { | ||||||
|  *  Inputs: |  *  Inputs: | ||||||
|  *      0  : 0x084C0242 |  *      0  : 0x084C0242 | ||||||
|  *      1  : Archive ID |  *      1  : Archive ID | ||||||
|  *      2  : Archive low path type |  *      2  : Archive path type | ||||||
|  *      3  : Archive low path size |  *      3  : Archive path size | ||||||
|  *      10 : (LowPathSize << 14) | 2 |  *      4  : Size in Blocks (1 block = 512 bytes) | ||||||
|  |  *      5  : Number of directories | ||||||
|  |  *      6  : Number of files | ||||||
|  |  *      7  : Directory bucket count | ||||||
|  |  *      8  : File bucket count | ||||||
|  |  *      9  : Duplicate data | ||||||
|  |  *      10 : (PathSize << 14) | 2 | ||||||
|  *      11 : Archive low path |  *      11 : Archive low path | ||||||
|  *  Outputs: |  *  Outputs: | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  */ |  */ | ||||||
| static void FormatSaveData(Service::Interface* self) { | static void FormatSaveData(Service::Interface* self) { | ||||||
|     // TODO(Subv): Find out what the other inputs and outputs of this function are
 |  | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     LOG_DEBUG(Service_FS, "(STUBBED)"); |     LOG_WARNING(Service_FS, "(STUBBED)"); | ||||||
| 
 | 
 | ||||||
|     auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]); |     auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]); | ||||||
|     auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); |     auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); | ||||||
|  | @ -464,9 +469,9 @@ static void FormatSaveData(Service::Interface* self) { | ||||||
|     LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); |     LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); | ||||||
| 
 | 
 | ||||||
|     if (archive_id != FS::ArchiveIdCode::SaveData) { |     if (archive_id != FS::ArchiveIdCode::SaveData) { | ||||||
|         // TODO(Subv): What should happen if somebody attempts to format a different archive?
 |         LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", archive_id); | ||||||
|         LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", cmd_buff[1]); |         cmd_buff[1] = ResultCode(ErrorDescription::FS_InvalidPath, ErrorModule::FS, | ||||||
|         cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; |                                  ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -477,23 +482,40 @@ static void FormatSaveData(Service::Interface* self) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; |     FileSys::ArchiveFormatInfo format_info; | ||||||
|  |     format_info.duplicate_data = cmd_buff[9] & 0xFF; | ||||||
|  |     format_info.number_directories = cmd_buff[5]; | ||||||
|  |     format_info.number_files = cmd_buff[6]; | ||||||
|  |     format_info.total_size = cmd_buff[4] * 512; | ||||||
|  | 
 | ||||||
|  |     cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData, format_info).raw; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * FS_User::FormatThisUserSaveData service function |  * FS_User::FormatThisUserSaveData service function | ||||||
|  *  Inputs: |  *  Inputs: | ||||||
|  *      0: 0x080F0180 |  *      0: 0x080F0180 | ||||||
|  |  *      1  : Size in Blocks (1 block = 512 bytes) | ||||||
|  |  *      2  : Number of directories | ||||||
|  |  *      3  : Number of files | ||||||
|  |  *      4  : Directory bucket count | ||||||
|  |  *      5  : File bucket count | ||||||
|  |  *      6  : Duplicate data | ||||||
|  *  Outputs: |  *  Outputs: | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  */ |  */ | ||||||
| static void FormatThisUserSaveData(Service::Interface* self) { | static void FormatThisUserSaveData(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     LOG_DEBUG(Service_FS, "(STUBBED)"); |  | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): Find out what the inputs and outputs of this function are
 |     FileSys::ArchiveFormatInfo format_info; | ||||||
|  |     format_info.duplicate_data = cmd_buff[6] & 0xFF; | ||||||
|  |     format_info.number_directories = cmd_buff[2]; | ||||||
|  |     format_info.number_files = cmd_buff[3]; | ||||||
|  |     format_info.total_size = cmd_buff[1] * 512; | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; |     cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData, format_info).raw; | ||||||
|  | 
 | ||||||
|  |     LOG_TRACE(Service_FS, "called"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -531,10 +553,9 @@ static void GetFreeBytes(Service::Interface* self) { | ||||||
|  *      2 : Low word of the saveid to create |  *      2 : Low word of the saveid to create | ||||||
|  *      3 : High word of the saveid to create |  *      3 : High word of the saveid to create | ||||||
|  *      4 : Unknown |  *      4 : Unknown | ||||||
|  *      5 : Unknown |  *      5 : Number of directories | ||||||
|  *      6 : Unknown |  *      6 : Number of files | ||||||
|  *      7 : Unknown |  *      7-8 : Size limit | ||||||
|  *      8 : Unknown |  | ||||||
|  *      9 : Size of the SMDH icon |  *      9 : Size of the SMDH icon | ||||||
|  *      10: (SMDH Size << 4) | 0x0000000A |  *      10: (SMDH Size << 4) | 0x0000000A | ||||||
|  *      11: Pointer to the SMDH icon for the new ExtSaveData |  *      11: Pointer to the SMDH icon for the new ExtSaveData | ||||||
|  | @ -556,7 +577,12 @@ static void CreateExtSaveData(Service::Interface* self) { | ||||||
|             cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size, |             cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size, | ||||||
|             cmd_buff[10], icon_buffer); |             cmd_buff[10], icon_buffer); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size).raw; |     FileSys::ArchiveFormatInfo format_info; | ||||||
|  |     format_info.number_directories = cmd_buff[5]; | ||||||
|  |     format_info.number_files = cmd_buff[6]; | ||||||
|  |     format_info.duplicate_data = false; | ||||||
|  |     format_info.total_size = 0; | ||||||
|  |     cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size, format_info).raw; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -731,6 +757,51 @@ static void GetArchiveResource(Service::Interface* self) { | ||||||
|     cmd_buff[5] = 0x80000; // 8GiB free
 |     cmd_buff[5] = 0x80000; // 8GiB free
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * FS_User::GetFormatInfo service function. | ||||||
|  |  *  Inputs: | ||||||
|  |  *      0 : 0x084500C2 | ||||||
|  |  *      1 : Archive ID | ||||||
|  |  *      2 : Archive path type | ||||||
|  |  *      3 : Archive path size | ||||||
|  |  *      4 : (PathSize << 14) | 2 | ||||||
|  |  *      5 : Archive low path | ||||||
|  |  *  Outputs: | ||||||
|  |  *      0 : 0x08450140 | ||||||
|  |  *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |  *      2 : Total size | ||||||
|  |  *      3 : Number of directories | ||||||
|  |  *      4 : Number of files | ||||||
|  |  *      5 : Duplicate data | ||||||
|  |  */ | ||||||
|  | static void GetFormatInfo(Service::Interface* self) { | ||||||
|  |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|  | 
 | ||||||
|  |     auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]); | ||||||
|  |     auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); | ||||||
|  |     u32 archivename_size = cmd_buff[3]; | ||||||
|  |     u32 archivename_ptr = cmd_buff[5]; | ||||||
|  |     FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); | ||||||
|  | 
 | ||||||
|  |     cmd_buff[0] = IPC::MakeHeader(0x0845, 5, 0); | ||||||
|  | 
 | ||||||
|  |     auto format_info = GetArchiveFormatInfo(archive_id, archive_path); | ||||||
|  | 
 | ||||||
|  |     if (format_info.Failed()) { | ||||||
|  |         LOG_ERROR(Service_FS, "Failed to retrieve the format info"); | ||||||
|  |         cmd_buff[1] = format_info.Code().raw; | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     cmd_buff[1] = RESULT_SUCCESS.raw; | ||||||
|  |     cmd_buff[2] = format_info->total_size; | ||||||
|  |     cmd_buff[3] = format_info->number_directories; | ||||||
|  |     cmd_buff[4] = format_info->number_files; | ||||||
|  |     cmd_buff[5] = format_info->duplicate_data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const Interface::FunctionInfo FunctionTable[] = { | const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x000100C6, nullptr,                  "Dummy1"}, |     {0x000100C6, nullptr,                  "Dummy1"}, | ||||||
|     {0x040100C4, nullptr,                  "Control"}, |     {0x040100C4, nullptr,                  "Control"}, | ||||||
|  | @ -802,7 +873,7 @@ const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x08420040, nullptr,                  "DeleteAllExtSaveDataOnNand"}, |     {0x08420040, nullptr,                  "DeleteAllExtSaveDataOnNand"}, | ||||||
|     {0x08430000, nullptr,                  "InitializeCtrFileSystem"}, |     {0x08430000, nullptr,                  "InitializeCtrFileSystem"}, | ||||||
|     {0x08440000, nullptr,                  "CreateSeed"}, |     {0x08440000, nullptr,                  "CreateSeed"}, | ||||||
|     {0x084500C2, nullptr,                  "GetFormatInfo"}, |     {0x084500C2, GetFormatInfo,            "GetFormatInfo"}, | ||||||
|     {0x08460102, nullptr,                  "GetLegacyRomHeader2"}, |     {0x08460102, nullptr,                  "GetLegacyRomHeader2"}, | ||||||
|     {0x08470180, nullptr,                  "FormatCtrCardUserSaveData"}, |     {0x08470180, nullptr,                  "FormatCtrCardUserSaveData"}, | ||||||
|     {0x08480042, nullptr,                  "GetSdmcCtrRootPath"}, |     {0x08480042, nullptr,                  "GetSdmcCtrRootPath"}, | ||||||
|  |  | ||||||
|  | @ -103,7 +103,7 @@ void Init() { | ||||||
|     // If the archive didn't exist, create the files inside
 |     // If the archive didn't exist, create the files inside
 | ||||||
|     if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { |     if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { | ||||||
|         // Format the archive to create the directories
 |         // Format the archive to create the directories
 | ||||||
|         Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); |         Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, FileSys::ArchiveFormatInfo(), archive_path); | ||||||
|         // Open it again to get a valid archive now that the folder exists
 |         // Open it again to get a valid archive now that the folder exists
 | ||||||
|         archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); |         archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); | ||||||
|         ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); |         ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue