mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Services/FS: Implemented DeleteExtSaveData, CreateSystemSaveData and DeleteSystemSaveData
Also fixed a bug with CreateExtSaveData that made it unable to create ExtSaveData archives in the SDMC directory.
This commit is contained in:
		
							parent
							
								
									ed5b275d21
								
							
						
					
					
						commit
						1d61cd4460
					
				
					 7 changed files with 240 additions and 26 deletions
				
			
		|  | @ -34,6 +34,27 @@ std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) | |||
|             SYSTEM_ID.c_str(), SDCARD_ID.c_str()); | ||||
| } | ||||
| 
 | ||||
| Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) { | ||||
|     std::vector<u8> binary_path; | ||||
|     binary_path.reserve(12); | ||||
| 
 | ||||
|     // Append each word byte by byte
 | ||||
| 
 | ||||
|     // The first word is the media type
 | ||||
|     for (unsigned i = 0; i < 4; ++i) | ||||
|         binary_path.push_back((media_type >> (8 * i)) & 0xFF); | ||||
| 
 | ||||
|     // Next is the low word
 | ||||
|     for (unsigned i = 0; i < 4; ++i) | ||||
|         binary_path.push_back((low >> (8 * i)) & 0xFF); | ||||
| 
 | ||||
|     // Next is the high word
 | ||||
|     for (unsigned i = 0; i < 4; ++i) | ||||
|         binary_path.push_back((high >> (8 * i)) & 0xFF); | ||||
| 
 | ||||
|     return { binary_path }; | ||||
| } | ||||
| 
 | ||||
| ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, bool shared) | ||||
|         : mount_point(GetExtDataContainerPath(mount_location, shared)) { | ||||
|     LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str()); | ||||
|  |  | |||
|  | @ -58,4 +58,14 @@ std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path) | |||
|  */ | ||||
| std::string GetExtDataContainerPath(const std::string& mount_point, bool shared); | ||||
| 
 | ||||
| /**
 | ||||
|  * Constructs a FileSys::Path object that refers to the ExtData archive identified by | ||||
|  * the specified media type, high save id and low save id. | ||||
|  * @param media_type The media type where the archive is located (NAND / SDMC) | ||||
|  * @param high The high word of the save id for the archive | ||||
|  * @param low The low word of the save id for the archive | ||||
|  * @returns A FileSys::Path to the wanted archive | ||||
|  */ | ||||
| Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low); | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ | |||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| static std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path) { | ||||
| std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path) { | ||||
|     std::vector<u8> vec_data = path.AsBinary(); | ||||
|     const u32* data = reinterpret_cast<const u32*>(vec_data.data()); | ||||
|     u32 save_low = data[1]; | ||||
|  | @ -25,10 +25,27 @@ static std::string GetSystemSaveDataPath(const std::string& mount_point, const P | |||
|     return Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), save_low, save_high); | ||||
| } | ||||
| 
 | ||||
| static std::string GetSystemSaveDataContainerPath(const std::string& mount_point) { | ||||
| std::string GetSystemSaveDataContainerPath(const std::string& mount_point) { | ||||
|     return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID.c_str()); | ||||
| } | ||||
| 
 | ||||
| Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low) { | ||||
|     std::vector<u8> binary_path; | ||||
|     binary_path.reserve(8); | ||||
| 
 | ||||
|     // Append each word byte by byte
 | ||||
| 
 | ||||
|     // First is the high word
 | ||||
|     for (unsigned i = 0; i < 4; ++i) | ||||
|         binary_path.push_back((high >> (8 * i)) & 0xFF); | ||||
| 
 | ||||
|     // Next is the low word
 | ||||
|     for (unsigned i = 0; i < 4; ++i) | ||||
|         binary_path.push_back((low >> (8 * i)) & 0xFF); | ||||
| 
 | ||||
|     return { binary_path }; | ||||
| } | ||||
| 
 | ||||
| ArchiveFactory_SystemSaveData::ArchiveFactory_SystemSaveData(const std::string& nand_path) | ||||
|         : base_path(GetSystemSaveDataContainerPath(nand_path)) { | ||||
| } | ||||
|  | @ -46,6 +63,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c | |||
| 
 | ||||
| ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path) { | ||||
|     std::string fullpath = GetSystemSaveDataPath(base_path, path); | ||||
|     FileUtil::DeleteDirRecursively(fullpath); | ||||
|     FileUtil::CreateFullPath(fullpath); | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
|  |  | |||
|  | @ -28,4 +28,29 @@ private: | |||
|     std::string base_path; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Constructs a path to the concrete SystemSaveData archive in the host filesystem based on the | ||||
|  * input Path and base mount point. | ||||
|  * @param mount_point The base mount point of the SystemSaveData archives. | ||||
|  * @param path The path that identifies the requested concrete SystemSaveData archive. | ||||
|  * @returns The complete path to the specified SystemSaveData archive in the host filesystem | ||||
|  */ | ||||
| std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path); | ||||
| 
 | ||||
| /**
 | ||||
|  * Constructs a path to the base folder to hold concrete SystemSaveData archives in the host file system. | ||||
|  * @param mount_point The base folder where this folder resides, ie. SDMC or NAND. | ||||
|  * @returns The path to the base SystemSaveData archives' folder in the host file system | ||||
|  */ | ||||
| std::string GetSystemSaveDataContainerPath(const std::string& mount_point); | ||||
| 
 | ||||
| /**
 | ||||
|  * Constructs a FileSys::Path object that refers to the SystemSaveData archive identified by | ||||
|  * the specified high save id and low save id. | ||||
|  * @param high The high word of the save id for the archive | ||||
|  * @param low The low word of the save id for the archive | ||||
|  * @returns A FileSys::Path to the wanted archive | ||||
|  */ | ||||
| Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low); | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
|  |  | |||
|  | @ -395,28 +395,72 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { | |||
|     return archive_itr->second->Format(path); | ||||
| } | ||||
| 
 | ||||
| ResultCode CreateExtSaveData(u32 high, u32 low) { | ||||
| ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low) { | ||||
|     // Construct the binary path to the archive first
 | ||||
|     std::vector<u8> binary_path; | ||||
|     binary_path.reserve(12); | ||||
|     // The first word is all zero to specify a NAND archive
 | ||||
|     for (unsigned i = 0; i < 4; ++i) | ||||
|         binary_path.push_back(0); | ||||
|     // Next is the low word
 | ||||
|     for (unsigned i = 0; i < 4; ++i) | ||||
|         binary_path.push_back((low >> (8 * i)) & 0xFF); | ||||
|     // Next is the high word
 | ||||
|     for (unsigned i = 0; i < 4; ++i) | ||||
|         binary_path.push_back((high >> i) & 0xFF); | ||||
|     FileSys::Path path(binary_path); | ||||
|     std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); | ||||
|     std::string base_path = FileSys::GetExtDataContainerPath(nand_directory, true); | ||||
|     FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); | ||||
| 
 | ||||
|     std::string media_type_directory; | ||||
|     if (media_type == MediaType::NAND) { | ||||
|         media_type_directory = FileUtil::GetUserPath(D_NAND_IDX); | ||||
|     } else if (media_type == MediaType::SDMC) { | ||||
|         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); | ||||
|     std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); | ||||
|     if (!FileUtil::CreateFullPath(extsavedata_path)) | ||||
|         return ResultCode(-1); // TODO(Subv): Find the right error code
 | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) { | ||||
|     // Construct the binary path to the archive first
 | ||||
|     FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); | ||||
| 
 | ||||
|     std::string media_type_directory; | ||||
|     if (media_type == MediaType::NAND) { | ||||
|         media_type_directory = FileUtil::GetUserPath(D_NAND_IDX); | ||||
|     } else if (media_type == MediaType::SDMC) { | ||||
|         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); | ||||
|     std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); | ||||
|     if (!FileUtil::DeleteDirRecursively(extsavedata_path)) | ||||
|         return ResultCode(-1); // TODO(Subv): Find the right error code
 | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| ResultCode DeleteSystemSaveData(u32 high, u32 low) { | ||||
|     // Construct the binary path to the archive first
 | ||||
|     FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); | ||||
| 
 | ||||
