nx_savedata: More fail paths, ensure alignment
This commit is contained in:
parent
1f77c50975
commit
044c8b32f0
|
@ -38,12 +38,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
#include <gfx_utils.h>
|
||||
|
||||
void save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block) {
|
||||
bool save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block) {
|
||||
ctx->base_storage = data;
|
||||
ctx->block_size = block_size;
|
||||
ctx->fat = table;
|
||||
ctx->initial_block = initial_block;
|
||||
ctx->_length = initial_block == 0xFFFFFFFF ? 0 : save_allocation_table_get_list_length(table, initial_block) * block_size;
|
||||
ctx->_length = 0;
|
||||
if (initial_block != 0xFFFFFFFF) {
|
||||
uint32_t list_length = save_allocation_table_get_list_length(table, initial_block);
|
||||
if (list_length == 0) {
|
||||
EPRINTF("Allocation table storage init failed!");
|
||||
return false;
|
||||
};
|
||||
ctx->_length = list_length * block_size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count) {
|
||||
|
|
|
@ -52,7 +52,7 @@ static ALWAYS_INLINE void save_allocation_table_storage_get_size(allocation_tabl
|
|||
*out_size = ctx->_length;
|
||||
}
|
||||
|
||||
void save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block);
|
||||
bool save_allocation_table_storage_init(allocation_table_storage_ctx_t *ctx, substorage *data, allocation_table_ctx_t *table, uint32_t block_size, uint32_t initial_block);
|
||||
uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, uint64_t count);
|
||||
uint32_t save_allocation_table_storage_write(allocation_table_storage_ctx_t *ctx, const void *buffer, uint64_t offset, uint64_t count);
|
||||
bool save_allocation_table_storage_set_size(allocation_table_storage_ctx_t *ctx, uint64_t size);
|
||||
|
|
|
@ -135,7 +135,7 @@ validity_t save_hierarchical_integrity_verification_storage_validate(hierarchica
|
|||
validity_t result = VALIDITY_VALID;
|
||||
integrity_verification_storage_ctx_t *storage = &ctx->integrity_storages[3];
|
||||
|
||||
uint64_t block_size = storage->base_storage.sector_size;
|
||||
uint32_t block_size = storage->base_storage.sector_size;
|
||||
uint32_t block_count = (uint32_t)(DIV_ROUND_UP(ctx->length, block_size));
|
||||
|
||||
uint8_t *buffer = malloc(block_size);
|
||||
|
@ -143,7 +143,7 @@ validity_t save_hierarchical_integrity_verification_storage_validate(hierarchica
|
|||
for (unsigned int i = 0; i < block_count; i++) {
|
||||
if (ctx->level_validities[3][i] == VALIDITY_UNCHECKED) {
|
||||
uint64_t storage_size = storage->base_storage.length;
|
||||
uint32_t to_read = MIN((uint32_t)(storage_size - block_size * i), (uint32_t)block_size);
|
||||
uint32_t to_read = MIN((uint32_t)(storage_size - block_size * i), block_size);
|
||||
substorage_read(&ctx->data_level->base_storage, buffer, block_size * i, to_read);
|
||||
}
|
||||
if (ctx->level_validities[3][i] == VALIDITY_INVALID) {
|
||||
|
|
|
@ -207,7 +207,7 @@ void save_hierarchical_file_table_unlink_file_from_parent(hierarchical_save_file
|
|||
return;
|
||||
}
|
||||
prev_index = cur_index;
|
||||
memcpy(&prev_entry, &cur_entry, sizeof(prev_entry));
|
||||
memcpy(&prev_entry, &cur_entry, sizeof(save_table_entry_t));
|
||||
cur_index = prev_entry.next_sibling;
|
||||
}
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ void save_hierarchical_file_table_unlink_directory_from_parent(hierarchical_save
|
|||
return;
|
||||
}
|
||||
prev_index = cur_index;
|
||||
memcpy(&prev_entry, &cur_entry, sizeof(prev_entry));
|
||||
memcpy(&prev_entry, &cur_entry, sizeof(save_table_entry_t));
|
||||
cur_index = prev_entry.next_sibling;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ void save_ivfc_storage_init(integrity_verification_storage_ctx_t *ctx, integrity
|
|||
/* buffer must have size count + 0x20 for salt to by copied in at offset 0. */
|
||||
static ALWAYS_INLINE void save_ivfc_storage_do_hash(integrity_verification_storage_ctx_t *ctx, uint8_t *out_hash, void *buffer, uint64_t count) {
|
||||
memcpy(buffer, ctx->salt, sizeof(ctx->salt));
|
||||
se_calc_sha256(out_hash, buffer, count + sizeof(ctx->salt));
|
||||
se_calc_sha256_oneshot(out_hash, buffer, count + sizeof(ctx->salt));
|
||||
out_hash[0x1F] |= 0x80;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ bool save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf
|
|||
return false;
|
||||
}
|
||||
|
||||
uint8_t hash_buffer[0x20] = {0};
|
||||
uint8_t hash_buffer[0x20] __attribute__((aligned(4))) = {0};
|
||||
uint64_t hash_pos = block_index * sizeof(hash_buffer);
|
||||
|
||||
if (substorage_read(&ctx->hash_storage, hash_buffer, hash_pos, sizeof(hash_buffer)) != sizeof(hash_buffer))
|
||||
|
@ -99,17 +99,16 @@ bool save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf
|
|||
return false;
|
||||
}
|
||||
|
||||
memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count);
|
||||
|
||||
if (ctx->integrity_check_level && ctx->block_validities[block_index] != VALIDITY_UNCHECKED) {
|
||||
memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count);
|
||||
free(data_buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t hash[0x20] = {0};
|
||||
uint8_t hash[0x20] __attribute__((aligned(4))) = {0};
|
||||
save_ivfc_storage_do_hash(ctx, hash, data_buffer, ctx->base_storage.sector_size);
|
||||
memcpy(buffer, data_buffer + 0x20 + (offset % ctx->base_storage.sector_size), count);
|
||||
free(data_buffer);
|
||||
|
||||
if (memcmp(hash_buffer, hash, sizeof(hash_buffer)) == 0) {
|
||||
ctx->block_validities[block_index] = VALIDITY_VALID;
|
||||
} else {
|
||||
|
@ -127,7 +126,7 @@ bool save_ivfc_storage_write(integrity_verification_storage_ctx_t *ctx, const vo
|
|||
uint64_t block_index = offset / ctx->base_storage.sector_size;
|
||||
uint64_t hash_pos = block_index * 0x20;
|
||||
|
||||
uint8_t hash[0x20] = {0};
|
||||
uint8_t hash[0x20] __attribute__((aligned(4))) = {0};
|
||||
uint8_t *data_buffer = calloc(1, ctx->base_storage.sector_size + 0x20);
|
||||
if (count < ctx->base_storage.sector_size) {
|
||||
if (substorage_read(&ctx->base_storage.base_storage, data_buffer + 0x20, offset - (offset % ctx->base_storage.sector_size), ctx->base_storage.sector_size) != ctx->base_storage.sector_size) {
|
||||
|
|
|
@ -98,13 +98,13 @@ static bool save_process_header(save_ctx_t *ctx) {
|
|||
ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a;
|
||||
ctx->fat_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.fat_ivfc_master_hash_a;
|
||||
|
||||
uint8_t hash[0x20];
|
||||
uint8_t hash[0x20] __attribute__((aligned(4)));
|
||||
uint32_t hashed_data_offset = sizeof(ctx->header.layout) + sizeof(ctx->header.cmac) + sizeof(ctx->header._0x10);
|
||||
uint32_t hashed_data_size = sizeof(ctx->header) - hashed_data_offset;
|
||||
se_calc_sha256(hash, (uint8_t *)&ctx->header + hashed_data_offset, hashed_data_size);
|
||||
ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, 0x20) == 0 ? VALIDITY_VALID : VALIDITY_INVALID;
|
||||
se_calc_sha256_oneshot(hash, (uint8_t *)&ctx->header + hashed_data_offset, hashed_data_size);
|
||||
ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, sizeof(hash)) == 0 ? VALIDITY_VALID : VALIDITY_INVALID;
|
||||
|
||||
unsigned char cmac[0x10] = {};
|
||||
uint8_t cmac[0x10] __attribute__((aligned(4)));
|
||||
se_aes_key_set(10, ctx->save_mac_key, 0x10);
|
||||
se_aes_cmac(10, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout));
|
||||
if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) {
|
||||
|
@ -126,14 +126,14 @@ bool save_process(save_ctx_t *ctx) {
|
|||
substorage_init(&ctx->base_storage, &file_storage_vt, ctx->file, 0, f_size(ctx->file));
|
||||
/* Try to parse Header A. */
|
||||
if (substorage_read(&ctx->base_storage, &ctx->header, 0, sizeof(ctx->header)) != sizeof(ctx->header)) {
|
||||
EPRINTF("Failed to read save header!\n");
|
||||
EPRINTF("Failed to read save header A!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!save_process_header(ctx) || (ctx->header_hash_validity == VALIDITY_INVALID)) {
|
||||
/* Try to parse Header B. */
|
||||
if (substorage_read(&ctx->base_storage, &ctx->header, sizeof(ctx->header), sizeof(ctx->header)) != sizeof(ctx->header)) {
|
||||
EPRINTF("Failed to read save header!\n");
|
||||
EPRINTF("Failed to read save header B!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -147,10 +147,13 @@ bool save_process(save_ctx_t *ctx) {
|
|||
ctx->data_remap_storage.header = &ctx->header.main_remap_header;
|
||||
ctx->meta_remap_storage.header = &ctx->header.meta_remap_header;
|
||||
|
||||
u32 data_remap_entry_size = sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count;
|
||||
u32 meta_remap_entry_size = sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count;
|
||||
|
||||
substorage_init(&ctx->data_remap_storage.base_storage, &file_storage_vt, ctx->file, ctx->header.layout.file_map_data_offset, ctx->header.layout.file_map_data_size);
|
||||
ctx->data_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count);
|
||||
uint8_t *remap_buffer = malloc(MAX(ctx->data_remap_storage.header->map_entry_count, ctx->meta_remap_storage.header->map_entry_count) * sizeof(remap_entry_t));
|
||||
if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.file_map_entry_offset, sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count) != sizeof(remap_entry_t) * ctx->data_remap_storage.header->map_entry_count) {
|
||||
uint8_t *remap_buffer = malloc(MAX(data_remap_entry_size, meta_remap_entry_size));
|
||||
if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.file_map_entry_offset, data_remap_entry_size) != data_remap_entry_size) {
|
||||
EPRINTF("Failed to read data remap table!");
|
||||
free(remap_buffer);
|
||||
return false;
|
||||
|
@ -177,7 +180,7 @@ bool save_process(save_ctx_t *ctx) {
|
|||
/* Initialize meta remap storage. */
|
||||
substorage_init(&ctx->meta_remap_storage.base_storage, &hierarchical_duplex_storage_vt, &ctx->duplex_storage, 0, ctx->duplex_storage.data_layer->_length);
|
||||
ctx->meta_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count);
|
||||
if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.meta_map_entry_offset, sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count) != sizeof(remap_entry_t) * ctx->meta_remap_storage.header->map_entry_count) {
|
||||
if (substorage_read(&ctx->base_storage, remap_buffer, ctx->header.layout.meta_map_entry_offset, meta_remap_entry_size) != meta_remap_entry_size) {
|
||||
EPRINTF("Failed to read meta remap table!");
|
||||
free(remap_buffer);
|
||||
return false;
|
||||
|
@ -225,9 +228,7 @@ bool save_process(save_ctx_t *ctx) {
|
|||
}
|
||||
|
||||
/* Initialize core save filesystem. */
|
||||
save_data_file_system_core_init(&ctx->save_filesystem_core, &ctx->core_data_ivfc_storage.base_storage, ctx->fat_storage, &ctx->header.save_header);
|
||||
|
||||
return true;
|
||||
return save_data_file_system_core_init(&ctx->save_filesystem_core, &ctx->core_data_ivfc_storage.base_storage, ctx->fat_storage, &ctx->header.save_header);
|
||||
}
|
||||
|
||||
void save_free_contexts(save_ctx_t *ctx) {
|
||||
|
@ -292,7 +293,7 @@ bool save_commit(save_ctx_t *ctx) {
|
|||
uint32_t hashed_data_offset = sizeof(ctx->header.layout) + sizeof(ctx->header.cmac) + sizeof(ctx->header._0x10);
|
||||
uint32_t hashed_data_size = sizeof(ctx->header) - hashed_data_offset;
|
||||
uint8_t *header = (uint8_t *)&ctx->header;
|
||||
se_calc_sha256(ctx->header.layout.hash, header + hashed_data_offset, hashed_data_size);
|
||||
se_calc_sha256_oneshot(ctx->header.layout.hash, header + hashed_data_offset, hashed_data_size);
|
||||
|
||||
se_aes_key_set(10, ctx->save_mac_key, 0x10);
|
||||
se_aes_cmac(10, ctx->header.cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout));
|
||||
|
|
|
@ -38,7 +38,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
void save_data_file_init(save_data_file_ctx_t *ctx, allocation_table_storage_ctx_t *base_storage, const char *path, hierarchical_save_file_table_ctx_t *file_table, uint64_t size, open_mode_t mode) {
|
||||
ctx->mode = mode;
|
||||
memcpy(&ctx->base_storage, base_storage, sizeof(ctx->base_storage));
|
||||
memcpy(&ctx->base_storage, base_storage, sizeof(allocation_table_storage_ctx_t));
|
||||
ctx->path = path;
|
||||
ctx->file_table = file_table;
|
||||
ctx->size = size;
|
||||
|
|
|
@ -41,21 +41,29 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <gfx_utils.h>
|
||||
#include <mem/heap.h>
|
||||
|
||||
static ALWAYS_INLINE void save_data_file_system_core_open_fat_storage(save_data_file_system_core_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) {
|
||||
save_allocation_table_storage_init(storage_ctx, ctx->base_storage, &ctx->allocation_table, (uint32_t)ctx->header->block_size, block_index);
|
||||
static ALWAYS_INLINE bool save_data_file_system_core_open_fat_storage(save_data_file_system_core_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) {
|
||||
return save_allocation_table_storage_init(storage_ctx, ctx->base_storage, &ctx->allocation_table, (uint32_t)ctx->header->block_size, block_index);
|
||||
}
|
||||
|
||||
void save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header) {
|
||||
bool save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header) {
|
||||
save_allocation_table_init(&ctx->allocation_table, allocation_table, &save_fs_header->fat_header);
|
||||
ctx->header = save_fs_header;
|
||||
ctx->base_storage = storage;
|
||||
|
||||
save_filesystem_list_ctx_t *dir_table = &ctx->file_table.directory_table;
|
||||
save_filesystem_list_ctx_t *file_table = &ctx->file_table.file_table;
|
||||
save_data_file_system_core_open_fat_storage(ctx, &dir_table->storage, save_fs_header->fat_header.directory_table_block);
|
||||
save_data_file_system_core_open_fat_storage(ctx, &file_table->storage, save_fs_header->fat_header.file_table_block);
|
||||
if (!save_data_file_system_core_open_fat_storage(ctx, &dir_table->storage, save_fs_header->fat_header.directory_table_block)) {
|
||||
EPRINTF("Failed to init dir table for fs core!");
|
||||
return false;
|
||||
}
|
||||
if (!save_data_file_system_core_open_fat_storage(ctx, &file_table->storage, save_fs_header->fat_header.file_table_block)) {
|
||||
EPRINTF("Failed to init file table for fs core!");
|
||||
return false;
|
||||
}
|
||||
save_fs_list_init(dir_table);
|
||||
save_fs_list_init(file_table);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool save_data_file_system_core_create_directory(save_data_file_system_core_ctx_t *ctx, const char *path) {
|
||||
|
|
|
@ -66,7 +66,7 @@ static ALWAYS_INLINE void save_data_file_system_core_get_total_space_size(save_d
|
|||
*out_total_space = ctx->header->block_size * ctx->header->block_count;
|
||||
}
|
||||
|
||||
void save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header);
|
||||
bool save_data_file_system_core_init(save_data_file_system_core_ctx_t *ctx, substorage *storage, void *allocation_table, save_fs_header_t *save_fs_header);
|
||||
|
||||
bool save_data_file_system_core_create_directory(save_data_file_system_core_ctx_t *ctx, const char *path);
|
||||
bool save_data_file_system_core_create_file(save_data_file_system_core_ctx_t *ctx, const char *path, uint64_t size);
|
||||
|
|
Loading…
Reference in New Issue