mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge pull request #4618 from wwylele/fs-clean
FS: pass down program ID for archive operation (cleanup System::GetInstance part 3)
This commit is contained in:
		
						commit
						9c57b74907
					
				
					 24 changed files with 165 additions and 99 deletions
				
			
		|  | @ -167,24 +167,28 @@ public: | |||
|     /**
 | ||||
|      * Tries to open the archive of this type with the specified path | ||||
|      * @param path Path to the archive | ||||
|      * @param program_id the program ID of the client that requests the operation | ||||
|      * @return An ArchiveBackend corresponding operating specified archive path. | ||||
|      */ | ||||
|     virtual ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) = 0; | ||||
|     virtual ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Deletes the archive contents and then re-creates the base folder | ||||
|      * @param path Path to the archive | ||||
|      * @param format_info Format information for the new archive | ||||
|      * @param program_id the program ID of the client that requests the operation | ||||
|      * @return ResultCode of the operation, 0 on success | ||||
|      */ | ||||
|     virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) = 0; | ||||
|     virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                               u64 program_id) = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Retrieves the format info about the archive with the specified path | ||||
|      * @param path Path to the archive | ||||
|      * @param program_id the program ID of the client that requests the operation | ||||
|      * @return Format information about the archive or error code | ||||
|      */ | ||||
|     virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const = 0; | ||||
|     virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const = 0; | ||||
| }; | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
|  |  | |||
|  | @ -220,7 +220,8 @@ Path ArchiveFactory_ExtSaveData::GetCorrectedPath(const Path& path) { | |||
|     return {binary_data}; | ||||
| } | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) { | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path, | ||||
|                                                                             u64 program_id) { | ||||
|     std::string fullpath = GetExtSaveDataPath(mount_point, GetCorrectedPath(path)) + "user/"; | ||||
|     if (!FileUtil::Exists(fullpath)) { | ||||
|         // TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData.
 | ||||
|  | @ -236,7 +237,8 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons | |||
| } | ||||
| 
 | ||||
| ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path, | ||||
|                                               const FileSys::ArchiveFormatInfo& format_info) { | ||||
|                                               const FileSys::ArchiveFormatInfo& format_info, | ||||
|                                               u64 program_id) { | ||||
|     auto corrected_path = GetCorrectedPath(path); | ||||
| 
 | ||||
|     // These folders are always created with the ExtSaveData
 | ||||
|  | @ -258,7 +260,8 @@ ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path, | |||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path) const { | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path, | ||||
|                                                                        u64 program_id) const { | ||||
|     std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata"; | ||||
|     FileUtil::IOFile file(metadata_path, "rb"); | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,9 +24,10 @@ public: | |||
|         return "ExtSaveData"; | ||||
|     } | ||||
| 
 | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                       u64 program_id) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override; | ||||
| 
 | ||||