|     std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); | ||||
|     std::string base_path = FileSys::GetSystemSaveDataContainerPath(nand_directory); | ||||
|     std::string systemsavedata_path = FileSys::GetSystemSaveDataPath(base_path, path); | ||||
|     if (!FileUtil::DeleteDirRecursively(systemsavedata_path)) | ||||
|         return ResultCode(-1); // TODO(Subv): Find the right error code
 | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| ResultCode CreateSystemSaveData(u32 high, u32 low) { | ||||
|     // Construct the binary path to the archive first
 | ||||
|     FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); | ||||
| 
 | ||||
|     std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); | ||||
|     std::string base_path = FileSys::GetSystemSaveDataContainerPath(nand_directory); | ||||
|     std::string systemsavedata_path = FileSys::GetSystemSaveDataPath(base_path, path); | ||||
|     if (!FileUtil::CreateFullPath(systemsavedata_path)) | ||||
|         return ResultCode(-1); // TODO(Subv): Find the right error code
 | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| /// Initialize archives
 | ||||
| void ArchiveInit() { | ||||
|     next_handle = 1; | ||||
|  |  | |||
|  | @ -35,6 +35,12 @@ enum class ArchiveIdCode : u32 { | |||
|     SaveDataCheck       = 0x2345678A, | ||||
| }; | ||||
| 
 | ||||
| /// Media types for the archives
 | ||||
| enum class MediaType : u32 { | ||||
|     NAND     = 0, | ||||
|     SDMC     = 1 | ||||
| }; | ||||
| 
 | ||||
| typedef u64 ArchiveHandle; | ||||
| 
 | ||||
| class File : public Kernel::Session { | ||||
|  | @ -172,11 +178,37 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = File | |||
| 
 | ||||
| /**
 | ||||
|  * Creates a blank SharedExtSaveData archive for the specified extdata ID | ||||
|  * @param media_type The media type of the archive to create (NAND / SDMC) | ||||
|  * @param high The high word of the extdata id to create | ||||
|  * @param low The low word of the extdata id to create | ||||
|  * @return ResultCode 0 on success or the corresponding code on error | ||||
|  */ | ||||
| ResultCode CreateExtSaveData(u32 high, u32 low); | ||||
| ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deletes the SharedExtSaveData archive for the specified extdata ID | ||||
|  * @param media_type The media type of the archive to delete (NAND / SDMC) | ||||
|  * @param high The high word of the extdata id to delete | ||||
|  * @param low The low word of the extdata id to delete | ||||
|  * @return ResultCode 0 on success or the corresponding code on error | ||||
|  */ | ||||
| ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deletes the SystemSaveData archive folder for the specified save data id | ||||
|  * @param high The high word of the SystemSaveData archive to delete | ||||
|  * @param low The low word of the SystemSaveData archive to delete | ||||
|  * @return ResultCode 0 on success or the corresponding code on error | ||||
|  */ | ||||
| ResultCode DeleteSystemSaveData(u32 high, u32 low); | ||||
| 
 | ||||
| /**
 | ||||
|  * Creates the SystemSaveData archive folder for the specified save data id | ||||
|  * @param high The high word of the SystemSaveData archive to create | ||||
|  * @param low The low word of the SystemSaveData archive to create | ||||
|  * @return ResultCode 0 on success or the corresponding code on error | ||||
|  */ | ||||
| ResultCode CreateSystemSaveData(u32 high, u32 low); | ||||
| 
 | ||||
| /// Initialize archives
 | ||||
| void ArchiveInit(); | ||||
|  |  | |||
|  | @ -491,18 +491,38 @@ static void FormatThisUserSaveData(Service::Interface* self) { | |||
|  * FS_User::CreateExtSaveData service function | ||||
|  *  Inputs: | ||||
|  *      0 : 0x08510242 | ||||
|  *      1: High word of the saveid to create | ||||
|  *      1 : Media type (NAND / SDMC) | ||||
|  *      2 : Low word of the saveid to create | ||||
|  *      3 : High word of the saveid to create | ||||
|  *  Outputs: | ||||
|  *      1 : Result of function, 0 on success, otherwise error code | ||||
|  */ | ||||
| static void CreateExtSaveData(Service::Interface* self) { | ||||
|     // TODO(Subv): Figure out the other parameters.
 | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
|     u32 save_high = cmd_buff[1]; | ||||
|     MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF); | ||||
|     u32 save_low = cmd_buff[2]; | ||||
|     // TODO(Subv): For now it is assumed that only SharedExtSaveData can be created like this
 | ||||
|     cmd_buff[1] = CreateExtSaveData(save_high, save_low).raw; | ||||
|     u32 save_high = cmd_buff[3]; | ||||
|     cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * FS_User::DeleteExtSaveData service function | ||||
|  *  Inputs: | ||||
|  *      0 : 0x08520100 | ||||
|  *      1 : Media type (NAND / SDMC) | ||||
|  *      2 : Low word of the saveid to create | ||||
|  *      3 : High word of the saveid to create | ||||
|  *  Outputs: | ||||
|  *      1 : Result of function, 0 on success, otherwise error code | ||||
|  */ | ||||
| static void DeleteExtSaveData(Service::Interface* self) { | ||||
|     // TODO(Subv): Figure out the other parameters.
 | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
|     MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF); | ||||
|     u32 save_low = cmd_buff[2]; | ||||
|     u32 save_high = cmd_buff[3]; | ||||
|     cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -520,6 +540,48 @@ static void CardSlotIsInserted(Service::Interface* self) { | |||
|     LOG_WARNING(Service_FS, "(STUBBED) called"); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * FS_User::DeleteSystemSaveData service function. | ||||
|  *  Inputs: | ||||
|  *      0 : 0x08570080 | ||||
|  *      1 : High word of the SystemSaveData id to delete | ||||
|  *      2 : Low word of the SystemSaveData id to delete | ||||
|  *  Outputs: | ||||
|  *      1 : Result of function, 0 on success, otherwise error code | ||||
|  */ | ||||
| static void DeleteSystemSaveData(Service::Interface* self) { | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
|     u32 savedata_high = cmd_buff[1]; | ||||
|     u32 savedata_low = cmd_buff[2]; | ||||
|      | ||||
|     cmd_buff[1] = DeleteSystemSaveData(savedata_high, savedata_low).raw; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * FS_User::CreateSystemSaveData service function. | ||||
|  *  Inputs: | ||||
|  *      0 : 0x08560240 | ||||
|  *      1 : High word of the SystemSaveData id to create | ||||
|  *      2 : Low word of the SystemSaveData id to create | ||||
|  *      3 : Unknown | ||||
|  *      4 : Unknown | ||||
|  *      5 : Unknown | ||||
|  *      6 : Unknown | ||||
|  *      7 : Unknown | ||||
|  *      8 : Unknown | ||||
|  *      9 : Unknown (Memory address) | ||||
|  *  Outputs: | ||||
|  *      1 : Result of function, 0 on success, otherwise error code | ||||
|  */ | ||||
| static void CreateSystemSaveData(Service::Interface* self) { | ||||
|     // TODO(Subv): Figure out the other parameters.
 | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
|     u32 savedata_high = cmd_buff[1]; | ||||
|     u32 savedata_low = cmd_buff[2]; | ||||
| 
 | ||||
|     cmd_buff[1] = CreateSystemSaveData(savedata_high, savedata_low).raw; | ||||
| } | ||||
| 
 | ||||
| const Interface::FunctionInfo FunctionTable[] = { | ||||
|     {0x000100C6, nullptr,               "Dummy1"}, | ||||
|     {0x040100C4, nullptr,               "Control"}, | ||||
|  | @ -604,7 +666,9 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
|     {0x084F0102, nullptr,               "ReadSpecialFile"}, | ||||
|     {0x08500040, nullptr,               "GetSpecialFileSize"}, | ||||
|     {0x08510242, CreateExtSaveData,     "CreateExtSaveData"}, | ||||
|     {0x08520100, nullptr,               "DeleteExtSaveData"}, | ||||
|     {0x08520100, DeleteExtSaveData,     "DeleteExtSaveData"}, | ||||
|     {0x08560240, CreateSystemSaveData,  "CreateSystemSaveData"}, | ||||
|     {0x08570080, DeleteSystemSaveData,  "DeleteSystemSaveData"}, | ||||
|     {0x08580000, nullptr,               "GetMovableSedHashedKeyYRandomData"}, | ||||
|     {0x08610042, nullptr,               "InitializeWithSdkVersion"}, | ||||
|     {0x08620040, nullptr,               "SetPriority"}, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue