Add more options for Update RomFS

This commit is contained in:
Michael Scire 2018-02-12 03:35:48 -08:00
parent 8311740694
commit 5271b3ae00
6 changed files with 96 additions and 19 deletions

View file

@ -40,6 +40,8 @@ NCA options:
--listromfs List files in RomFS.
--baseromfs Set Base RomFS to use with update partitions.
--basenca Set Base NCA to use with update partitions.
--basefake Use a fake Base RomFS with update partitions (all reads will return 0xCC).
--onlyupdated Ignore non-updated files in update partitions.
PFS0 options:
--pfs0dir=dir Specify PFS0 directory path.
--outdir=dir Specify PFS0 directory path. Overrides previous path, if present.

View file

@ -38,6 +38,14 @@ int os_makedir(const oschar_t *dir) {
#endif
}
int os_rmdir(const oschar_t *dir) {
#ifdef _WIN32
return _wrmdir(dir);
#else
return remove(dir);
#endif
}
void filepath_update(filepath_t *fpath) {
memset(fpath->os_path, 0, MAX_PATH * sizeof(oschar_t));
os_strcpy(fpath->os_path, fpath->char_path);

View file

@ -32,6 +32,7 @@ typedef struct filepath {
void os_strcpy(oschar_t *dst, const char *src);
int os_makedir(const oschar_t *dir);
int os_rmdir(const oschar_t *dir);
void filepath_init(filepath_t *fpath);
void filepath_copy(filepath_t *fpath, filepath_t *copy);

21
main.c
View file

@ -50,7 +50,9 @@ static void usage(void) {
" --romfsdir=dir Specify RomFS directory path. Overrides appropriate section directory path.\n"
" --listromfs List files in RomFS.\n"
" --baseromfs Set Base RomFS to use with update partitions.\n"
" --basenca Set Base NCA to use with update partitions.\n"
" --basenca Set Base NCA to use with update partitions.\n"
" --basefake Use a fake Base RomFS with update partitions (all reads will return 0xCC).\n"
" --onlyupdated Ignore non-updated files in update partitions.\n"
"PFS0 options:\n"
" --pfs0dir=dir Specify PFS0 directory path.\n"
" --outdir=dir Specify PFS0 directory path. Overrides previous path, if present.\n"
@ -148,6 +150,8 @@ int main(int argc, char **argv) {
{"package2dir", 1, NULL, 27},
{"ini1dir", 1, NULL, 28},
{"extractini1", 0, NULL, 29},
{"basefake", 0, NULL, 30},
{"onlyupdated", 0, NULL, 31},
{NULL, 0, NULL, 0},
};
@ -304,6 +308,17 @@ int main(int argc, char **argv) {
case 29:
tool_ctx.action |= ACTION_EXTRACTINI1;
break;
case 30:
if (nca_ctx.tool_ctx->base_file != NULL) {
usage();
return EXIT_FAILURE;
}
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:
tool_ctx.action |= ACTION_ONLYUPDATEDROMFS;
break;
default:
usage();
return EXIT_FAILURE;
@ -371,6 +386,10 @@ int main(int argc, char **argv) {
nca_process(&nca_ctx);
nca_free_section_contexts(&nca_ctx);
if (nca_ctx.tool_ctx->base_file_type == BASEFILE_FAKE) {
nca_ctx.tool_ctx->base_file = NULL;
}
if (nca_ctx.tool_ctx->base_file != NULL) {
fclose(nca_ctx.tool_ctx->base_file);
if (nca_ctx.tool_ctx->base_file_type == BASEFILE_NCA) {

79
nca.c
View file

@ -215,7 +215,7 @@ size_t nca_section_fread(nca_section_ctx_t *ctx, void *buffer, size_t count) {
if ((read = fread(buffer, 1, count, ctx->tool_ctx->base_file)) != count) {
return 0;
}
} else {
} else if (ctx->tool_ctx->base_file_type == BASEFILE_NCA) {
nca_ctx_t *base_ctx = ctx->tool_ctx->base_nca_ctx;
unsigned int romfs_section_num;
for (romfs_section_num = 0; romfs_section_num < 4; romfs_section_num++) {
@ -228,6 +228,13 @@ size_t nca_section_fread(nca_section_ctx_t *ctx, void *buffer, size_t count) {
fprintf(stderr, "Failed to read from Base NCA RomFS!\n");
exit(EXIT_FAILURE);
}
} else if (ctx->tool_ctx->base_file_type == BASEFILE_FAKE) {
/* Fake reads. */
memset(buffer, 0xCC, count);
read = count;
} else {
fprintf(stderr, "Unknown Base File Type!\n");
exit(EXIT_FAILURE);
}
}
} else {
@ -1190,7 +1197,28 @@ void nca_save_pfs0_section(nca_section_ctx_t *ctx) {
}
/* RomFS functions... */
void nca_visit_romfs_file(nca_section_ctx_t *ctx, uint32_t file_offset, filepath_t *dir_path) {
int nca_is_romfs_file_updated(nca_section_ctx_t *ctx, uint64_t file_offset, uint64_t file_size) {
/* All files in a Base RomFS are "updated". */
if (ctx->type == ROMFS) {
return 1;
}
bktr_relocation_entry_t *first_reloc = bktr_get_relocation(ctx->bktr_ctx.relocation_block, file_offset);
bktr_relocation_entry_t *last_reloc = first_reloc;
while (last_reloc->virt_offset < file_offset + file_size) {
last_reloc++;
}
for (bktr_relocation_entry_t *cur_reloc = first_reloc; cur_reloc < last_reloc; cur_reloc++) {
if (cur_reloc->is_patch) {
return 1;
}
}
return 0;
}
int nca_visit_romfs_file(nca_section_ctx_t *ctx, uint32_t file_offset, filepath_t *dir_path) {
romfs_fentry_t *entry;
if (ctx->type == ROMFS) {
entry = romfs_get_fentry(ctx->romfs_ctx.files, file_offset);
@ -1207,29 +1235,37 @@ void nca_visit_romfs_file(nca_section_ctx_t *ctx, uint32_t file_offset, filepath
if (entry->name_size) {
filepath_append_n(cur_path, entry->name_size, "%s", entry->name);
}
int found_file = 1;
/* If we're extracting... */
if ((ctx->tool_ctx->action & ACTION_LISTROMFS) == 0) {
printf("Saving %s...\n", cur_path->char_path);
uint64_t phys_offset;
if (ctx->type == ROMFS) {
phys_offset = ctx->romfs_ctx.romfs_offset + ctx->romfs_ctx.header.data_offset + entry->offset;
} else {
phys_offset = ctx->bktr_ctx.romfs_offset + ctx->bktr_ctx.header.data_offset + entry->offset;
}
nca_save_section_file(ctx, phys_offset, entry->size, cur_path);
uint64_t phys_offset;
if (ctx->type == ROMFS) {
phys_offset = ctx->romfs_ctx.romfs_offset + ctx->romfs_ctx.header.data_offset + entry->offset;
} else {
printf("rom:%s\n", cur_path->char_path);
phys_offset = ctx->bktr_ctx.romfs_offset + ctx->bktr_ctx.header.data_offset + entry->offset;
}
if ((ctx->tool_ctx->action & ACTION_ONLYUPDATEDROMFS) == 0 || nca_is_romfs_file_updated(ctx, phys_offset, entry->size)) {
if ((ctx->tool_ctx->action & ACTION_LISTROMFS) == 0) {
printf("Saving %s...\n", cur_path->char_path);
nca_save_section_file(ctx, phys_offset, entry->size, cur_path);
} else {
printf("rom:%s\n", cur_path->char_path);
}
} else {
found_file = 0;
}
free(cur_path);
if (entry->sibling != ROMFS_ENTRY_EMPTY) {
nca_visit_romfs_file(ctx, entry->sibling, dir_path);
return found_file | nca_visit_romfs_file(ctx, entry->sibling, dir_path);
}
return found_file;
}
void nca_visit_romfs_dir(nca_section_ctx_t *ctx, uint32_t dir_offset, filepath_t *parent_path) {
int nca_visit_romfs_dir(nca_section_ctx_t *ctx, uint32_t dir_offset, filepath_t *parent_path) {
romfs_direntry_t *entry;
if (ctx->type == ROMFS) {
entry = romfs_get_direntry(ctx->romfs_ctx.directories, dir_offset);
@ -1251,18 +1287,27 @@ void nca_visit_romfs_dir(nca_section_ctx_t *ctx, uint32_t dir_offset, filepath_t
if ((ctx->tool_ctx->action & ACTION_LISTROMFS) == 0) {
os_makedir(cur_path->os_path);
}
int any_files = 0;
if (entry->file != ROMFS_ENTRY_EMPTY) {
nca_visit_romfs_file(ctx, entry->file, cur_path);
any_files |= nca_visit_romfs_file(ctx, entry->file, cur_path);
}
if (entry->child != ROMFS_ENTRY_EMPTY) {
nca_visit_romfs_dir(ctx, entry->child, cur_path);
any_files |= nca_visit_romfs_dir(ctx, entry->child, cur_path);
}
if (any_files == 0 && ctx->type == BKTR && (ctx->tool_ctx->action & ACTION_ONLYUPDATEDROMFS)) {
os_rmdir(cur_path->os_path);
}
if (entry->sibling != ROMFS_ENTRY_EMPTY) {
nca_visit_romfs_dir(ctx, entry->sibling, parent_path);
}
free(cur_path);
return any_files;
}

View file

@ -11,7 +11,8 @@ typedef enum {
typedef enum {
BASEFILE_ROMFS,
BASEFILE_NCA
BASEFILE_NCA,
BASEFILE_FAKE
} hactool_basefile_t;
typedef struct {
@ -88,6 +89,7 @@ enum hactool_file_type
#define ACTION_LISTROMFS (1<<4)
#define ACTION_DEV (1<<5)
#define ACTION_EXTRACTINI1 (1<<6)
#define ACTION_ONLYUPDATEDROMFS (1<<7)
struct nca_ctx; /* This will get re-defined by nca.h. */