|     const std::string& GetMountPoint() const { | ||||
|         return mount_point; | ||||
|  |  | |||
|  | @ -269,7 +269,8 @@ bool NCCHFile::SetSize(const u64 size) const { | |||
| 
 | ||||
| ArchiveFactory_NCCH::ArchiveFactory_NCCH() {} | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path& path) { | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path& path, | ||||
|                                                                      u64 program_id) { | ||||
|     if (path.GetType() != LowPathType::Binary) { | ||||
|         LOG_ERROR(Service_FS, "Path need to be Binary"); | ||||
|         return ERROR_INVALID_PATH; | ||||
|  | @ -290,14 +291,16 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path& | |||
| } | ||||
| 
 | ||||
| ResultCode ArchiveFactory_NCCH::Format(const Path& path, | ||||
|                                        const FileSys::ArchiveFormatInfo& format_info) { | ||||
|                                        const FileSys::ArchiveFormatInfo& format_info, | ||||
|                                        u64 program_id) { | ||||
|     LOG_ERROR(Service_FS, "Attempted to format a NCCH archive."); | ||||
|     // TODO: Verify error code
 | ||||
|     return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, | ||||
|                       ErrorLevel::Permanent); | ||||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_NCCH::GetFormatInfo(const Path& path) const { | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_NCCH::GetFormatInfo(const Path& path, | ||||
|                                                                 u64 program_id) const { | ||||
|     // TODO(Subv): Implement
 | ||||
|     LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName()); | ||||
|     return ResultCode(-1); | ||||
|  |  | |||
|  | @ -95,9 +95,10 @@ public: | |||
|         return "NCCH"; | ||||
|     } | ||||
| 
 | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                       u64 program_id) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override; | ||||
| }; | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
|  |  | |||
|  | @ -64,7 +64,7 @@ ArchiveFactory_OtherSaveDataPermitted::ArchiveFactory_OtherSaveDataPermitted( | |||
|     : sd_savedata_source(std::move(sd_savedata)) {} | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataPermitted::Open( | ||||
|     const Path& path) { | ||||
|     const Path& path, u64 /*client_program_id*/) { | ||||
|     MediaType media_type; | ||||
|     u64 program_id; | ||||
|     CASCADE_RESULT(std::tie(media_type, program_id), ParsePathPermitted(path)); | ||||
|  | @ -78,13 +78,13 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataPermitted | |||
| } | ||||
| 
 | ||||
| ResultCode ArchiveFactory_OtherSaveDataPermitted::Format( | ||||
|     const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | ||||
|     const Path& path, const FileSys::ArchiveFormatInfo& format_info, u64 program_id) { | ||||
|     LOG_ERROR(Service_FS, "Attempted to format a OtherSaveDataPermitted archive."); | ||||
|     return ERROR_INVALID_PATH; | ||||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataPermitted::GetFormatInfo( | ||||
|     const Path& path) const { | ||||
|     const Path& path, u64 /*client_program_id*/) const { | ||||
|     MediaType media_type; | ||||
|     u64 program_id; | ||||
|     CASCADE_RESULT(std::tie(media_type, program_id), ParsePathPermitted(path)); | ||||
|  | @ -102,7 +102,7 @@ ArchiveFactory_OtherSaveDataGeneral::ArchiveFactory_OtherSaveDataGeneral( | |||
|     : sd_savedata_source(std::move(sd_savedata)) {} | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataGeneral::Open( | ||||
|     const Path& path) { | ||||
|     const Path& path, u64 /*client_program_id*/) { | ||||
|     MediaType media_type; | ||||
|     u64 program_id; | ||||
|     CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); | ||||
|  | @ -116,7 +116,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataGeneral:: | |||
| } | ||||
| 
 | ||||
| ResultCode ArchiveFactory_OtherSaveDataGeneral::Format( | ||||
|     const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | ||||
|     const Path& path, const FileSys::ArchiveFormatInfo& format_info, u64 /*client_program_id*/) { | ||||
|     MediaType media_type; | ||||
|     u64 program_id; | ||||
|     CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); | ||||
|  | @ -130,7 +130,7 @@ ResultCode ArchiveFactory_OtherSaveDataGeneral::Format( | |||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataGeneral::GetFormatInfo( | ||||
|     const Path& path) const { | ||||
|     const Path& path, u64 /*client_program_id*/) const { | ||||
|     MediaType media_type; | ||||
|     u64 program_id; | ||||
|     CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); | ||||
|  |  | |||
|  | @ -21,9 +21,10 @@ public: | |||
|         return "OtherSaveDataPermitted"; | ||||
|     } | ||||
| 
 | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                       u64 program_id) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override; | ||||
| 
 | ||||
| private: | ||||
|     std::string mount_point; | ||||
|  | @ -40,9 +41,10 @@ public: | |||
|         return "OtherSaveDataGeneral"; | ||||
|     } | ||||
| 
 | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                       u64 program_id) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override; | ||||
| 
 | ||||
| private: | ||||
|     std::string mount_point; | ||||
|  |  | |||
|  | @ -16,20 +16,20 @@ ArchiveFactory_SaveData::ArchiveFactory_SaveData( | |||
|     std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata) | ||||
|     : sd_savedata_source(std::move(sd_savedata)) {} | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) { | ||||
|     return sd_savedata_source->Open( | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id); | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path, | ||||
|                                                                          u64 program_id) { | ||||
|     return sd_savedata_source->Open(program_id); | ||||
| } | ||||
| 
 | ||||
| ResultCode ArchiveFactory_SaveData::Format(const Path& path, | ||||
|                                            const FileSys::ArchiveFormatInfo& format_info) { | ||||
|     return sd_savedata_source->Format( | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id, format_info); | ||||
|                                            const FileSys::ArchiveFormatInfo& format_info, | ||||
|                                            u64 program_id) { | ||||
|     return sd_savedata_source->Format(program_id, format_info); | ||||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const { | ||||
|     return sd_savedata_source->GetFormatInfo( | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id); | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path, | ||||
|                                                                     u64 program_id) const { | ||||
|     return sd_savedata_source->GetFormatInfo(program_id); | ||||
| } | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
|  |  | |||
|  | @ -20,10 +20,11 @@ public: | |||
|         return "SaveData"; | ||||
|     } | ||||
| 
 | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                       u64 program_id) override; | ||||
| 
 | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override; | ||||
| 
 | ||||
| private: | ||||
|     std::string mount_point; | ||||
|  |  | |||
|  | @ -376,18 +376,21 @@ bool ArchiveFactory_SDMC::Initialize() { | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path& path) { | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path& path, | ||||
|                                                                      u64 program_id) { | ||||
|     auto archive = std::make_unique<SDMCArchive>(sdmc_directory); | ||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||
| } | ||||
| 
 | ||||
| ResultCode ArchiveFactory_SDMC::Format(const Path& path, | ||||
|                                        const FileSys::ArchiveFormatInfo& format_info) { | ||||
|                                        const FileSys::ArchiveFormatInfo& format_info, | ||||
|                                        u64 program_id) { | ||||
|     // This is kind of an undesirable operation, so let's just ignore it. :)
 | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path) const { | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path, | ||||
|                                                                 u64 program_id) const { | ||||
|     // TODO(Subv): Implement
 | ||||
|     LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName()); | ||||
|     return ResultCode(-1); | ||||
|  |  | |||
|  | @ -55,9 +55,10 @@ public: | |||
|         return "SDMC"; | ||||
|     } | ||||
| 
 | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                       u64 program_id) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override; | ||||
| 
 | ||||
| private: | ||||
|     std::string sdmc_directory; | ||||
|  |  | |||
|  | @ -49,19 +49,22 @@ bool ArchiveFactory_SDMCWriteOnly::Initialize() { | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMCWriteOnly::Open(const Path& path) { | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMCWriteOnly::Open(const Path& path, | ||||
|                                                                               u64 program_id) { | ||||
|     auto archive = std::make_unique<SDMCWriteOnlyArchive>(sdmc_directory); | ||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||
| } | ||||
| 
 | ||||
| ResultCode ArchiveFactory_SDMCWriteOnly::Format(const Path& path, | ||||
|                                                 const FileSys::ArchiveFormatInfo& format_info) { | ||||
|                                                 const FileSys::ArchiveFormatInfo& format_info, | ||||
|                                                 u64 program_id) { | ||||
|     // TODO(wwylele): hwtest this
 | ||||
|     LOG_ERROR(Service_FS, "Attempted to format a SDMC write-only archive."); | ||||
|     return ResultCode(-1); | ||||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMCWriteOnly::GetFormatInfo(const Path& path) const { | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMCWriteOnly::GetFormatInfo(const Path& path, | ||||
|                                                                          u64 program_id) const { | ||||
|     // TODO(Subv): Implement
 | ||||
|     LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName()); | ||||
|     return ResultCode(-1); | ||||
|  |  | |||
|  | @ -46,9 +46,10 @@ public: | |||
|         return "SDMCWriteOnly"; | ||||
|     } | ||||
| 
 | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                       u64 program_id) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override; | ||||
| 
 | ||||
| private: | ||||
|     std::string sdmc_directory; | ||||
|  |  | |||
|  | @ -278,18 +278,20 @@ void ArchiveFactory_SelfNCCH::Register(Loader::AppLoader& app_loader) { | |||
|         data.banner = std::make_shared<std::vector<u8>>(std::move(buffer)); | ||||
| } | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) { | ||||
|     auto archive = std::make_unique<SelfNCCHArchive>( | ||||
|         ncch_data[Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id]); | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path, | ||||
|                                                                          u64 program_id) { | ||||
|     auto archive = std::make_unique<SelfNCCHArchive>(ncch_data[program_id]); | ||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||
| } | ||||
| 
 | ||||
| ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&) { | ||||
| ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&, | ||||
|                                            u64 program_id) { | ||||
|     LOG_ERROR(Service_FS, "Attempted to format a SelfNCCH archive."); | ||||
|     return ERROR_INVALID_PATH; | ||||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SelfNCCH::GetFormatInfo(const Path&) const { | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SelfNCCH::GetFormatInfo(const Path&, | ||||
|                                                                     u64 program_id) const { | ||||
|     LOG_ERROR(Service_FS, "Attempted to get format info of a SelfNCCH archive"); | ||||
|     return ERROR_INVALID_PATH; | ||||
| } | ||||
|  |  | |||
|  | @ -37,9 +37,10 @@ public: | |||
|     std::string GetName() const override { | ||||
|         return "SelfNCCH"; | ||||
|     } | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                       u64 program_id) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override; | ||||
| 
 | ||||
| private: | ||||
|     /// Mapping of ProgramId -> NCCHData
 | ||||
|  |  | |||
|  | @ -52,7 +52,8 @@ Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low) { | |||
| ArchiveFactory_SystemSaveData::ArchiveFactory_SystemSaveData(const std::string& nand_path) | ||||
|     : base_path(GetSystemSaveDataContainerPath(nand_path)) {} | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(const Path& path) { | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(const Path& path, | ||||
|                                                                                u64 program_id) { | ||||
|     std::string fullpath = GetSystemSaveDataPath(base_path, path); | ||||
|     if (!FileUtil::Exists(fullpath)) { | ||||
|         // TODO(Subv): Check error code, this one is probably wrong
 | ||||
|  | @ -63,14 +64,16 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c | |||
| } | ||||
| 
 | ||||
| ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path, | ||||
|                                                  const FileSys::ArchiveFormatInfo& format_info) { | ||||
|                                                  const FileSys::ArchiveFormatInfo& format_info, | ||||
|                                                  u64 program_id) { | ||||
|     std::string fullpath = GetSystemSaveDataPath(base_path, path); | ||||
|     FileUtil::DeleteDirRecursively(fullpath); | ||||
|     FileUtil::CreateFullPath(fullpath); | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const Path& path) const { | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const Path& path, | ||||
|                                                                           u64 program_id) const { | ||||
|     // TODO(Subv): Implement
 | ||||
|     LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName()); | ||||
|     return ResultCode(-1); | ||||
|  |  | |||
|  | @ -20,9 +20,10 @@ class ArchiveFactory_SystemSaveData final : public ArchiveFactory { | |||
| public: | ||||
|     explicit ArchiveFactory_SystemSaveData(const std::string& mount_point); | ||||
| 
 | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path, u64 program_id) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                       u64 program_id) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override; | ||||
| 
 | ||||
|     std::string GetName() const override { | ||||
|         return "SystemSaveData"; | ||||
|  |  | |||
|  | @ -1362,7 +1362,7 @@ Module::Module(Core::System& system) : system(system) { | |||
| 
 | ||||
|     // Open the SystemSaveData archive 0x00010026
 | ||||
|     FileSys::Path archive_path(cecd_system_savedata_id); | ||||
|     auto archive_result = systemsavedata_factory.Open(archive_path); | ||||
|     auto archive_result = systemsavedata_factory.Open(archive_path, 0); | ||||
| 
 | ||||
|     // If the archive didn't exist, create the files inside
 | ||||
|     if (archive_result.Code() != FileSys::ERR_NOT_FORMATTED) { | ||||
|  | @ -1370,10 +1370,10 @@ Module::Module(Core::System& system) : system(system) { | |||
|         cecd_system_save_data_archive = std::move(archive_result).Unwrap(); | ||||
|     } else { | ||||
|         // Format the archive to create the directories
 | ||||
|         systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo()); | ||||
|         systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0); | ||||
| 
 | ||||
|         // Open it again to get a valid archive now that the folder exists
 | ||||
|         cecd_system_save_data_archive = systemsavedata_factory.Open(archive_path).Unwrap(); | ||||
|         cecd_system_save_data_archive = systemsavedata_factory.Open(archive_path, 0).Unwrap(); | ||||
| 
 | ||||
|         /// Now that the archive is formatted, we need to create the root CEC directory,
 | ||||
|         /// eventlog.dat, and CEC/MBoxList____
 | ||||
|  |  | |||
|  | @ -531,15 +531,15 @@ ResultCode Module::LoadConfigNANDSaveFile() { | |||
| 
 | ||||
|     // Open the SystemSaveData archive 0x00010017
 | ||||
|     FileSys::Path archive_path(cfg_system_savedata_id); | ||||
|     auto archive_result = systemsavedata_factory.Open(archive_path); | ||||
|     auto archive_result = systemsavedata_factory.Open(archive_path, 0); | ||||
| 
 | ||||
|     // If the archive didn't exist, create the files inside
 | ||||
|     if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { | ||||
|         // Format the archive to create the directories
 | ||||
|         systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo()); | ||||
|         systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0); | ||||
| 
 | ||||
|         // Open it again to get a valid archive now that the folder exists
 | ||||
|         cfg_system_save_data_archive = systemsavedata_factory.Open(archive_path).Unwrap(); | ||||
|         cfg_system_save_data_archive = systemsavedata_factory.Open(archive_path, 0).Unwrap(); | ||||
|     } else { | ||||
|         ASSERT_MSG(archive_result.Succeeded(), "Could not open the CFG SystemSaveData archive!"); | ||||
| 
 | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ ArchiveBackend* ArchiveManager::GetArchive(ArchiveHandle handle) { | |||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveHandle> ArchiveManager::OpenArchive(ArchiveIdCode id_code, | ||||
|                                                      FileSys::Path& archive_path) { | ||||
|                                                      FileSys::Path& archive_path, u64 program_id) { | ||||
|     LOG_TRACE(Service_FS, "Opening archive with id code 0x{:08X}", static_cast<u32>(id_code)); | ||||
| 
 | ||||
|     auto itr = id_code_map.find(id_code); | ||||
|  | @ -44,7 +44,8 @@ ResultVal<ArchiveHandle> ArchiveManager::OpenArchive(ArchiveIdCode id_code, | |||
|         return FileSys::ERROR_NOT_FOUND; | ||||
|     } | ||||
| 
 | ||||
|     CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path)); | ||||
|     CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, | ||||
|                    itr->second->Open(archive_path, program_id)); | ||||
| 
 | ||||
|     // This should never even happen in the first place with 64-bit handles,
 | ||||
|     while (handle_map.count(next_handle) != 0) { | ||||
|  | @ -193,28 +194,29 @@ ResultVal<u64> ArchiveManager::GetFreeBytesInArchive(ArchiveHandle archive_handl | |||
| 
 | ||||
| ResultCode ArchiveManager::FormatArchive(ArchiveIdCode id_code, | ||||
|                                          const FileSys::ArchiveFormatInfo& format_info, | ||||
|                                          const FileSys::Path& path) { | ||||
|                                          const FileSys::Path& path, u64 program_id) { | ||||
|     auto archive_itr = id_code_map.find(id_code); | ||||
|     if (archive_itr == id_code_map.end()) { | ||||
|         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
 | ||||
|     } | ||||
| 
 | ||||
|     return archive_itr->second->Format(path, format_info); | ||||
|     return archive_itr->second->Format(path, format_info, program_id); | ||||
| } | ||||
| 
 | ||||
| ResultVal<FileSys::ArchiveFormatInfo> ArchiveManager::GetArchiveFormatInfo( | ||||
|     ArchiveIdCode id_code, FileSys::Path& archive_path) { | ||||
|     ArchiveIdCode id_code, FileSys::Path& archive_path, u64 program_id) { | ||||
|     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); | ||||
|     return archive->second->GetFormatInfo(archive_path, program_id); | ||||
| } | ||||
| 
 | ||||
| ResultCode ArchiveManager::CreateExtSaveData(MediaType media_type, u32 high, u32 low, | ||||
|                                              const std::vector<u8>& smdh_icon, | ||||
|                                              const FileSys::ArchiveFormatInfo& format_info) { | ||||
|                                              const FileSys::ArchiveFormatInfo& format_info, | ||||
|                                              u64 program_id) { | ||||
|     // Construct the binary path to the archive first
 | ||||
|     FileSys::Path path = | ||||
|         FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); | ||||
|  | @ -228,7 +230,7 @@ ResultCode ArchiveManager::CreateExtSaveData(MediaType media_type, u32 high, u32 | |||
| 
 | ||||
|     auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get()); | ||||
| 
 | ||||
|     ResultCode result = ext_savedata->Format(path, format_info); | ||||
|     ResultCode result = ext_savedata->Format(path, format_info, program_id); | ||||
|     if (result.IsError()) | ||||
|         return result; | ||||
| 
 | ||||
|  |  | |||
|  | @ -60,9 +60,11 @@ public: | |||
|      * Opens an archive | ||||
|      * @param id_code IdCode of the archive to open | ||||
|      * @param archive_path Path to the archive, used with Binary paths | ||||
|      * @param program_id the program ID of the client that requests the operation | ||||
|      * @return Handle to the opened archive | ||||
|      */ | ||||
|     ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path); | ||||
|     ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path, | ||||
|                                          u64 program_id); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Closes an archive | ||||
|  | @ -172,20 +174,23 @@ public: | |||
|      * @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 program_id the program ID of the client that requests the operation | ||||
|      * @return ResultCode 0 on success or the corresponding code on error | ||||
|      */ | ||||
|     ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, | ||||
|                              const FileSys::Path& path = FileSys::Path()); | ||||
|                              const FileSys::Path& path, u64 program_id); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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 | ||||
|      * @param program_id the program ID of the client that requests the operation | ||||
|      * @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); | ||||
|                                                                FileSys::Path& archive_path, | ||||
|                                                                u64 program_id); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Creates a blank SharedExtSaveData archive for the specified extdata ID | ||||
|  | @ -194,11 +199,12 @@ public: | |||
|      * @param low The low word of the extdata id to create | ||||
|      * @param smdh_icon the SMDH icon for this ExtSaveData | ||||
|      * @param format_info Format information about the new archive | ||||
|      * @param program_id the program ID of the client that requests the operation | ||||
|      * @return ResultCode 0 on success or the corresponding code on error | ||||
|      */ | ||||
|     ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, | ||||
|                                  const std::vector<u8>& smdh_icon, | ||||
|                                  const FileSys::ArchiveFormatInfo& format_info); | ||||
|                                  const FileSys::ArchiveFormatInfo& format_info, u64 program_id); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Deletes the SharedExtSaveData archive for the specified extdata ID | ||||
|  |  | |||
|  | @ -35,7 +35,10 @@ namespace Service::FS { | |||
| 
 | ||||
| void FS_USER::Initialize(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp(ctx, 0x0801, 0, 2); | ||||
|     rp.PopPID(); | ||||
|     u32 pid = rp.PopPID(); | ||||
| 
 | ||||
|     ClientSlot* slot = GetSessionData(ctx.Session()); | ||||
|     slot->program_id = system.Kernel().GetProcessById(pid)->codeset->program_id; | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|  | @ -93,7 +96,10 @@ void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) { | |||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||
| 
 | ||||
|     ResultVal<ArchiveHandle> archive_handle = archives.OpenArchive(archive_id, archive_path); | ||||
|     ClientSlot* slot = GetSessionData(ctx.Session()); | ||||
| 
 | ||||
|     ResultVal<ArchiveHandle> archive_handle = | ||||
|         archives.OpenArchive(archive_id, archive_path, slot->program_id); | ||||
|     if (archive_handle.Failed()) { | ||||
|         LOG_ERROR(Service_FS, | ||||
|                   "Failed to get a handle for archive archive_id=0x{:08X} archive_path={}", | ||||
|  | @ -309,7 +315,9 @@ void FS_USER::OpenArchive(Kernel::HLERequestContext& ctx) { | |||
|               archive_path.DebugStr()); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); | ||||
|     ResultVal<ArchiveHandle> handle = archives.OpenArchive(archive_id, archive_path); | ||||
|     ClientSlot* slot = GetSessionData(ctx.Session()); | ||||
|     ResultVal<ArchiveHandle> handle = | ||||
|         archives.OpenArchive(archive_id, archive_path, slot->program_id); | ||||
|     rb.Push(handle.Code()); | ||||
|     if (handle.Succeeded()) { | ||||
|         rb.PushRaw(*handle); | ||||
|  | @ -385,7 +393,9 @@ void FS_USER::FormatSaveData(Kernel::HLERequestContext& ctx) { | |||
|     format_info.number_files = number_files; | ||||
|     format_info.total_size = block_size * 512; | ||||
| 
 | ||||
|     rb.Push(archives.FormatArchive(ArchiveIdCode::SaveData, format_info)); | ||||
|     ClientSlot* slot = GetSessionData(ctx.Session()); | ||||
|     rb.Push(archives.FormatArchive(ArchiveIdCode::SaveData, format_info, archive_path, | ||||
|                                    slot->program_id)); | ||||
| } | ||||
| 
 | ||||
| void FS_USER::FormatThisUserSaveData(Kernel::HLERequestContext& ctx) { | ||||
|  | @ -404,7 +414,9 @@ void FS_USER::FormatThisUserSaveData(Kernel::HLERequestContext& ctx) { | |||
|     format_info.total_size = block_size * 512; | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|     rb.Push(archives.FormatArchive(ArchiveIdCode::SaveData, format_info)); | ||||
|     ClientSlot* slot = GetSessionData(ctx.Session()); | ||||
|     rb.Push(archives.FormatArchive(ArchiveIdCode::SaveData, format_info, FileSys::Path(), | ||||
|                                    slot->program_id)); | ||||
| 
 | ||||
|     LOG_TRACE(Service_FS, "called"); | ||||
| } | ||||
|  | @ -446,7 +458,9 @@ void FS_USER::CreateExtSaveData(Kernel::HLERequestContext& ctx) { | |||
|     format_info.total_size = 0; | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||
|     rb.Push(archives.CreateExtSaveData(media_type, save_high, save_low, icon, format_info)); | ||||
|     ClientSlot* slot = GetSessionData(ctx.Session()); | ||||
|     rb.Push(archives.CreateExtSaveData(media_type, save_high, save_low, icon, format_info, | ||||
|                                        slot->program_id)); | ||||
|     rb.PushMappedBuffer(icon_buffer); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_FS, | ||||
|  | @ -535,7 +549,10 @@ void FS_USER::CreateLegacySystemSaveData(Kernel::HLERequestContext& ctx) { | |||
| void FS_USER::InitializeWithSdkVersion(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp(ctx, 0x861, 1, 2); | ||||
|     const u32 version = rp.Pop<u32>(); | ||||
|     rp.PopPID(); | ||||
|     u32 pid = rp.PopPID(); | ||||
| 
 | ||||
|     ClientSlot* slot = GetSessionData(ctx.Session()); | ||||
|     slot->program_id = system.Kernel().GetProcessById(pid)->codeset->program_id; | ||||
| 
 | ||||
|     LOG_WARNING(Service_FS, "(STUBBED) called, version: 0x{:08X}", version); | ||||
| 
 | ||||
|  | @ -595,8 +612,8 @@ void FS_USER::GetFormatInfo(Kernel::HLERequestContext& ctx) { | |||
|     LOG_DEBUG(Service_FS, "archive_path={}", archive_path.DebugStr()); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); | ||||
| 
 | ||||
|     auto format_info = archives.GetArchiveFormatInfo(archive_id, archive_path); | ||||
|     ClientSlot* slot = GetSessionData(ctx.Session()); | ||||
|     auto format_info = archives.GetArchiveFormatInfo(archive_id, archive_path, slot->program_id); | ||||
|     rb.Push(format_info.Code()); | ||||
|     if (format_info.Failed()) { | ||||
|         LOG_ERROR(Service_FS, "Failed to retrieve the format info"); | ||||
|  | @ -664,7 +681,9 @@ void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) { | |||
|     format_info.total_size = 0; | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||
|     rb.Push(archives.CreateExtSaveData(media_type, save_high, save_low, icon, format_info)); | ||||
|     ClientSlot* slot = GetSessionData(ctx.Session()); | ||||
|     rb.Push(archives.CreateExtSaveData(media_type, save_high, save_low, icon, format_info, | ||||
|                                        slot->program_id)); | ||||
|     rb.PushMappedBuffer(icon_buffer); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_FS, | ||||
|  |  | |||
|  | @ -15,7 +15,16 @@ namespace Service::FS { | |||
| 
 | ||||
| class ArchiveManager; | ||||
| 
 | ||||
| class FS_USER final : public ServiceFramework<FS_USER> { | ||||
| struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase { | ||||
|     // We retrieves program ID for client process on FS::Initialize(WithSDKVersion)
 | ||||
|     // Real 3DS matches program ID and process ID based on data registered by loader via fs:REG, so
 | ||||
|     // theoretically the program ID for FS client and for process codeset can mismatch if the loader
 | ||||
|     // behaviour is modified. Since we don't emulate fs:REG mechanism, we assume the program ID is
 | ||||
|     // the same as codeset ID and fetch from there directly.
 | ||||
|     u64 program_id = 0; | ||||
| }; | ||||
| 
 | ||||
| class FS_USER final : public ServiceFramework<FS_USER, ClientSlot> { | ||||
| public: | ||||
|     explicit FS_USER(Core::System& system); | ||||
| 
 | ||||
|  |  | |||
|  | @ -143,16 +143,16 @@ static void WriteGameCoinData(GameCoin gamecoin_data) { | |||
|     FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); | ||||
| 
 | ||||
|     FileSys::Path archive_path(ptm_shared_extdata_id); | ||||
|     auto archive_result = extdata_archive_factory.Open(archive_path); | ||||
|     auto archive_result = extdata_archive_factory.Open(archive_path, 0); | ||||
|     std::unique_ptr<FileSys::ArchiveBackend> archive; | ||||
| 
 | ||||
|     FileSys::Path gamecoin_path("/gamecoin.dat"); | ||||
|     // If the archive didn't exist, create the files inside
 | ||||
|     if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { | ||||
|         // Format the archive to create the directories
 | ||||
|         extdata_archive_factory.Format(archive_path, FileSys::ArchiveFormatInfo()); | ||||
|         extdata_archive_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0); | ||||
|         // Open it again to get a valid archive now that the folder exists
 | ||||
|         archive = extdata_archive_factory.Open(archive_path).Unwrap(); | ||||
|         archive = extdata_archive_factory.Open(archive_path, 0).Unwrap(); | ||||
|         // Create the game coin file
 | ||||
|         archive->CreateFile(gamecoin_path, sizeof(GameCoin)); | ||||
|     } else { | ||||
|  | @ -176,7 +176,7 @@ static GameCoin ReadGameCoinData() { | |||
|     FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); | ||||
| 
 | ||||
|     FileSys::Path archive_path(ptm_shared_extdata_id); | ||||
|     auto archive_result = extdata_archive_factory.Open(archive_path); | ||||
|     auto archive_result = extdata_archive_factory.Open(archive_path, 0); | ||||
|     if (!archive_result.Succeeded()) { | ||||
|         LOG_ERROR(Service_PTM, "Could not open the PTM SharedExtSaveData archive!"); | ||||
|         return default_game_coin; | ||||
|  | @ -205,7 +205,7 @@ Module::Module() { | |||
|     std::string nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); | ||||
|     FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); | ||||
|     FileSys::Path archive_path(ptm_shared_extdata_id); | ||||
|     auto archive_result = extdata_archive_factory.Open(archive_path); | ||||
|     auto archive_result = extdata_archive_factory.Open(archive_path, 0); | ||||
|     // If the archive didn't exist, write the default game coin file
 | ||||
|     if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { | ||||
|         WriteGameCoinData(default_game_coin); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue