mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06: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:
		@@ -407,7 +407,7 @@ void Init() {
 | 
			
		||||
    // If the archive didn't exist, create the files inside
 | 
			
		||||
    if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
 | 
			
		||||
        // 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
 | 
			
		||||
        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());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    if (archive_itr == id_code_map.end()) {
 | 
			
		||||
        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
 | 
			
		||||
    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
 | 
			
		||||
    auto archive = id_code_map.find(media_type == MediaType::NAND ? ArchiveIdCode::SharedExtSaveData : ArchiveIdCode::ExtSaveData);
 | 
			
		||||
 | 
			
		||||
    if (archive == id_code_map.end()) {
 | 
			
		||||
        return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
 | 
			
		||||
    std::string game_path = FileSys::GetExtSaveDataPath(base_path, path);
 | 
			
		||||
    // These two folders are always created with the ExtSaveData
 | 
			
		||||
    std::string user_path = game_path + "user/";
 | 
			
		||||
    std::string boss_path = game_path + "boss/";
 | 
			
		||||
    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
 | 
			
		||||
    auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get());
 | 
			
		||||
 | 
			
		||||
    ResultCode result = ext_savedata->Format(path, format_info);
 | 
			
		||||
    if (result.IsError())
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    u8* smdh_icon = Memory::GetPointer(icon_buffer);
 | 
			
		||||
    if (!smdh_icon)
 | 
			
		||||
        return ResultCode(-1); // TODO(Subv): Find the right error code
 | 
			
		||||
 | 
			
		||||
    // Create the icon
 | 
			
		||||
    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);
 | 
			
		||||
    ext_savedata->WriteIcon(path, smdh_icon, icon_size);
 | 
			
		||||
    return RESULT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -177,10 +177,20 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle);
 | 
			
		||||
 * Erases the contents of the physical folder that contains the archive
 | 
			
		||||
 * identified by the specified id code and path
 | 
			
		||||
 * @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.
 | 
			
		||||
 * @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
 | 
			
		||||
@@ -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 icon_buffer VAddr of the SMDH icon for this ExtSaveData
 | 
			
		||||
 * @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
 | 
			
		||||
 */
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
@@ -443,17 +443,22 @@ static void IsSdmcWriteable(Service::Interface* self) {
 | 
			
		||||
 *  Inputs:
 | 
			
		||||
 *      0  : 0x084C0242
 | 
			
		||||
 *      1  : Archive ID
 | 
			
		||||
 *      2  : Archive low path type
 | 
			
		||||
 *      3  : Archive low path size
 | 
			
		||||
 *      10 : (LowPathSize << 14) | 2
 | 
			
		||||
 *      2  : Archive path type
 | 
			
		||||
 *      3  : Archive path size
 | 
			
		||||
 *      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
 | 
			
		||||
 *  Outputs:
 | 
			
		||||
 *      1 : Result of function, 0 on success, otherwise error code
 | 
			
		||||
 */
 | 
			
		||||
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();
 | 
			
		||||
    LOG_DEBUG(Service_FS, "(STUBBED)");
 | 
			
		||||
    LOG_WARNING(Service_FS, "(STUBBED)");
 | 
			
		||||
 | 
			
		||||
    auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
 | 
			
		||||
    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());
 | 
			
		||||
 | 
			
		||||
    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", cmd_buff[1]);
 | 
			
		||||
        cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
 | 
			
		||||
        LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", archive_id);
 | 
			
		||||
        cmd_buff[1] = ResultCode(ErrorDescription::FS_InvalidPath, ErrorModule::FS,
 | 
			
		||||
                                 ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -477,23 +482,40 @@ static void FormatSaveData(Service::Interface* self) {
 | 
			
		||||
        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
 | 
			
		||||
 *  Inputs:
 | 
			
		||||
 *      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:
 | 
			
		||||
 *      1 : Result of function, 0 on success, otherwise error code
 | 
			
		||||
 */
 | 
			
		||||
static void FormatThisUserSaveData(Service::Interface* self) {
 | 
			
		||||
    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
 | 
			
		||||
 *      3 : High word of the saveid to create
 | 
			
		||||
 *      4 : Unknown
 | 
			
		||||
 *      5 : Unknown
 | 
			
		||||
 *      6 : Unknown
 | 
			
		||||
 *      7 : Unknown
 | 
			
		||||
 *      8 : Unknown
 | 
			
		||||
 *      5 : Number of directories
 | 
			
		||||
 *      6 : Number of files
 | 
			
		||||
 *      7-8 : Size limit
 | 
			
		||||
 *      9 : Size of the SMDH icon
 | 
			
		||||
 *      10: (SMDH Size << 4) | 0x0000000A
 | 
			
		||||
 *      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[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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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[] = {
 | 
			
		||||
    {0x000100C6, nullptr,                  "Dummy1"},
 | 
			
		||||
    {0x040100C4, nullptr,                  "Control"},
 | 
			
		||||
@@ -802,7 +873,7 @@ const Interface::FunctionInfo FunctionTable[] = {
 | 
			
		||||
    {0x08420040, nullptr,                  "DeleteAllExtSaveDataOnNand"},
 | 
			
		||||
    {0x08430000, nullptr,                  "InitializeCtrFileSystem"},
 | 
			
		||||
    {0x08440000, nullptr,                  "CreateSeed"},
 | 
			
		||||
    {0x084500C2, nullptr,                  "GetFormatInfo"},
 | 
			
		||||
    {0x084500C2, GetFormatInfo,            "GetFormatInfo"},
 | 
			
		||||
    {0x08460102, nullptr,                  "GetLegacyRomHeader2"},
 | 
			
		||||
    {0x08470180, nullptr,                  "FormatCtrCardUserSaveData"},
 | 
			
		||||
    {0x08480042, nullptr,                  "GetSdmcCtrRootPath"},
 | 
			
		||||
 
 | 
			
		||||
@@ -103,7 +103,7 @@ void Init() {
 | 
			
		||||
    // If the archive didn't exist, create the files inside
 | 
			
		||||
    if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
 | 
			
		||||
        // 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
 | 
			
		||||
        archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
 | 
			
		||||
        ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!");
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user