1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-22 18:26:39 +00:00

Some changes.

* nxdt_includes: renamed VersionType1 to Version and tweaked it to add the application_version struct, renamed VersionType2 to SdkAddOnVersion.

* gc_dumper: use utilsGeneratePath() to truncate generated filenames to safe filesystem limits. Thanks to n0tw0rk for reporting the issue and testing the changes!

* nxdt_host.py: fixed a string formatting issue that made it impossible to unpack data from the SendFileProperties command block under certain circumstances.

* gamecard: modified GameCardKeySource to add a value field, added GameCardFlags_HasCa10Certificate flag.

* utils: utilsGeneratePath() no longer adds a dot on its own if it's not part of the provided extension string.
This commit is contained in:
Pablo Curiel 2022-03-17 13:37:24 +01:00
parent b9018a7df0
commit 278cb5c72a
14 changed files with 149 additions and 106 deletions

View file

@ -80,6 +80,8 @@ static bool waitForUsb(void);
static void generateDumpTxt(void);
static bool saveDumpTxt(void);
static char *generateOutputFileName(const char *extension);
static bool saveGameCardSpecificData(void);
static bool saveGameCardCertificate(void);
static bool saveGameCardInitialData(void);
@ -557,6 +559,29 @@ static bool saveDumpTxt(void)
return saveFileData(path, txt_info, strlen(txt_info));
}
static char *generateOutputFileName(const char *extension)
{
char *filename = NULL, *output = NULL;
if (!extension || !*extension || !(filename = titleGenerateGameCardFileName(TitleNamingConvention_Full, g_useUsbHost ? TitleFileNameIllegalCharReplaceType_IllegalFsChars : TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly)))
{
consolePrint("failed to get gamecard filename!\n");
return NULL;
}
output = utilsGeneratePath(NULL, filename, extension);
free(filename);
if (output)
{
snprintf(path, MAX_ELEMENTS(path), "%s", output);
} else {
consolePrint("failed to generate output filename!\n");
}
return output;
}
static bool dumpGameCardSecurityInformation(GameCardSecurityInformation *out)
{
if (!out)
@ -580,16 +605,19 @@ static bool saveGameCardSpecificData(void)
GameCardSecurityInformation gc_security_information = {0};
bool success = false;
u32 crc = 0;
char *filename = titleGenerateGameCardFileName(TitleNamingConvention_Full, g_useUsbHost ? TitleFileNameIllegalCharReplaceType_IllegalFsChars : TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
char *filename = NULL;
if (!dumpGameCardSecurityInformation(&gc_security_information) || !filename) goto end;
if (!dumpGameCardSecurityInformation(&gc_security_information)) goto end;
crc = crc32Calculate(&(gc_security_information.specific_data), sizeof(GameCardSpecificData));
snprintf(path, MAX_ELEMENTS(path), "%s (Specific Data) (%08X).bin", filename, crc);
snprintf(path, MAX_ELEMENTS(path), " (Specific Data) (%08X).bin", crc);
if (!saveFileData(path, &(gc_security_information.specific_data), sizeof(GameCardSpecificData))) goto end;
filename = generateOutputFileName(path);
if (!filename) goto end;
printf("successfully saved specific data as \"%s\"\n", path);
if (!saveFileData(filename, &(gc_security_information.specific_data), sizeof(GameCardSpecificData))) goto end;
printf("successfully saved specific data as \"%s\"\n", filename);
success = true;
end:
@ -603,9 +631,9 @@ static bool saveGameCardCertificate(void)
FsGameCardCertificate gc_cert = {0};
bool success = false;
u32 crc = 0;
char *filename = titleGenerateGameCardFileName(TitleNamingConvention_Full, g_useUsbHost ? TitleFileNameIllegalCharReplaceType_IllegalFsChars : TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
char *filename = NULL;
if (!gamecardGetCertificate(&gc_cert) || !filename)
if (!gamecardGetCertificate(&gc_cert))
{
consolePrint("failed to get gamecard certificate\n");
goto end;
@ -614,11 +642,14 @@ static bool saveGameCardCertificate(void)
consolePrint("get gamecard certificate ok\n");
crc = crc32Calculate(&gc_cert, sizeof(FsGameCardCertificate));
snprintf(path, MAX_ELEMENTS(path), "%s (Certificate) (%08X).bin", filename, crc);
snprintf(path, MAX_ELEMENTS(path), " (Certificate) (%08X).bin", crc);
if (!saveFileData(path, &gc_cert, sizeof(FsGameCardCertificate))) goto end;
filename = generateOutputFileName(path);
if (!filename) goto end;
printf("successfully saved certificate as \"%s\"\n", path);
if (!saveFileData(filename, &gc_cert, sizeof(FsGameCardCertificate))) goto end;
printf("successfully saved certificate as \"%s\"\n", filename);
success = true;
end:
@ -632,16 +663,19 @@ static bool saveGameCardInitialData(void)
GameCardSecurityInformation gc_security_information = {0};
bool success = false;
u32 crc = 0;
char *filename = titleGenerateGameCardFileName(TitleNamingConvention_Full, g_useUsbHost ? TitleFileNameIllegalCharReplaceType_IllegalFsChars : TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
char *filename = NULL;
if (!dumpGameCardSecurityInformation(&gc_security_information) || !filename) goto end;
if (!dumpGameCardSecurityInformation(&gc_security_information)) goto end;
crc = crc32Calculate(&(gc_security_information.initial_data), sizeof(GameCardInitialData));
snprintf(path, MAX_ELEMENTS(path), "%s (Initial Data) (%08X).bin", filename, crc);
snprintf(path, MAX_ELEMENTS(path), " (Initial Data) (%08X).bin", crc);
if (!saveFileData(path, &(gc_security_information.initial_data), sizeof(GameCardInitialData))) goto end;
filename = generateOutputFileName(path);
if (!filename) goto end;
printf("successfully saved initial data as \"%s\"\n", path);
if (!saveFileData(filename, &(gc_security_information.initial_data), sizeof(GameCardInitialData))) goto end;
printf("successfully saved initial data as \"%s\"\n", filename);
success = true;
end:
@ -655,16 +689,19 @@ static bool saveGameCardIdSet(void)
FsGameCardIdSet id_set = {0};
bool success = false;
u32 crc = 0;
char *filename = titleGenerateGameCardFileName(TitleNamingConvention_Full, g_useUsbHost ? TitleFileNameIllegalCharReplaceType_IllegalFsChars : TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
char *filename = NULL;
if (!gamecardGetIdSet(&id_set) || !filename) goto end;
if (!gamecardGetIdSet(&id_set)) goto end;
crc = crc32Calculate(&id_set, sizeof(FsGameCardIdSet));
snprintf(path, MAX_ELEMENTS(path), "%s (Card ID Set) (%08X).bin", filename, crc);
snprintf(path, MAX_ELEMENTS(path), " (Card ID Set) (%08X).bin", crc);
if (!saveFileData(path, &id_set, sizeof(FsGameCardIdSet))) goto end;
if (!saveFileData(filename, &id_set, sizeof(FsGameCardIdSet))) goto end;
printf("successfully saved gamecard id set as \"%s\"\n", path);
filename = generateOutputFileName(path);
if (!filename) goto end;
printf("successfully saved gamecard id set as \"%s\"\n", filename);
success = true;
end:
@ -686,12 +723,9 @@ static bool saveGameCardImage(void)
consolePrint("gamecard image dump\nkeep certificate: %s | trim dump: %s | calculate crc32: %s\n\n", g_keepCertificate ? "yes" : "no", g_trimDump ? "yes" : "no", g_calcCrc ? "yes" : "no");
filename = titleGenerateGameCardFileName(TitleNamingConvention_Full, g_useUsbHost ? TitleFileNameIllegalCharReplaceType_IllegalFsChars : TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
if (!filename)
{
consolePrint("failed to generate gamecard filename!\n");
goto end;
}
snprintf(path, MAX_ELEMENTS(path), " (%s) (%s).xci", g_keepCertificate ? "cert" : "certless", g_trimDump ? "trimmed" : "untrimmed");
filename = generateOutputFileName(path);
if (!filename) goto end;
shared_data.data = usbAllocatePageAlignedBuffer(BLOCK_SIZE);
if (!shared_data.data)
@ -710,25 +744,23 @@ static bool saveGameCardImage(void)
consolePrint("gamecard size: 0x%lX\n", gc_size);
snprintf(path, MAX_ELEMENTS(path), "%s (%s) (%s).xci", filename, g_keepCertificate ? "cert" : "certless", g_trimDump ? "trimmed" : "untrimmed");
if (g_useUsbHost && !usbSendFilePropertiesCommon(gc_size, path))
if (g_useUsbHost && !usbSendFilePropertiesCommon(gc_size, filename))
{
consolePrint("failed to send file properties for \"%s\"!\n", path);
consolePrint("failed to send file properties for \"%s\"!\n", filename);
goto end;
} else
if (!g_useUsbHost)
{
if (gc_size > FAT32_FILESIZE_LIMIT && !utilsCreateConcatenationFile(path))
if (gc_size > FAT32_FILESIZE_LIMIT && !utilsCreateConcatenationFile(filename))
{
consolePrint("failed to create concatenation file for \"%s\"!\n", path);
consolePrint("failed to create concatenation file for \"%s\"!\n", filename);
goto end;
}
shared_data.fp = fopen(path, "wb");
shared_data.fp = fopen(filename, "wb");
if (!shared_data.fp)
{
consolePrint("failed to open \"%s\" for writing!\n", path);
consolePrint("failed to open \"%s\" for writing!\n", filename);
goto end;
}
}
@ -824,7 +856,7 @@ end:
shared_data.fp = NULL;
}
if (!success && !g_useUsbHost) utilsRemoveConcatenationFile(path);
if (!success && !g_useUsbHost) utilsRemoveConcatenationFile(filename);
if (shared_data.data) free(shared_data.data);

View file

@ -123,8 +123,8 @@ static void nspDump(TitleInfo *title_info, u64 free_space)
printf("source storage: %s\n", title_info->storage_id == NcmStorageId_GameCard ? "gamecard" : (title_info->storage_id == NcmStorageId_BuiltInUser ? "emmc" : "sd card"));
printf("title id: %016lX\n", title_info->meta_key.id);
printf("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.major, title_info->version.minor, title_info->version.micro, title_info->version.major_relstep, \
title_info->version.minor_relstep);
printf("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.system_version.major, title_info->version.system_version.minor, title_info->version.system_version.micro, title_info->version.system_version.major_relstep, \
title_info->version.system_version.minor_relstep);
printf("content count: %u\n", title_info->content_count);
printf("size: %s\n", title_info->size_str);
printf("______________________________\n\n");
@ -895,8 +895,8 @@ int main(int argc, char *argv[])
(title_info->meta_key.type == NcmContentMetaType_Patch ? "update" : "dlc"));
printf("source storage: %s\n", title_info->storage_id == NcmStorageId_GameCard ? "gamecard" : (title_info->storage_id == NcmStorageId_BuiltInUser ? "emmc" : "sd card"));
if (title_info->meta_key.type != NcmContentMetaType_Application) printf("title id: %016lX\n", title_info->meta_key.id);
printf("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.major, title_info->version.minor, title_info->version.micro, title_info->version.major_relstep, \
title_info->version.minor_relstep);
printf("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.system_version.major, title_info->version.system_version.minor, title_info->version.system_version.micro, title_info->version.system_version.major_relstep, \
title_info->version.system_version.minor_relstep);
printf("content count: %u\n", title_info->content_count);
printf("size: %s\n", title_info->size_str);
}

View file

@ -859,8 +859,8 @@ static void nspDump(TitleInfo *title_info)
consolePrint("source storage: %s\n", title_info->storage_id == NcmStorageId_GameCard ? "gamecard" : (title_info->storage_id == NcmStorageId_BuiltInUser ? "emmc" : "sd card"));
consolePrint("title id: %016lX\n", title_info->meta_key.id);
consolePrint("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.major, title_info->version.minor, title_info->version.micro, title_info->version.major_relstep, \
title_info->version.minor_relstep);
consolePrint("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.system_version.major, title_info->version.system_version.minor, title_info->version.system_version.micro, title_info->version.system_version.major_relstep, \
title_info->version.system_version.minor_relstep);
consolePrint("content count: %u\n", title_info->content_count);
consolePrint("size: %s\n", title_info->size_str);
consolePrint("______________________________\n\n");
@ -1046,8 +1046,8 @@ int main(int argc, char *argv[])
(title_info->meta_key.type == NcmContentMetaType_Patch ? "update" : "dlc"));
consolePrint("source storage: %s\n", title_info->storage_id == NcmStorageId_GameCard ? "gamecard" : (title_info->storage_id == NcmStorageId_BuiltInUser ? "emmc" : "sd card"));
if (title_info->meta_key.type != NcmContentMetaType_Application) consolePrint("title id: %016lX\n", title_info->meta_key.id);
consolePrint("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.major, title_info->version.minor, title_info->version.micro, title_info->version.major_relstep, \
title_info->version.minor_relstep);
consolePrint("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.system_version.major, title_info->version.system_version.minor, title_info->version.system_version.micro, title_info->version.system_version.major_relstep, \
title_info->version.system_version.minor_relstep);
consolePrint("content count: %u\n", title_info->content_count);
consolePrint("size: %s\n", title_info->size_str);
}

View file

@ -629,7 +629,7 @@ def usbHandleSendFileProperties(cmd_block):
g_logger.debug('Received SendFileProperties (%02X) command.' % (USB_CMD_SEND_FILE_PROPERTIES))
# Parse command block.
(file_size, filename_length, nsp_header_size, raw_filename) = struct.unpack_from('<QII{}s'.format(USB_FILE_PROPERTIES_MAX_NAME_LENGTH), cmd_block, 0)
(file_size, filename_length, nsp_header_size, raw_filename) = struct.unpack_from('<QII%ds' % (USB_FILE_PROPERTIES_MAX_NAME_LENGTH), cmd_block, 0)
filename = raw_filename.decode('utf-8').strip('\x00')
# Print info.

View file

@ -51,7 +51,7 @@ typedef enum {
/// Finally, a 0x20 byte long digest is appended to the EOF.
typedef struct {
u64 title_id;
VersionType1 version;
Version version;
u8 content_meta_type; ///< NcmContentMetaType.
u8 reserved_1;
u16 extended_header_size; ///< Must match the size from the extended header struct for this content meta type (SystemUpdate, Application, Patch, AddOnContent, Delta).
@ -61,7 +61,7 @@ typedef struct {
u8 storage_id; ///< NcmStorageId.
u8 content_install_type; ///< NcmContentInstallType.
u8 install_state; ///< ContentMetaInstallState.
VersionType1 required_download_system_version;
Version required_download_system_version;
u8 reserved_2[0x4];
} ContentMetaPackagedContentMetaHeader;
@ -76,20 +76,20 @@ typedef struct {
NXDT_ASSERT(ContentMetaSystemUpdateMetaExtendedHeader, 0x4);
/// Extended header for Application titles.
/// Equivalent to NcmApplicationMetaExtendedHeader, but using VersionType1 structs.
/// Equivalent to NcmApplicationMetaExtendedHeader, but using Version structs.
typedef struct {
u64 patch_id;
VersionType1 required_system_version;
VersionType1 required_application_version;
Version required_system_version;
Version required_application_version;
} ContentMetaApplicationMetaExtendedHeader;
NXDT_ASSERT(ContentMetaApplicationMetaExtendedHeader, 0x10);
/// Extended header for Patch titles.
/// Equivalent to NcmPatchMetaExtendedHeader, but using a VersionType1 struct.
/// Equivalent to NcmPatchMetaExtendedHeader, but using a Version struct.
typedef struct {
u64 application_id;
VersionType1 required_system_version;
Version required_system_version;
u32 extended_data_size;
u8 reserved[0x8];
} ContentMetaPatchMetaExtendedHeader;
@ -97,10 +97,10 @@ typedef struct {
NXDT_ASSERT(ContentMetaPatchMetaExtendedHeader, 0x18);
/// Extended header for AddOnContent titles.
/// Equivalent to NcmAddOnContentMetaExtendedHeader, but using a VersionType1 struct.
/// Equivalent to NcmAddOnContentMetaExtendedHeader, but using a Version struct.
typedef struct {
u64 application_id;
VersionType1 required_application_version;
Version required_application_version;
u8 reserved[0x4];
} ContentMetaAddOnContentMetaExtendedHeader;
@ -186,8 +186,8 @@ NXDT_ASSERT(ContentMetaPatchHistoryHeader, 0x38);
typedef struct {
u64 source_patch_id;
u64 destination_patch_id;
VersionType1 source_version;
VersionType1 destination_version;
Version source_version;
Version destination_version;
u64 download_size;
u8 reserved[0x8];
} ContentMetaPatchDeltaHistory;
@ -197,8 +197,8 @@ NXDT_ASSERT(ContentMetaPatchDeltaHistory, 0x28);
typedef struct {
u64 source_patch_id;
u64 destination_patch_id;
VersionType1 source_version;
VersionType1 destination_version;
Version source_version;
Version destination_version;
u16 fragment_set_count;
u8 reserved_1[0x6];
u16 content_info_count;
@ -244,8 +244,8 @@ NXDT_ASSERT(ContentMetaFragmentIndicator, 0x4);
typedef struct {
u64 source_patch_id;
u64 destination_patch_id;
VersionType1 source_version;
VersionType1 destination_version;
Version source_version;
Version destination_version;
u16 fragment_set_count;
u8 reserved[0x6];
} ContentMetaDeltaMetaExtendedDataHeader;
@ -323,7 +323,7 @@ NX_INLINE u32 cnmtGetRequiredTitleVersion(ContentMetaContext *cnmt_ctx)
{
return ((cnmtIsValidContext(cnmt_ctx) && (cnmt_ctx->packaged_header->content_meta_type == NcmContentMetaType_Application || \
cnmt_ctx->packaged_header->content_meta_type == NcmContentMetaType_Patch || cnmt_ctx->packaged_header->content_meta_type == NcmContentMetaType_AddOnContent)) ? \
((VersionType1*)(cnmt_ctx->extended_header + sizeof(u64)))->value : 0);
((Version*)(cnmt_ctx->extended_header + sizeof(u64)))->value : 0);
}
#ifdef __cplusplus

View file

@ -56,8 +56,13 @@ NXDT_ASSERT(GameCardSpecificData, 0x200);
/// Encrypted using AES-128-ECB with the common titlekek generator key (stored in the .rodata segment from the Lotus firmware).
typedef struct {
union {
u8 value[0x10];
struct {
u64 package_id; ///< Matches package_id from GameCardHeader.
u8 reserved[0x8]; ///< Just zeroes.
};
};
} GameCardKeySource;
NXDT_ASSERT(GameCardKeySource, 0x10);
@ -138,7 +143,8 @@ typedef enum {
GameCardFlags_HistoryErase = BIT(1),
GameCardFlags_RepairTool = BIT(2),
GameCardFlags_DifferentRegionCupToTerraDevice = BIT(3),
GameCardFlags_DifferentRegionCupToGlobalDevice = BIT(4)
GameCardFlags_DifferentRegionCupToGlobalDevice = BIT(4),
GameCardFlags_HasCa10Certificate = BIT(7)
} GameCardFlags;
typedef enum {
@ -178,11 +184,11 @@ typedef struct {
u32 wait_2_time_read; ///< Always 0.
u32 wait_1_time_write; ///< Always 0.
u32 wait_2_time_write; ///< Always 0.
VersionType2 fw_mode; ///< Current SdkAddonVersion.
VersionType1 upp_version; ///< Bundled system update version.
SdkAddOnVersion fw_mode; ///< Current SdkAddOnVersion.
Version upp_version; ///< Bundled system update version.
u8 compatibility_type; ///< GameCardCompatibilityType.
u8 reserved_1[0x3];
u64 upp_hash; ///< SHA-256 checksum for the update partition.
u64 upp_hash; ///< SHA-256 (?) checksum for the update partition. The exact way it's calculated is currently unknown.
u64 upp_id; ///< Must match GAMECARD_UPDATE_TID.
u8 reserved_2[0x38];
} GameCardInfo;
@ -325,8 +331,8 @@ bool gamecardGetTrimmedSize(u64 *out);
/// Fills the provided u64 pointer with the gamecard ROM capacity, based on the GameCardRomSize value from the header. Not the same as gamecardGetTotalSize().
bool gamecardGetRomCapacity(u64 *out);
/// Fills the provided VersionType1 pointer with the bundled firmware update version in the inserted gamecard.
bool gamecardGetBundledFirmwareUpdateVersion(VersionType1 *out);
/// Fills the provided Version pointer with the bundled firmware update version in the inserted gamecard.
bool gamecardGetBundledFirmwareUpdateVersion(Version *out);
/// Fills the provided HashFileSystemContext pointer using information from the requested Hash FS partition.
/// Hash FS functions can be used on the retrieved HashFileSystemContext. hfsFreeContext() must be used to free the underlying data from the filled context.

View file

@ -144,7 +144,7 @@ typedef struct {
u64 content_size;
u64 program_id;
u32 content_index;
VersionType2 sdk_addon_version;
SdkAddOnVersion sdk_addon_version;
u8 key_generation; ///< NcaKeyGeneration. Uses NcaKeyGeneration_Since301NUP or greater values.
u8 main_signature_key_generation; ///< NcaMainSignatureKeyGeneration.
u8 reserved[0xE];

View file

@ -76,7 +76,7 @@ typedef struct {
u8 main_thread_core_number; ///< Must not exceed NPDM_MAIN_THREAD_MAX_CORE_NUMBER.
u8 reserved_3[0x4];
u32 system_resource_size; ///< Must not exceed NPDM_SYSTEM_RESOURCE_MAX_SIZE.
VersionType1 version;
Version version;
u32 main_thread_stack_size; ///< Must be aligned to NPDM_MAIN_THREAD_STACK_SIZE_ALIGNMENT.
char name[0x10]; ///< Usually set to "Application".
char product_code[0x10]; ///< Usually zeroed out.

View file

@ -65,37 +65,43 @@
/* USB Mass Storage support. */
#include "ums.h"
/// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{major_relstep}.{minor_relstep}".
/// Used to store version numbers expressed in dot notation:
/// * System version: "{major}.{minor}.{micro}-{major_relstep}.{minor_relstep}".
/// * Application version: "{release}.{private}".
/// Referenced by multiple header files.
typedef struct {
union {
u32 value;
struct {
u32 minor_relstep : 8;
u32 major_relstep : 8;
u32 micro : 4;
u32 minor : 6;
u32 major : 6;
} system_version;
struct {
u32 private_ver : 16;
u32 release_ver : 16;
} application_version;
};
u32 value;
};
} VersionType1;
} Version;
NXDT_ASSERT(VersionType1, 0x4);
NXDT_ASSERT(Version, 0x4);
/// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{relstep}".
/// Only used by GameCardFwMode and NcaSdkAddOnVersion.
typedef struct {
union {
u32 value;
struct {
u32 relstep : 8;
u32 micro : 8;
u32 minor : 8;
u32 major : 8;
};
u32 value;
};
} VersionType2;
} SdkAddOnVersion;
NXDT_ASSERT(VersionType2, 0x4);
NXDT_ASSERT(SdkAddOnVersion, 0x4);
#endif /* __NXDT_INCLUDES_H__ */

View file

@ -148,6 +148,8 @@ void utilsCreateDirectoryTree(const char *path, bool create_last_element);
/// Returns a pointer to a dynamically allocated string that holds the full path formed by the provided arguments. Both path prefix and file extension are optional.
/// If any elements from the generated path exceed safe filesystem limits, each exceeding element will be truncated. Truncations, if needed, are performed on a per-codepoint basis (UTF-8).
/// If an extension is provided, it will always be preserved, regardless of any possible truncations being carried out.
/// A path separator is automatically placed between the provided prefix and the filename if the prefix doesn't end with one.
/// A dot *isn't* automatically placed between the filename and the provided extension -- if required, it must be provided as part of the extension string.
/// Furthermore, if the full length for the generated path is >= FS_MAX_PATH, NULL will be returned.
char *utilsGeneratePath(const char *prefix, const char *filename, const char *extension);

View file

@ -49,7 +49,7 @@ typedef struct {
typedef struct _TitleInfo {
u8 storage_id; ///< NcmStorageId.
NcmContentMetaKey meta_key; ///< Used with ncm calls.
VersionType1 version; ///< Holds the same value from meta_key.version.
Version version; ///< Holds the same value from meta_key.version.
u32 content_count; ///< Content info count.
NcmContentInfo *content_infos; ///< Content info entries from this title.
u64 size; ///< Total title size.

View file

@ -435,7 +435,7 @@ bool gamecardGetRomCapacity(u64 *out)
return ret;
}
bool gamecardGetBundledFirmwareUpdateVersion(VersionType1 *out)
bool gamecardGetBundledFirmwareUpdateVersion(Version *out)
{
bool ret = false;

View file

@ -759,11 +759,9 @@ char *utilsGeneratePath(const char *prefix, const char *filename, const char *ex
bool use_extension = (extension && *extension);
size_t extension_len = (use_extension ? strlen(extension) : 0);
bool append_dot = (use_extension && *extension != '.');
size_t path_len = (prefix_len + strlen(filename) + extension_len);
if (append_path_sep) path_len++;
if (append_dot) path_len++;
char *path = NULL, *ptr1 = NULL, *ptr2 = NULL;
bool filename_only = false, success = false;
@ -779,7 +777,6 @@ char *utilsGeneratePath(const char *prefix, const char *filename, const char *ex
if (use_prefix) strcat(path, prefix);
if (append_path_sep) strcat(path, "/");
strcat(path, filename);
if (append_dot) strcat(path, ".");
if (use_extension) strcat(path, extension);
/* Retrieve pointer to the first path separator. */
@ -792,12 +789,15 @@ char *utilsGeneratePath(const char *prefix, const char *filename, const char *ex
/* Make sure each path element doesn't exceed NT_MAX_FILENAME_LENGTH. */
while(ptr1)
{
if (!filename_only)
{
/* End loop if we find a NULL terminator. */
if (!filename_only && !*ptr1++) break;
if (!*ptr1++) break;
/* Get pointer to next path separator. */
ptr2 = strchr(ptr1, '/');
}
/* Get current path element size. */
size_t element_size = (ptr2 ? (size_t)(ptr2 - ptr1) : (path_len - (size_t)(ptr1 - path)));
@ -819,16 +819,13 @@ char *utilsGeneratePath(const char *prefix, const char *filename, const char *ex
if (use_extension)
{
/* Truncate last element. Make sure to preserve the provided file extension. */
size_t diff = extension_len;
if (append_dot) diff++;
if (diff >= last_cp_pos)
if (extension_len >= last_cp_pos)
{
LOG_MSG("File extension length is >= truncated filename length! (0x%lX >= 0x%lX) (#1).", diff, last_cp_pos);
LOG_MSG("File extension length is >= truncated filename length! (0x%lX >= 0x%lX).", extension_len, last_cp_pos);
goto end;
}
memmove(ptr1 + last_cp_pos - diff, ptr1 + element_size - diff, diff);
memmove(ptr1 + last_cp_pos - extension_len, ptr1 + element_size - extension_len, extension_len);
}
path_len -= (element_size - last_cp_pos);

View file

@ -104,14 +104,14 @@ namespace nxdt::views
this->total_size->setValue(this->GetFormattedSizeString(&gamecardGetTotalSize));
this->trimmed_size->setValue(this->GetFormattedSizeString(&gamecardGetTrimmedSize));
const VersionType1 *upp_version = &(card_info.upp_version);
this->update_version->setValue(fmt::format("{}.{}.{}-{}.{} (v{})", upp_version->major, upp_version->minor, upp_version->micro, upp_version->major_relstep, \
upp_version->minor_relstep, upp_version->value));
const Version *upp_version = &(card_info.upp_version);
this->update_version->setValue(fmt::format("{}.{}.{}-{}.{} (v{})", upp_version->system_version.major, upp_version->system_version.minor, upp_version->system_version.micro, \
upp_version->system_version.major_relstep, upp_version->system_version.minor_relstep, upp_version->value));
u64 fw_version = card_info.fw_version;
this->lafw_version->setValue(fmt::format("{} ({})", fw_version, fw_version >= GameCardFwVersion_Count ? "generic/unknown"_i18n : gamecardGetRequiredHosVersionString(fw_version)));
const VersionType2 *fw_mode = &(card_info.fw_mode);
const SdkAddOnVersion *fw_mode = &(card_info.fw_mode);
this->sdk_version->setValue(fmt::format("{}.{}.{}-{} (v{})", fw_mode->major, fw_mode->minor, fw_mode->micro, fw_mode->relstep, fw_mode->value));
u8 compatibility_type = card_info.compatibility_type;