2019-06-04 19:41:18 +00:00
|
|
|
#ifndef HACTOOL_SAVE_H
|
|
|
|
#define HACTOOL_SAVE_H
|
|
|
|
#include "types.h"
|
|
|
|
#include "settings.h"
|
|
|
|
#include "ivfc.h"
|
|
|
|
|
|
|
|
#define SAVE_HEADER_SIZE 0x4000
|
|
|
|
|
|
|
|
#define MAGIC_DISF 0x46534944
|
|
|
|
#define MAGIC_DPFS 0x53465044
|
|
|
|
#define MAGIC_JNGL 0x4C474E4A
|
|
|
|
#define MAGIC_SAVE 0x45564153
|
|
|
|
#define MAGIC_RMAP 0x50414D52
|
|
|
|
#define MAGIC_IVFC 0x43465649
|
|
|
|
|
2019-10-13 22:22:47 +00:00
|
|
|
typedef struct save_ctx_t save_ctx_t;
|
|
|
|
|
2019-06-04 19:41:18 +00:00
|
|
|
typedef struct {
|
|
|
|
uint32_t magic; /* DISF */
|
|
|
|
uint32_t version;
|
|
|
|
uint8_t hash[0x20];
|
|
|
|
uint64_t file_map_entry_offset;
|
|
|
|
uint64_t file_map_entry_size;
|
|
|
|
uint64_t meta_map_entry_offset;
|
|
|
|
uint64_t meta_map_entry_size;
|
|
|
|
uint64_t file_map_data_offset;
|
|
|
|
uint64_t file_map_data_size;
|
|
|
|
uint64_t duplex_l1_offset_a;
|
|
|
|
uint64_t duplex_l1_offset_b;
|
|
|
|
uint64_t duplex_l1_size;
|
|
|
|
uint64_t duplex_data_offset_a;
|
|
|
|
uint64_t duplex_data_offset_b;
|
|
|
|
uint64_t duplex_data_size;
|
|
|
|
uint64_t journal_data_offset;
|
|
|
|
uint64_t journal_data_size_a;
|
|
|
|
uint64_t journal_data_size_b;
|
|
|
|
uint64_t journal_size;
|
|
|
|
uint64_t duplex_master_offset_a;
|
|
|
|
uint64_t duplex_master_offset_b;
|
|
|
|
uint64_t duplex_master_size;
|
|
|
|
uint64_t ivfc_master_hash_offset_a;
|
|
|
|
uint64_t ivfc_master_hash_offset_b;
|
|
|
|
uint64_t ivfc_master_hash_size;
|
|
|
|
uint64_t journal_map_table_offset;
|
|
|
|
uint64_t journal_map_table_size;
|
|
|
|
uint64_t journal_physical_bitmap_offset;
|
|
|
|
uint64_t journal_physical_bitmap_size;
|
|
|
|
uint64_t journal_virtual_bitmap_offset;
|
|
|
|
uint64_t journal_virtual_bitmap_size;
|
|
|
|
uint64_t journal_free_bitmap_offset;
|
|
|
|
uint64_t journal_free_bitmap_size;
|
|
|
|
uint64_t ivfc_l1_offset;
|
|
|
|
uint64_t ivfc_l1_size;
|
|
|
|
uint64_t ivfc_l2_offset;
|
|
|
|
uint64_t ivfc_l2_size;
|
|
|
|
uint64_t ivfc_l3_offset;
|
|
|
|
uint64_t ivfc_l3_size;
|
|
|
|
uint64_t fat_offset;
|
|
|
|
uint64_t fat_size;
|
|
|
|
uint64_t duplex_index;
|
|
|
|
uint64_t fat_ivfc_master_hash_a;
|
|
|
|
uint64_t fat_ivfc_master_hash_b;
|
|
|
|
uint64_t fat_ivfc_l1_offset;
|
|
|
|
uint64_t fat_ivfc_l1_size;
|
|
|
|
uint64_t fat_ivfc_l2_offset;
|
|
|
|
uint64_t fat_ivfc_l2_size;
|
|
|
|
uint8_t _0x190[0x70];
|
|
|
|
} fs_layout_t;
|
|
|
|
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
typedef struct {
|
|
|
|
uint64_t offset;
|
|
|
|
uint64_t length;
|
|
|
|
uint32_t block_size_power;
|
|
|
|
} duplex_info_t;
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint32_t magic; /* DPFS */
|
|
|
|
uint32_t version;
|
|
|
|
duplex_info_t layers[3];
|
|
|
|
} duplex_header_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint32_t version;
|
|
|
|
uint32_t main_data_block_count;
|
|
|
|
uint32_t journal_block_count;
|
|
|
|
uint32_t _0x0C;
|
|
|
|
} journal_map_header_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint32_t magic; /* JNGL */
|
|
|
|
uint32_t version;
|
|
|
|
uint64_t total_size;
|
|
|
|
uint64_t journal_size;
|
|
|
|
uint64_t block_size;
|
|
|
|
} journal_header_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint32_t magic; /* SAVE */
|
|
|
|
uint32_t version;
|
|
|
|
uint64_t block_count;
|
|
|
|
uint64_t block_size;
|
|
|
|
} save_fs_header_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint64_t block_size;
|
|
|
|
uint64_t fat_offset;
|
|
|
|
uint32_t fat_block_count;
|
|
|
|
uint32_t _0x14;
|
|
|
|
uint64_t data_offset;
|
|
|
|
uint32_t data_block_count;
|
|
|
|
uint32_t _0x24;
|
|
|
|
uint32_t directory_table_block;
|
|
|
|
uint32_t file_table_block;
|
|
|
|
} fat_header_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint32_t magic; /* RMAP */
|
|
|
|
uint32_t version;
|
|
|
|
uint32_t map_entry_count;
|
|
|
|
uint32_t map_segment_count;
|
|
|
|
uint32_t segment_bits;
|
|
|
|
uint8_t _0x14[0x2C];
|
|
|
|
} remap_header_t;
|
|
|
|
|
2019-10-08 15:24:16 +00:00
|
|
|
typedef struct remap_segment_ctx_t remap_segment_ctx_t;
|
|
|
|
typedef struct remap_entry_ctx_t remap_entry_ctx_t;
|
|
|
|
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
struct remap_entry_ctx_t {
|
|
|
|
uint64_t virtual_offset;
|
|
|
|
uint64_t physical_offset;
|
|
|
|
uint64_t size;
|
|
|
|
uint32_t alignment;
|
|
|
|
uint32_t _0x1C;
|
|
|
|
uint64_t virtual_offset_end;
|
|
|
|
uint64_t physical_offset_end;
|
|
|
|
remap_segment_ctx_t *segment;
|
|
|
|
remap_entry_ctx_t *next;
|
|
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
struct remap_segment_ctx_t{
|
|
|
|
uint64_t offset;
|
|
|
|
uint64_t length;
|
|
|
|
remap_entry_ctx_t *entries;
|
|
|
|
uint64_t entry_count;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct {
|
2019-10-10 00:45:28 +00:00
|
|
|
uint8_t *data;
|
|
|
|
uint8_t *bitmap;
|
|
|
|
} duplex_bitmap_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint32_t block_size;
|
|
|
|
uint8_t *bitmap_storage;
|
|
|
|
uint8_t *data_a;
|
|
|
|
uint8_t *data_b;
|
|
|
|
duplex_bitmap_t bitmap;
|
|
|
|
uint64_t _length;
|
|
|
|
} duplex_storage_ctx_t;
|
|
|
|
|
|
|
|
enum base_storage_type {
|
|
|
|
STORAGE_BYTES = 0,
|
|
|
|
STORAGE_DUPLEX = 1,
|
|
|
|
STORAGE_REMAP = 2,
|
|
|
|
STORAGE_JOURNAL = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct {
|
2019-10-08 15:24:16 +00:00
|
|
|
remap_header_t *header;
|
|
|
|
remap_entry_ctx_t *map_entries;
|
|
|
|
remap_segment_ctx_t *segments;
|
2019-10-10 00:45:28 +00:00
|
|
|
enum base_storage_type type;
|
|
|
|
uint64_t base_storage_offset;
|
|
|
|
duplex_storage_ctx_t *duplex;
|
2019-10-08 15:24:16 +00:00
|
|
|
FILE *file;
|
|
|
|
} remap_storage_ctx_t;
|
|
|
|
|
2019-06-04 19:41:18 +00:00
|
|
|
typedef struct {
|
|
|
|
uint64_t title_id;
|
|
|
|
uint8_t user_id[0x10];
|
|
|
|
uint64_t save_id;
|
|
|
|
uint8_t save_data_type;
|
|
|
|
uint8_t _0x21[0x1F];
|
|
|
|
uint64_t save_owner_id;
|
|
|
|
uint64_t timestamp;
|
|
|
|
uint64_t _0x50;
|
|
|
|
uint64_t data_size;
|
|
|
|
uint64_t journal_size;
|
|
|
|
uint64_t commit_id;
|
|
|
|
} extra_data_t;
|
|
|
|
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
typedef struct {
|
|
|
|
uint8_t cmac[0x10];
|
|
|
|
uint8_t _0x10[0xF0];
|
|
|
|
fs_layout_t layout;
|
|
|
|
duplex_header_t duplex_header;
|
2019-10-08 15:24:16 +00:00
|
|
|
ivfc_save_hdr_t data_ivfc_header;
|
2019-06-04 19:41:18 +00:00
|
|
|
uint32_t _0x404;
|
|
|
|
journal_header_t journal_header;
|
|
|
|
journal_map_header_t map_header;
|
|
|
|
uint8_t _0x438[0x1D0];
|
|
|
|
save_fs_header_t save_header;
|
|
|
|
fat_header_t fat_header;
|
|
|
|
remap_header_t main_remap_header, meta_remap_header;
|
|
|
|
uint64_t _0x6D0;
|
|
|
|
extra_data_t extra_data;
|
|
|
|
uint8_t _0x748[0x390];
|
|
|
|
ivfc_save_hdr_t fat_ivfc_header;
|
2019-10-08 15:24:16 +00:00
|
|
|
uint8_t _0xB98[0x3468];
|
2019-06-04 19:41:18 +00:00
|
|
|
} save_header_t;
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
2019-10-08 15:24:16 +00:00
|
|
|
typedef struct {
|
|
|
|
duplex_storage_ctx_t layers[2];
|
|
|
|
duplex_storage_ctx_t data_layer;
|
|
|
|
uint64_t _length;
|
|
|
|
} hierarchical_duplex_storage_ctx_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint8_t *data_a;
|
|
|
|
uint8_t *data_b;
|
|
|
|
duplex_info_t info;
|
|
|
|
} duplex_fs_layer_info_t;
|
|
|
|
|
2019-10-10 00:45:28 +00:00
|
|
|
typedef struct {
|
|
|
|
uint8_t *map_storage;
|
|
|
|
uint8_t *physical_block_bitmap;
|
|
|
|
uint8_t *virtual_block_bitmap;
|
|
|
|
uint8_t *free_block_bitmap;
|
|
|
|
} journal_map_params_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint32_t physical_index;
|
|
|
|
uint32_t virtual_index;
|
|
|
|
} journal_map_entry_t;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
journal_map_header_t *header;
|
|
|
|
journal_map_entry_t *entries;
|
|
|
|
uint8_t *map_storage;
|
|
|
|
} journal_map_ctx_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
journal_map_ctx_t map;
|
|
|
|
journal_header_t *header;
|
|
|
|
uint32_t block_size;
|
2019-10-13 22:22:47 +00:00
|
|
|
uint64_t journal_data_offset;
|
2019-10-10 00:45:28 +00:00
|
|
|
uint64_t _length;
|
2019-10-13 22:22:47 +00:00
|
|
|
FILE *file;
|
2019-10-10 00:45:28 +00:00
|
|
|
} journal_storage_ctx_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint64_t data_offset;
|
|
|
|
uint64_t data_size;
|
|
|
|
uint64_t hash_offset;
|
|
|
|
uint32_t hash_block_size;
|
|
|
|
validity_t hash_validity;
|
|
|
|
enum base_storage_type type;
|
2019-10-13 22:22:47 +00:00
|
|
|
save_ctx_t *save_ctx;
|
2019-10-10 00:45:28 +00:00
|
|
|
} ivfc_level_save_ctx_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
ivfc_level_save_ctx_t *data;
|
|
|
|
uint32_t block_size;
|
|
|
|
uint8_t salt[0x20];
|
|
|
|
} integrity_verification_info_ctx_t;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
ivfc_level_save_ctx_t *hash_storage;
|
2019-10-13 22:22:47 +00:00
|
|
|
ivfc_level_save_ctx_t *base_storage;
|
2019-10-10 00:45:28 +00:00
|
|
|
validity_t *block_validities;
|
|
|
|
uint8_t salt[0x20];
|
|
|
|
uint32_t sector_size;
|
|
|
|
uint32_t sector_count;
|
|
|
|
uint64_t _length;
|
|
|
|
} integrity_verification_storage_ctx_t;
|
|
|
|
|
|
|
|
typedef struct {
|
2019-10-10 20:16:22 +00:00
|
|
|
ivfc_level_save_ctx_t levels[5];
|
2019-10-10 00:45:28 +00:00
|
|
|
ivfc_level_save_ctx_t *data_level;
|
|
|
|
validity_t **level_validities;
|
|
|
|
uint64_t _length;
|
|
|
|
integrity_verification_storage_ctx_t integrity_storages[4];
|
|
|
|
} hierarchical_integrity_verification_storage_ctx_t;
|
|
|
|
|
2019-10-13 22:22:47 +00:00
|
|
|
struct save_ctx_t {
|
2019-06-04 19:41:18 +00:00
|
|
|
FILE *file;
|
|
|
|
hactool_ctx_t *tool_ctx;
|
|
|
|
save_header_t header;
|
2019-10-08 15:24:16 +00:00
|
|
|
validity_t header_cmac_validity;
|
|
|
|
validity_t header_hash_validity;
|
|
|
|
uint8_t *data_ivfc_master;
|
|
|
|
uint8_t *fat_ivfc_master;
|
|
|
|
remap_storage_ctx_t data_remap_storage;
|
|
|
|
remap_storage_ctx_t meta_remap_storage;
|
|
|
|
duplex_fs_layer_info_t duplex_layers[3];
|
2019-10-10 00:45:28 +00:00
|
|
|
hierarchical_duplex_storage_ctx_t duplex_storage;
|
|
|
|
journal_storage_ctx_t journal_storage;
|
2019-10-10 20:16:22 +00:00
|
|
|
journal_map_params_t journal_map_info;
|
2019-10-10 00:45:28 +00:00
|
|
|
hierarchical_integrity_verification_storage_ctx_t core_data_ivfc_storage;
|
|
|
|
hierarchical_integrity_verification_storage_ctx_t fat_ivfc_storage;
|
2019-10-13 22:22:47 +00:00
|
|
|
uint8_t *fat_storage;
|
|
|
|
};
|
2019-06-04 19:41:18 +00:00
|
|
|
|
|
|
|
void save_process(save_ctx_t *ctx);
|
2019-10-08 15:24:16 +00:00
|
|
|
void save_process_header(save_ctx_t *ctx);
|
2019-06-04 19:41:18 +00:00
|
|
|
void save_save(save_ctx_t *ctx);
|
|
|
|
void save_print(save_ctx_t *ctx);
|
|
|
|
|
2019-10-08 15:24:16 +00:00
|
|
|
void save_free_contexts(save_ctx_t *ctx);
|
|
|
|
|
2019-10-10 00:45:28 +00:00
|
|
|
void save_duplex_storage_init(duplex_storage_ctx_t *ctx, duplex_fs_layer_info_t *layer, void *bitmap, uint64_t bitmap_size);
|
|
|
|
void save_duplex_storage_read(duplex_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count);
|
|
|
|
|
2019-06-04 19:41:18 +00:00
|
|
|
#endif
|