mirror of
https://github.com/SciresM/hactool
synced 2024-11-23 04:23:13 +00:00
Implement -t romfs (and placeholder code for remaining types) (#4)
This commit is contained in:
parent
d762f71f98
commit
ac7b24a24e
7 changed files with 254 additions and 61 deletions
4
Makefile
4
Makefile
|
@ -17,7 +17,7 @@ all:
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
|
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
hactool: sha.o aes.o rsa.o npdm.o bktr.o pki.o pfs0.o utils.o nca.o main.o filepath.o
|
hactool: sha.o aes.o rsa.o npdm.o bktr.o pki.o pfs0.o romfs.o utils.o nca.o main.o filepath.o
|
||||||
$(CC) -o $@ $^ $(LDFLAGS) -L $(LIBDIR)
|
$(CC) -o $@ $^ $(LDFLAGS) -L $(LIBDIR)
|
||||||
|
|
||||||
aes.o: aes.h types.h
|
aes.o: aes.h types.h
|
||||||
|
@ -36,6 +36,8 @@ nca.o: nca.h aes.h sha.h rsa.h bktr.h filepath.h types.h
|
||||||
|
|
||||||
npdm.o: npdm.c types.h
|
npdm.o: npdm.c types.h
|
||||||
|
|
||||||
|
romfs.o: ivfc.h types.h
|
||||||
|
|
||||||
rsa.o: rsa.h sha.h types.h
|
rsa.o: rsa.h sha.h types.h
|
||||||
|
|
||||||
sha.o: sha.h types.h
|
sha.o: sha.h types.h
|
||||||
|
|
25
ivfc.h
25
ivfc.h
|
@ -2,6 +2,9 @@
|
||||||
#define HACTOOL_IVFC_H
|
#define HACTOOL_IVFC_H
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
|
||||||
#define IVFC_HEADER_SIZE 0xE0
|
#define IVFC_HEADER_SIZE 0xE0
|
||||||
#define IVFC_MAX_LEVEL 6
|
#define IVFC_MAX_LEVEL 6
|
||||||
|
@ -69,6 +72,23 @@ typedef struct {
|
||||||
char name[];
|
char name[];
|
||||||
} romfs_fentry_t;
|
} romfs_fentry_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ivfc_hdr_t ivfc_header;
|
||||||
|
uint8_t _0xE0[0x58];
|
||||||
|
} romfs_superblock_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
romfs_superblock_t *superblock;
|
||||||
|
FILE *file;
|
||||||
|
hactool_ctx_t *tool_ctx;
|
||||||
|
validity_t superblock_hash_validity;
|
||||||
|
ivfc_level_ctx_t ivfc_levels[IVFC_MAX_LEVEL];
|
||||||
|
uint64_t romfs_offset;
|
||||||
|
romfs_hdr_t header;
|
||||||
|
romfs_direntry_t *directories;
|
||||||
|
romfs_fentry_t *files;
|
||||||
|
} romfs_ctx_t;
|
||||||
|
|
||||||
#define ROMFS_ENTRY_EMPTY 0xFFFFFFFF
|
#define ROMFS_ENTRY_EMPTY 0xFFFFFFFF
|
||||||
|
|
||||||
static inline romfs_direntry_t *romfs_get_direntry(romfs_direntry_t *directories, uint32_t offset) {
|
static inline romfs_direntry_t *romfs_get_direntry(romfs_direntry_t *directories, uint32_t offset) {
|
||||||
|
@ -79,4 +99,9 @@ static inline romfs_fentry_t *romfs_get_fentry(romfs_fentry_t *files, uint32_t o
|
||||||
return (romfs_fentry_t *)((char *)files + offset);
|
return (romfs_fentry_t *)((char *)files + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void romfs_process(romfs_ctx_t *ctx);
|
||||||
|
void romfs_save(romfs_ctx_t *ctx);
|
||||||
|
void romfs_print(romfs_ctx_t *ctx);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
49
main.c
49
main.c
|
@ -26,7 +26,7 @@ static void usage(void) {
|
||||||
" -r, --raw Keep raw data, don't unpack.\n"
|
" -r, --raw Keep raw data, don't unpack.\n"
|
||||||
" -y, --verify Verify hashes and signatures.\n"
|
" -y, --verify Verify hashes and signatures.\n"
|
||||||
" -d, --dev Decrypt with development keys instead of retail.\n"
|
" -d, --dev Decrypt with development keys instead of retail.\n"
|
||||||
" -t, --intype=type Specify input file type [nca, pfs0]\n"
|
" -t, --intype=type Specify input file type [nca, pfs0, romfs]\n"
|
||||||
" --titlekey=key Set title key for Rights ID crypto titles.\n"
|
" --titlekey=key Set title key for Rights ID crypto titles.\n"
|
||||||
" --contentkey=key Set raw key for NCA body decryption.\n"
|
" --contentkey=key Set raw key for NCA body decryption.\n"
|
||||||
"NCA options:\n"
|
"NCA options:\n"
|
||||||
|
@ -49,6 +49,9 @@ static void usage(void) {
|
||||||
" --basenca Set Base NCA to use with update partitions.\n"
|
" --basenca Set Base NCA to use with update partitions.\n"
|
||||||
"PFS0 options:\n"
|
"PFS0 options:\n"
|
||||||
" --outdir=dir Specify PFS0 directory path.\n"
|
" --outdir=dir Specify PFS0 directory path.\n"
|
||||||
|
"RomFS options:\n"
|
||||||
|
" --romfsdir=dir Specify RomFS directory path.\n"
|
||||||
|
" --listromfs List files in RomFS.\n"
|
||||||
"\n", __TIME__, __DATE__, prog_name);
|
"\n", __TIME__, __DATE__, prog_name);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +174,22 @@ int main(int argc, char **argv) {
|
||||||
nca_ctx.tool_ctx->file_type = FILETYPE_NCA;
|
nca_ctx.tool_ctx->file_type = FILETYPE_NCA;
|
||||||
} else if (!strcmp(optarg, "pfs0") || !strcmp(optarg, "exefs")) {
|
} else if (!strcmp(optarg, "pfs0") || !strcmp(optarg, "exefs")) {
|
||||||
nca_ctx.tool_ctx->file_type = FILETYPE_PFS0;
|
nca_ctx.tool_ctx->file_type = FILETYPE_PFS0;
|
||||||
|
} else if (!strcmp(optarg, "romfs")) {
|
||||||
|
nca_ctx.tool_ctx->file_type = FILETYPE_ROMFS;
|
||||||
}
|
}
|
||||||
|
/* } else if (!strcmp(optarg, "hfs0")) {
|
||||||
|
* nca_ctx.tool_ctx->file_type = FILETYPE_HFS0;
|
||||||
|
* }
|
||||||
|
* } else if (!strcmp(optarg, "xci") || !strcmp(optarg, "gamecard") || !strcmp(optarg, "gc")) {
|
||||||
|
* nca_ctx.tool_ctx->file_type = FILETYPE_XCI;
|
||||||
|
* }
|
||||||
|
* } else if (!strcmp(optarg, "package2") || !strcmp(optarg, "pk21")) {
|
||||||
|
* nca_ctx.tool_ctx->file_type = FILETYPE_PACKAGE2;
|
||||||
|
* }
|
||||||
|
* } else if (!strcmp(optarg, "package1") || !strcmp(optarg, "pk11")) {
|
||||||
|
* nca_ctx.tool_ctx->file_type = FILETYPE_PACKAGE1;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0: filepath_set(&nca_ctx.tool_ctx->settings.section_paths[0], optarg); break;
|
case 0: filepath_set(&nca_ctx.tool_ctx->settings.section_paths[0], optarg); break;
|
||||||
|
@ -266,7 +284,8 @@ int main(int argc, char **argv) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tool_ctx.file_type == FILETYPE_NCA) {
|
switch (tool_ctx.file_type) {
|
||||||
|
case FILETYPE_NCA: {
|
||||||
if (nca_ctx.tool_ctx->base_nca_ctx != NULL) {
|
if (nca_ctx.tool_ctx->base_nca_ctx != NULL) {
|
||||||
memcpy(&base_ctx.settings.keyset, &tool_ctx.settings.keyset, sizeof(nca_keyset_t));
|
memcpy(&base_ctx.settings.keyset, &tool_ctx.settings.keyset, sizeof(nca_keyset_t));
|
||||||
nca_ctx.tool_ctx->base_nca_ctx->tool_ctx = &base_ctx;
|
nca_ctx.tool_ctx->base_nca_ctx->tool_ctx = &base_ctx;
|
||||||
|
@ -295,7 +314,9 @@ int main(int argc, char **argv) {
|
||||||
free(nca_ctx.tool_ctx->base_nca_ctx);
|
free(nca_ctx.tool_ctx->base_nca_ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (tool_ctx.file_type == FILETYPE_PFS0) {
|
break;
|
||||||
|
}
|
||||||
|
case FILETYPE_PFS0: {
|
||||||
pfs0_ctx_t pfs0_ctx;
|
pfs0_ctx_t pfs0_ctx;
|
||||||
memset(&pfs0_ctx, 0, sizeof(pfs0_ctx));
|
memset(&pfs0_ctx, 0, sizeof(pfs0_ctx));
|
||||||
pfs0_ctx.file = tool_ctx.file;
|
pfs0_ctx.file = tool_ctx.file;
|
||||||
|
@ -307,9 +328,27 @@ int main(int argc, char **argv) {
|
||||||
if (pfs0_ctx.npdm) {
|
if (pfs0_ctx.npdm) {
|
||||||
free(pfs0_ctx.npdm);
|
free(pfs0_ctx.npdm);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FILETYPE_ROMFS: {
|
||||||
|
romfs_ctx_t romfs_ctx;
|
||||||
|
memset(&romfs_ctx, 0, sizeof(romfs_ctx));
|
||||||
|
romfs_ctx.file = tool_ctx.file;
|
||||||
|
romfs_ctx.tool_ctx = &tool_ctx;
|
||||||
|
romfs_process(&romfs_ctx);
|
||||||
|
if (romfs_ctx.files) {
|
||||||
|
free(romfs_ctx.files);
|
||||||
|
}
|
||||||
|
if (romfs_ctx.directories) {
|
||||||
|
free(romfs_ctx.directories);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
fprintf(stderr, "Unknown File Type!\n\n");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (tool_ctx.file != NULL) {
|
if (tool_ctx.file != NULL) {
|
||||||
fclose(tool_ctx.file);
|
fclose(tool_ctx.file);
|
||||||
|
|
16
nca.h
16
nca.h
|
@ -19,11 +19,6 @@ typedef struct {
|
||||||
uint8_t _0x8[0x8]; /* Padding. */
|
uint8_t _0x8[0x8]; /* Padding. */
|
||||||
} nca_section_entry_t;
|
} nca_section_entry_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
ivfc_hdr_t ivfc_header;
|
|
||||||
uint8_t _0xE0[0x58];
|
|
||||||
} romfs_superblock_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ivfc_hdr_t ivfc_header;
|
ivfc_hdr_t ivfc_header;
|
||||||
uint8_t _0xE0[0x18];
|
uint8_t _0xE0[0x18];
|
||||||
|
@ -31,17 +26,6 @@ typedef struct {
|
||||||
bktr_header_t subsection_header;
|
bktr_header_t subsection_header;
|
||||||
} bktr_superblock_t;
|
} bktr_superblock_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
romfs_superblock_t *superblock;
|
|
||||||
FILE *file;
|
|
||||||
validity_t superblock_hash_validity;
|
|
||||||
ivfc_level_ctx_t ivfc_levels[IVFC_MAX_LEVEL];
|
|
||||||
uint64_t romfs_offset;
|
|
||||||
romfs_hdr_t header;
|
|
||||||
romfs_direntry_t *directories;
|
|
||||||
romfs_fentry_t *files;
|
|
||||||
} romfs_ctx_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bktr_superblock_t *superblock;
|
bktr_superblock_t *superblock;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
|
6
pfs0.c
6
pfs0.c
|
@ -4,7 +4,7 @@
|
||||||
void pfs0_process(pfs0_ctx_t *ctx) {
|
void pfs0_process(pfs0_ctx_t *ctx) {
|
||||||
/* Read *just* safe amount. */
|
/* Read *just* safe amount. */
|
||||||
pfs0_header_t raw_header;
|
pfs0_header_t raw_header;
|
||||||
fseek(ctx->file, 0, SEEK_SET);
|
fseeko64(ctx->file, 0, SEEK_SET);
|
||||||
if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) {
|
if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) {
|
||||||
fprintf(stderr, "Failed to read PFS0 header!\n");
|
fprintf(stderr, "Failed to read PFS0 header!\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -22,7 +22,7 @@ void pfs0_process(pfs0_ctx_t *ctx) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(ctx->file, 0, SEEK_SET);
|
fseeko64(ctx->file, 0, SEEK_SET);
|
||||||
if (fread(ctx->header, 1, header_size, ctx->file) != header_size) {
|
if (fread(ctx->header, 1, header_size, ctx->file) != header_size) {
|
||||||
fprintf(stderr, "Failed to read PFS0 header!\n");
|
fprintf(stderr, "Failed to read PFS0 header!\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -51,7 +51,7 @@ void pfs0_process(pfs0_ctx_t *ctx) {
|
||||||
fprintf(stderr, "Failed to allocate NPDM!\n");
|
fprintf(stderr, "Failed to allocate NPDM!\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
fseek(ctx->file, pfs0_get_header_size(ctx->header) + cur_file->offset, SEEK_SET);
|
fseeko64(ctx->file, pfs0_get_header_size(ctx->header) + cur_file->offset, SEEK_SET);
|
||||||
if (fread(ctx->npdm, 1, cur_file->size, ctx->file) != cur_file->size) {
|
if (fread(ctx->npdm, 1, cur_file->size, ctx->file) != cur_file->size) {
|
||||||
fprintf(stderr, "Failed to read NPDM!\n");
|
fprintf(stderr, "Failed to read NPDM!\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
138
romfs.c
Normal file
138
romfs.c
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "types.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "ivfc.h"
|
||||||
|
|
||||||
|
/* RomFS functions... */
|
||||||
|
void romfs_visit_file(romfs_ctx_t *ctx, uint32_t file_offset, filepath_t *dir_path) {
|
||||||
|
romfs_fentry_t *entry = romfs_get_fentry(ctx->files, file_offset);
|
||||||
|
filepath_t *cur_path = calloc(1, sizeof(filepath_t));
|
||||||
|
if (cur_path == NULL) {
|
||||||
|
fprintf(stderr, "Failed to allocate filepath!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
filepath_copy(cur_path, dir_path);
|
||||||
|
if (entry->name_size) {
|
||||||
|
filepath_append_n(cur_path, entry->name_size, "%s", entry->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're extracting... */
|
||||||
|
if ((ctx->tool_ctx->action & ACTION_LISTROMFS) == 0) {
|
||||||
|
printf("Saving %s...\n", cur_path->char_path);
|
||||||
|
save_file_section(ctx->file, ctx->romfs_offset + ctx->header.data_offset + entry->offset, entry->size, cur_path);
|
||||||
|
} else {
|
||||||
|
printf("rom:%s\n", cur_path->char_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cur_path);
|
||||||
|
|
||||||
|
if (entry->sibling != ROMFS_ENTRY_EMPTY) {
|
||||||
|
romfs_visit_file(ctx, entry->sibling, dir_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void romfs_visit_dir(romfs_ctx_t *ctx, uint32_t dir_offset, filepath_t *parent_path) {
|
||||||
|
romfs_direntry_t *entry = romfs_get_direntry(ctx->directories, dir_offset);
|
||||||
|
filepath_t *cur_path = calloc(1, sizeof(filepath_t));
|
||||||
|
if (cur_path == NULL) {
|
||||||
|
fprintf(stderr, "Failed to allocate filepath!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
filepath_copy(cur_path, parent_path);
|
||||||
|
if (entry->name_size) {
|
||||||
|
filepath_append_n(cur_path, entry->name_size, "%s", entry->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're actually extracting the romfs, make directory. */
|
||||||
|
if ((ctx->tool_ctx->action & ACTION_LISTROMFS) == 0) {
|
||||||
|
os_makedir(cur_path->os_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->file != ROMFS_ENTRY_EMPTY) {
|
||||||
|
romfs_visit_file(ctx, entry->file, cur_path);
|
||||||
|
}
|
||||||
|
if (entry->child != ROMFS_ENTRY_EMPTY) {
|
||||||
|
romfs_visit_dir(ctx, entry->child, cur_path);
|
||||||
|
}
|
||||||
|
if (entry->sibling != ROMFS_ENTRY_EMPTY) {
|
||||||
|
romfs_visit_dir(ctx, entry->sibling, parent_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cur_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void romfs_process(romfs_ctx_t *ctx) {
|
||||||
|
ctx->romfs_offset = 0;
|
||||||
|
fseeko64(ctx->file, ctx->romfs_offset, SEEK_SET);
|
||||||
|
if (fread(&ctx->header, 1, sizeof(romfs_hdr_t), ctx->file) != sizeof(romfs_hdr_t)) {
|
||||||
|
fprintf(stderr, "Failed to read RomFS header!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ctx->tool_ctx->action & (ACTION_EXTRACT | ACTION_LISTROMFS)) && ctx->header.header_size == ROMFS_HEADER_SIZE) {
|
||||||
|
/* Pre-load the file/data entry caches. */
|
||||||
|
ctx->directories = calloc(1, ctx->header.dir_meta_table_size);
|
||||||
|
if (ctx->directories == NULL) {
|
||||||
|
fprintf(stderr, "Failed to allocate RomFS directory cache!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Switch RomFS has actual entries at table offset + 4 for no good reason. */
|
||||||
|
fseeko64(ctx->file, ctx->romfs_offset + ctx->header.dir_meta_table_offset + 4, SEEK_SET);
|
||||||
|
if (fread(ctx->directories, 1, ctx->header.dir_meta_table_size, ctx->file) != ctx->header.dir_meta_table_size) {
|
||||||
|
fprintf(stderr, "Failed to read RomFS directory cache!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->files = calloc(1, ctx->header.file_meta_table_size);
|
||||||
|
if (ctx->files == NULL) {
|
||||||
|
fprintf(stderr, "Failed to allocate RomFS file cache!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
fseeko64(ctx->file, ctx->romfs_offset + ctx->header.file_meta_table_offset, SEEK_SET);
|
||||||
|
if (fread(ctx->files, 1, ctx->header.file_meta_table_size, ctx->file) != ctx->header.file_meta_table_size) {
|
||||||
|
fprintf(stderr, "Failed to read RomFS file cache!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there's ever anything meaningful to print about RomFS, uncomment and implement.
|
||||||
|
*
|
||||||
|
* if (ctx->tool_ctx->action & ACTION_INFO) {
|
||||||
|
* romfs_print(ctx);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
|
||||||
|
romfs_save(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void romfs_save(romfs_ctx_t *ctx) {
|
||||||
|
if (ctx->tool_ctx->action & ACTION_LISTROMFS) {
|
||||||
|
filepath_t fakepath;
|
||||||
|
filepath_init(&fakepath);
|
||||||
|
filepath_set(&fakepath, "");
|
||||||
|
|
||||||
|
romfs_visit_dir(ctx, 0, &fakepath);
|
||||||
|
} else {
|
||||||
|
/* Extract to directory. */
|
||||||
|
filepath_t *dirpath = NULL;
|
||||||
|
if (ctx->tool_ctx->settings.romfs_dir_path.enabled) {
|
||||||
|
dirpath = &ctx->tool_ctx->settings.romfs_dir_path.path;
|
||||||
|
}
|
||||||
|
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
||||||
|
os_makedir(dirpath->os_path);
|
||||||
|
romfs_visit_dir(ctx, 0, dirpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void romfs_print(romfs_ctx_t *ctx) {
|
||||||
|
/* Is there anything meaningful to print here? */
|
||||||
|
fprintf(stderr, "Error: RomFS printing not implemented.\n");
|
||||||
|
}
|
|
@ -57,7 +57,12 @@ typedef struct {
|
||||||
enum hactool_file_type
|
enum hactool_file_type
|
||||||
{
|
{
|
||||||
FILETYPE_NCA,
|
FILETYPE_NCA,
|
||||||
FILETYPE_PFS0
|
FILETYPE_PFS0,
|
||||||
|
FILETYPE_ROMFS,
|
||||||
|
/* FILETYPE_HFS0, */
|
||||||
|
/* FILETYPE_XCI, */
|
||||||
|
/* FILETYPE_PACKAGE2, */
|
||||||
|
/* FILETYPE_PACKAGE1, */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ACTION_INFO (1<<0)
|
#define ACTION_INFO (1<<0)
|
||||||
|
|
Loading…
Reference in a new issue