diff --git a/main.c b/main.c index 385c675..2111525 100644 --- a/main.c +++ b/main.c @@ -73,6 +73,7 @@ static void usage(void) { " --updatedir=dir Specify XCI update HFS0 directory path.\n" " --normaldir=dir Specify XCI normal HFS0 directory path.\n" " --securedir=dir Specify XCI secure HFS0 directory path.\n" + " --logodir=dir Specify XCI logo HFS0 directory path.\n" " --outdir=dir Specify XCI directory path. Overrides previous paths, if present.\n" "Package1 options:\n" " --package1dir=dir Specify Package1 directory path.\n" @@ -156,18 +157,19 @@ int main(int argc, char **argv) { {"updatedir", 1, NULL, 23}, {"normaldir", 1, NULL, 24}, {"securedir", 1, NULL, 25}, - {"package1dir", 1, NULL, 26}, - {"package2dir", 1, NULL, 27}, - {"ini1dir", 1, NULL, 28}, - {"extractini1", 0, NULL, 29}, - {"basefake", 0, NULL, 30}, - {"onlyupdated", 0, NULL, 31}, - {"sdseed", 1, NULL, 32}, - {"sdpath", 1, NULL, 33}, - {"sbk", 1, NULL, 34}, - {"tseckey", 1, NULL, 35}, - {"json", 1, NULL, 36}, - {"saveini1json", 0, NULL, 37}, + {"logodir", 1, NULL, 26}, + {"package1dir", 1, NULL, 27}, + {"package2dir", 1, NULL, 28}, + {"ini1dir", 1, NULL, 29}, + {"extractini1", 0, NULL, 30}, + {"basefake", 0, NULL, 31}, + {"onlyupdated", 0, NULL, 32}, + {"sdseed", 1, NULL, 33}, + {"sdpath", 1, NULL, 34}, + {"sbk", 1, NULL, 35}, + {"tseckey", 1, NULL, 36}, + {"json", 1, NULL, 37}, + {"saveini1json", 0, NULL, 38}, {NULL, 0, NULL, 0}, }; @@ -317,18 +319,21 @@ int main(int argc, char **argv) { filepath_set(&tool_ctx.settings.secure_dir_path, optarg); break; case 26: - filepath_set(&tool_ctx.settings.pk11_dir_path, optarg); + filepath_set(&tool_ctx.settings.logo_dir_path, optarg); break; case 27: - filepath_set(&tool_ctx.settings.pk21_dir_path, optarg); + filepath_set(&tool_ctx.settings.pk11_dir_path, optarg); break; case 28: - filepath_set(&tool_ctx.settings.ini1_dir_path, optarg); + filepath_set(&tool_ctx.settings.pk21_dir_path, optarg); break; case 29: - tool_ctx.action |= ACTION_EXTRACTINI1; + filepath_set(&tool_ctx.settings.ini1_dir_path, optarg); break; case 30: + tool_ctx.action |= ACTION_EXTRACTINI1; + break; + case 31: if (nca_ctx.tool_ctx->base_file != NULL) { usage(); return EXIT_FAILURE; @@ -336,10 +341,10 @@ int main(int argc, char **argv) { nca_ctx.tool_ctx->base_file_type = BASEFILE_FAKE; nca_ctx.tool_ctx->base_file++; /* Guarantees base_file != NULL. I'm so sorry. */ break; - case 31: + case 32: tool_ctx.action |= ACTION_ONLYUPDATEDROMFS; break; - case 32: + case 33: parse_hex_key(nca_ctx.tool_ctx->settings.sdseed, optarg, 16); nca_ctx.tool_ctx->settings.has_sdseed = 1; for (unsigned int key = 0; key < 2; key++) { @@ -349,19 +354,19 @@ int main(int argc, char **argv) { } pki_derive_keys(&tool_ctx.settings.keyset); break; - case 33: + case 34: filepath_set(&tool_ctx.settings.nax0_sd_path, optarg); break; - case 34: + case 35: parse_hex_key(nca_ctx.tool_ctx->settings.keygen_sbk, optarg, 16); break; - case 35: + case 36: parse_hex_key(nca_ctx.tool_ctx->settings.keygen_tsec, optarg, 16); break; - case 36: + case 37: filepath_set(&tool_ctx.settings.npdm_json_path, optarg); break; - case 37: + case 38: tool_ctx.action |= ACTION_SAVEINIJSON; break; default: @@ -449,14 +454,11 @@ int main(int argc, char **argv) { printf("Done!\n"); return EXIT_SUCCESS; } - - + if ((tool_ctx.file = fopen(input_name, "rb")) == NULL && tool_ctx.file_type != FILETYPE_BOOT0) { fprintf(stderr, "unable to open %s: %s\n", input_name, strerror(errno)); return EXIT_FAILURE; } - - switch (tool_ctx.file_type) { case FILETYPE_NCA: { diff --git a/settings.h b/settings.h index d669fc6..fcc0ed9 100644 --- a/settings.h +++ b/settings.h @@ -81,6 +81,7 @@ typedef struct { filepath_t update_dir_path; filepath_t normal_dir_path; filepath_t secure_dir_path; + filepath_t logo_dir_path; filepath_t header_path; filepath_t nax0_path; filepath_t nax0_sd_path; @@ -125,5 +126,4 @@ typedef struct { uint32_t action; } hactool_ctx_t; - #endif diff --git a/utils.h b/utils.h index bdb1ab9..47d55e2 100644 --- a/utils.h +++ b/utils.h @@ -51,16 +51,9 @@ inline int fseeko64(FILE *__stream, long long __off, int __whence) { return _fseeki64(__stream, __off, __whence); } -#elif __APPLE__ || __CYGWIN__ - // OS X file I/O is 64bit - #define fseeko64 fseek -#elif __linux__ || __WIN32 - extern int fseeko64 (FILE *__stream, _off64_t __off, int __whence); #else - /* fseeko is guaranteed by POSIX, hopefully the OS made their off_t definition 64-bit; - * known sane on FreeBSD and OpenBSD. - */ - #define fseeko64 fseeko + /* off_t is 64-bit with large file support */ + #define fseeko64 fseek #endif static inline uint64_t media_to_real(uint64_t media) { diff --git a/xci.c b/xci.c index 5cbf488..e375710 100644 --- a/xci.c +++ b/xci.c @@ -60,12 +60,12 @@ void xci_process(xci_ctx_t *ctx) { ctx->partition_ctx.name = "rootpt"; hfs0_process(&ctx->partition_ctx); - if (ctx->partition_ctx.header->num_files != 3) { + if (ctx->partition_ctx.header->num_files > 4) { fprintf(stderr, "Error: Invalid XCI partition!\n"); exit(EXIT_FAILURE); } - for (unsigned int i = 0; i < 3; i++) { + for (unsigned int i = 0; i < ctx->partition_ctx.header->num_files; i++) { hfs0_ctx_t *cur_ctx = NULL; hfs0_file_entry_t *cur_file = hfs0_get_file_entry(ctx->partition_ctx.header, i); @@ -76,6 +76,8 @@ void xci_process(xci_ctx_t *ctx) { cur_ctx = &ctx->normal_ctx; } else if (!strcmp(cur_name, "secure") && ctx->secure_ctx.file == NULL) { cur_ctx = &ctx->secure_ctx; + } else if (!strcmp(cur_name, "logo") && ctx->logo_ctx.file == NULL) { + cur_ctx = &ctx->logo_ctx; } if (cur_ctx == NULL) { @@ -109,7 +111,7 @@ void xci_save(xci_ctx_t *ctx) { printf("Extracting XCI...\n"); filepath_t *dirpath = &ctx->tool_ctx->settings.out_dir_path.path; os_makedir(dirpath->os_path); - for (unsigned int i = 0; i < 3; i++) { + for (unsigned int i = 0; i < ctx->partition_ctx.header->num_files; i++) { hfs0_ctx_t *cur_ctx = NULL; char *cur_name = hfs0_get_file_name(ctx->partition_ctx.header, i); @@ -119,9 +121,11 @@ void xci_save(xci_ctx_t *ctx) { cur_ctx = &ctx->normal_ctx; } else if (!strcmp(cur_name, "secure")) { cur_ctx = &ctx->secure_ctx; + } else if (!strcmp(cur_name, "logo")) { + cur_ctx = &ctx->logo_ctx; } if (cur_ctx == NULL) { - fprintf(stderr, "Unkown XCI partition found in extraction: %s\n", cur_name); + fprintf(stderr, "Unknown XCI partition found in extraction: %s\n", cur_name); exit(EXIT_FAILURE); } filepath_t partition_dirpath; @@ -163,13 +167,22 @@ void xci_save(xci_ctx_t *ctx) { } /* Save Secure Partition. */ if (ctx->tool_ctx->settings.secure_dir_path.valid == VALIDITY_VALID) { - printf("Saving Secure Partition...\n"); + printf("Saving Secure Partition...\n"); os_makedir(ctx->tool_ctx->settings.secure_dir_path.os_path); for (uint32_t i = 0; i < ctx->secure_ctx.header->num_files; i++) { hfs0_save_file(&ctx->secure_ctx, i, &ctx->tool_ctx->settings.secure_dir_path); } printf("\n"); - } + } + /* Save Logo Partition. */ + if (ctx->tool_ctx->settings.logo_dir_path.valid == VALIDITY_VALID) { + printf("Saving Logo Partition...\n"); + os_makedir(ctx->tool_ctx->settings.logo_dir_path.os_path); + for (uint32_t i = 0; i < ctx->logo_ctx.header->num_files; i++) { + hfs0_save_file(&ctx->logo_ctx, i, &ctx->tool_ctx->settings.logo_dir_path); + } + printf("\n"); + } } } @@ -238,4 +251,10 @@ void xci_print(xci_ctx_t *ctx) { printf("Secure Partition:\n"); xci_print_hfs0(&ctx->secure_ctx); + + /* Ensure that Logo partition exists. */ + if (ctx->partition_ctx.header->num_files == 4) { + printf("Logo Partition:\n"); + xci_print_hfs0(&ctx->logo_ctx); + } } \ No newline at end of file diff --git a/xci.h b/xci.h index fb268b6..96bf030 100644 --- a/xci.h +++ b/xci.h @@ -10,11 +10,12 @@ #define MAGIC_HEAD 0x44414548 /* "HEAD" */ typedef enum { + CARTSIZE_1GB = 0xFA, CARTSIZE_2GB = 0xF8, CARTSIZE_4GB = 0xF0, CARTSIZE_8GB = 0xE0, CARTSIZE_16GB = 0xE1, - /* CARTSIZE_32GB = 0xE2? */ + CARTSIZE_32GB = 0xE2 } cartridge_type_t; typedef struct { @@ -49,6 +50,7 @@ typedef struct { hfs0_ctx_t normal_ctx; hfs0_ctx_t update_ctx; hfs0_ctx_t secure_ctx; + hfs0_ctx_t logo_ctx; hactool_ctx_t *tool_ctx; unsigned char iv[0x10]; /* TODO: Header decryption. */ @@ -60,5 +62,4 @@ void xci_process(xci_ctx_t *ctx); void xci_save(xci_ctx_t *ctx); void xci_print(xci_ctx_t *ctx); - #endif \ No newline at end of file