mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
romfs: use hash buckets for FS entry lookups.
* romfs: add hash bucket fields to RomFileSystemContext struct. * romfs: remove current offset fields from RomFileSystemContext struct and all functions that relied on them. * romfs: add romfsCalculateEntryHash(). * romfs: update romfsInitializeContext() to also load file/directory hash buckets. * romfs: update romfsGetTotalDataSize() to make up for the removed functions. * romfs: update romfsGetChild*EntryByName() functions to use hash bucket lookups. Other changes include: * devoptab: add missing exit macros to some FS operations across all interfaces. * poc: update extractedRomFsReadThreadFunc() to make up for the removed RomFS functions.
This commit is contained in:
parent
ef03aa4cbe
commit
364b3f39dc
6 changed files with 130 additions and 119 deletions
|
@ -4542,6 +4542,7 @@ static void extractedRomFsReadThreadFunc(void *arg)
|
||||||
|
|
||||||
RomFileSystemContext *romfs_ctx = romfs_thread_data->romfs_ctx;
|
RomFileSystemContext *romfs_ctx = romfs_thread_data->romfs_ctx;
|
||||||
RomFileSystemFileEntry *romfs_file_entry = NULL;
|
RomFileSystemFileEntry *romfs_file_entry = NULL;
|
||||||
|
u64 cur_entry_offset = 0;
|
||||||
|
|
||||||
char romfs_path[FS_MAX_PATH] = {0}, subdir[0x20] = {0}, *filename = NULL;
|
char romfs_path[FS_MAX_PATH] = {0}, subdir[0x20] = {0}, *filename = NULL;
|
||||||
size_t filename_len = 0;
|
size_t filename_len = 0;
|
||||||
|
@ -4611,11 +4612,8 @@ static void extractedRomFsReadThreadFunc(void *arg)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset current file table offset. */
|
|
||||||
romfsResetFileTableOffset(romfs_ctx);
|
|
||||||
|
|
||||||
/* Loop through all file entries. */
|
/* Loop through all file entries. */
|
||||||
while(shared_thread_data->data_written < shared_thread_data->total_size && romfsCanMoveToNextFileEntry(romfs_ctx))
|
while(shared_thread_data->data_written < shared_thread_data->total_size && cur_entry_offset < romfs_ctx->file_table_size)
|
||||||
{
|
{
|
||||||
/* Check if the transfer has been cancelled by the user. */
|
/* Check if the transfer has been cancelled by the user. */
|
||||||
if (shared_thread_data->transfer_cancelled)
|
if (shared_thread_data->transfer_cancelled)
|
||||||
|
@ -4643,7 +4641,7 @@ static void extractedRomFsReadThreadFunc(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve RomFS file entry information and generate output path. */
|
/* Retrieve RomFS file entry information and generate output path. */
|
||||||
shared_thread_data->read_error = (!(romfs_file_entry = romfsGetCurrentFileEntry(romfs_ctx)) || \
|
shared_thread_data->read_error = (!(romfs_file_entry = romfsGetFileEntryByOffset(romfs_ctx, cur_entry_offset)) || \
|
||||||
!romfsGeneratePathFromFileEntry(romfs_ctx, romfs_file_entry, romfs_path + filename_len, sizeof(romfs_path) - filename_len, romfs_illegal_char_replace_type));
|
!romfsGeneratePathFromFileEntry(romfs_ctx, romfs_file_entry, romfs_path + filename_len, sizeof(romfs_path) - filename_len, romfs_illegal_char_replace_type));
|
||||||
if (shared_thread_data->read_error)
|
if (shared_thread_data->read_error)
|
||||||
{
|
{
|
||||||
|
@ -4749,13 +4747,8 @@ static void extractedRomFsReadThreadFunc(void *arg)
|
||||||
|
|
||||||
if (shared_thread_data->read_error || shared_thread_data->write_error || shared_thread_data->transfer_cancelled) break;
|
if (shared_thread_data->read_error || shared_thread_data->write_error || shared_thread_data->transfer_cancelled) break;
|
||||||
|
|
||||||
/* Move to the next file entry. */
|
/* Get the offset for the next file entry. */
|
||||||
shared_thread_data->read_error = !romfsMoveToNextFileEntry(romfs_ctx);
|
cur_entry_offset += ALIGN_UP(sizeof(RomFileSystemFileEntry) + romfs_file_entry->name_length, ROMFS_TABLE_ENTRY_ALIGNMENT);
|
||||||
if (shared_thread_data->read_error)
|
|
||||||
{
|
|
||||||
condvarWakeAll(&g_writeCondvar);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shared_thread_data->read_error && !shared_thread_data->write_error && !shared_thread_data->transfer_cancelled)
|
if (!shared_thread_data->read_error && !shared_thread_data->write_error && !shared_thread_data->transfer_cancelled)
|
||||||
|
|
|
@ -40,12 +40,12 @@ extern "C" {
|
||||||
/// Header used by NCA0 RomFS sections.
|
/// Header used by NCA0 RomFS sections.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 header_size; ///< Header size. Must be equal to ROMFS_OLD_HEADER_SIZE.
|
u32 header_size; ///< Header size. Must be equal to ROMFS_OLD_HEADER_SIZE.
|
||||||
u32 directory_bucket_offset; ///< Directory buckets table offset.
|
u32 directory_bucket_offset; ///< Directory bucket offset.
|
||||||
u32 directory_bucket_size; ///< Directory buckets table size.
|
u32 directory_bucket_size; ///< Directory bucket size.
|
||||||
u32 directory_entry_offset; ///< Directory entries table offset.
|
u32 directory_entry_offset; ///< Directory entries table offset.
|
||||||
u32 directory_entry_size; ///< Directory entries table size.
|
u32 directory_entry_size; ///< Directory entries table size.
|
||||||
u32 file_bucket_offset; ///< File buckets table offset.
|
u32 file_bucket_offset; ///< File bucket offset.
|
||||||
u32 file_bucket_size; ///< File buckets table size.
|
u32 file_bucket_size; ///< File bucket size.
|
||||||
u32 file_entry_offset; ///< File entries table offset.
|
u32 file_entry_offset; ///< File entries table offset.
|
||||||
u32 file_entry_size; ///< File entries table size.
|
u32 file_entry_size; ///< File entries table size.
|
||||||
u32 body_offset; ///< File data body offset.
|
u32 body_offset; ///< File data body offset.
|
||||||
|
@ -56,12 +56,12 @@ NXDT_ASSERT(RomFileSystemInformationOld, ROMFS_OLD_HEADER_SIZE);
|
||||||
/// Header used by NCA2/NCA3 RomFS sections.
|
/// Header used by NCA2/NCA3 RomFS sections.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u64 header_size; ///< Header size. Must be equal to ROMFS_HEADER_SIZE.
|
u64 header_size; ///< Header size. Must be equal to ROMFS_HEADER_SIZE.
|
||||||
u64 directory_bucket_offset; ///< Directory buckets table offset.
|
u64 directory_bucket_offset; ///< Directory bucket offset.
|
||||||
u64 directory_bucket_size; ///< Directory buckets table size.
|
u64 directory_bucket_size; ///< Directory bucket size.
|
||||||
u64 directory_entry_offset; ///< Directory entries table offset.
|
u64 directory_entry_offset; ///< Directory entries table offset.
|
||||||
u64 directory_entry_size; ///< Directory entries table size.
|
u64 directory_entry_size; ///< Directory entries table size.
|
||||||
u64 file_bucket_offset; ///< File buckets table offset.
|
u64 file_bucket_offset; ///< File bucket offset.
|
||||||
u64 file_bucket_size; ///< File buckets table size.
|
u64 file_bucket_size; ///< File bucket size.
|
||||||
u64 file_entry_offset; ///< File entries table offset.
|
u64 file_entry_offset; ///< File entries table offset.
|
||||||
u64 file_entry_size; ///< File entries table size.
|
u64 file_entry_size; ///< File entries table size.
|
||||||
u64 body_offset; ///< File data body offset.
|
u64 body_offset; ///< File data body offset.
|
||||||
|
@ -115,13 +115,15 @@ typedef struct {
|
||||||
u64 offset; ///< RomFS offset (relative to the start of the NCA FS section).
|
u64 offset; ///< RomFS offset (relative to the start of the NCA FS section).
|
||||||
u64 size; ///< RomFS size.
|
u64 size; ///< RomFS size.
|
||||||
RomFileSystemHeader header; ///< RomFS header.
|
RomFileSystemHeader header; ///< RomFS header.
|
||||||
|
u64 dir_bucket_size; ///< RomFS directory bucket size.
|
||||||
|
u32 *dir_bucket; ///< RomFS directory bucket.
|
||||||
u64 dir_table_size; ///< RomFS directory entries table size.
|
u64 dir_table_size; ///< RomFS directory entries table size.
|
||||||
RomFileSystemDirectoryEntry *dir_table; ///< RomFS directory entries table.
|
RomFileSystemDirectoryEntry *dir_table; ///< RomFS directory entries table.
|
||||||
|
u64 file_bucket_size; ///< RomFS file bucket size.
|
||||||
|
u32 *file_bucket; ///< RomFS file bucket.
|
||||||
u64 file_table_size; ///< RomFS file entries table size.
|
u64 file_table_size; ///< RomFS file entries table size.
|
||||||
RomFileSystemFileEntry *file_table; ///< RomFS file entries table.
|
RomFileSystemFileEntry *file_table; ///< RomFS file entries table.
|
||||||
u64 body_offset; ///< RomFS file data body offset (relative to the start of the RomFS).
|
u64 body_offset; ///< RomFS file data body offset (relative to the start of the RomFS).
|
||||||
u64 cur_dir_offset; ///< Current RomFS directory offset (relative to the start of the directory entries table). Used for RomFS browsing.
|
|
||||||
u64 cur_file_offset; ///< Current RomFS file offset (relative to the start of the file entries table). Used for RomFS browsing.
|
|
||||||
} RomFileSystemContext;
|
} RomFileSystemContext;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -188,28 +190,19 @@ NX_INLINE void romfsFreeContext(RomFileSystemContext *ctx)
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
ncaStorageFreeContext(&(ctx->storage_ctx[0]));
|
ncaStorageFreeContext(&(ctx->storage_ctx[0]));
|
||||||
ncaStorageFreeContext(&(ctx->storage_ctx[1]));
|
ncaStorageFreeContext(&(ctx->storage_ctx[1]));
|
||||||
|
if (ctx->dir_bucket) free(ctx->dir_bucket);
|
||||||
if (ctx->dir_table) free(ctx->dir_table);
|
if (ctx->dir_table) free(ctx->dir_table);
|
||||||
|
if (ctx->file_bucket) free(ctx->file_bucket);
|
||||||
if (ctx->file_table) free(ctx->file_table);
|
if (ctx->file_table) free(ctx->file_table);
|
||||||
memset(ctx, 0, sizeof(RomFileSystemContext));
|
memset(ctx, 0, sizeof(RomFileSystemContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Functions to reset the current directory/file entry offset.
|
|
||||||
|
|
||||||
NX_INLINE void romfsResetDirectoryTableOffset(RomFileSystemContext *ctx)
|
|
||||||
{
|
|
||||||
if (ctx) ctx->cur_dir_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
NX_INLINE void romfsResetFileTableOffset(RomFileSystemContext *ctx)
|
|
||||||
{
|
|
||||||
if (ctx) ctx->cur_file_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if the provided RomFileSystemContext is valid.
|
/// Checks if the provided RomFileSystemContext is valid.
|
||||||
NX_INLINE bool romfsIsValidContext(RomFileSystemContext *ctx)
|
NX_INLINE bool romfsIsValidContext(RomFileSystemContext *ctx)
|
||||||
{
|
{
|
||||||
return (ctx && ncaStorageIsValidContext(ctx->default_storage_ctx) && ctx->size && ctx->dir_table_size && ctx->dir_table && ctx->file_table_size && ctx->file_table && \
|
return (ctx && ncaStorageIsValidContext(ctx->default_storage_ctx) && ctx->size && ctx->dir_bucket_size && ctx->dir_bucket && ctx->dir_table_size && ctx->dir_table && \
|
||||||
ctx->body_offset >= ctx->header.old_format.header_size && ctx->body_offset < ctx->size);
|
ctx->file_bucket_size && ctx->file_bucket && ctx->file_table_size && ctx->file_table && ctx->body_offset >= ctx->header.old_format.header_size && \
|
||||||
|
ctx->body_offset < ctx->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Functions to retrieve a directory/file entry.
|
/// Functions to retrieve a directory/file entry.
|
||||||
|
@ -225,60 +218,11 @@ NX_INLINE RomFileSystemDirectoryEntry *romfsGetDirectoryEntryByOffset(RomFileSys
|
||||||
return (ctx ? (RomFileSystemDirectoryEntry*)romfsGetEntryByOffset(ctx, ctx->dir_table, ctx->dir_table_size, sizeof(RomFileSystemDirectoryEntry), dir_entry_offset) : NULL);
|
return (ctx ? (RomFileSystemDirectoryEntry*)romfsGetEntryByOffset(ctx, ctx->dir_table, ctx->dir_table_size, sizeof(RomFileSystemDirectoryEntry), dir_entry_offset) : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE RomFileSystemDirectoryEntry *romfsGetCurrentDirectoryEntry(RomFileSystemContext *ctx)
|
|
||||||
{
|
|
||||||
return (ctx ? romfsGetDirectoryEntryByOffset(ctx, ctx->cur_dir_offset) : NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
NX_INLINE RomFileSystemFileEntry *romfsGetFileEntryByOffset(RomFileSystemContext *ctx, u64 file_entry_offset)
|
NX_INLINE RomFileSystemFileEntry *romfsGetFileEntryByOffset(RomFileSystemContext *ctx, u64 file_entry_offset)
|
||||||
{
|
{
|
||||||
return (ctx ? (RomFileSystemFileEntry*)romfsGetEntryByOffset(ctx, ctx->file_table, ctx->file_table_size, sizeof(RomFileSystemFileEntry), file_entry_offset) : NULL);
|
return (ctx ? (RomFileSystemFileEntry*)romfsGetEntryByOffset(ctx, ctx->file_table, ctx->file_table_size, sizeof(RomFileSystemFileEntry), file_entry_offset) : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE RomFileSystemFileEntry *romfsGetCurrentFileEntry(RomFileSystemContext *ctx)
|
|
||||||
{
|
|
||||||
return (ctx ? romfsGetFileEntryByOffset(ctx, ctx->cur_file_offset) : NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Functions to check if it's possible to move to the next directory/file entry based on the current directory/file entry offset.
|
|
||||||
|
|
||||||
NX_INLINE bool romfsCanMoveToNextEntry(RomFileSystemContext *ctx, void *entry_table, u64 entry_table_size, u64 entry_size, u64 entry_offset)
|
|
||||||
{
|
|
||||||
if (!romfsIsValidContext(ctx) || !entry_table || !entry_table_size || entry_size < 4 || (entry_offset + entry_size) > entry_table_size) return false;
|
|
||||||
u32 name_length = *((u32*)((u8*)entry_table + entry_offset + entry_size - 4));
|
|
||||||
return ((entry_offset + ALIGN_UP(entry_size + name_length, ROMFS_TABLE_ENTRY_ALIGNMENT)) <= entry_table_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
NX_INLINE bool romfsCanMoveToNextDirectoryEntry(RomFileSystemContext *ctx)
|
|
||||||
{
|
|
||||||
return (ctx ? romfsCanMoveToNextEntry(ctx, ctx->dir_table, ctx->dir_table_size, sizeof(RomFileSystemDirectoryEntry), ctx->cur_dir_offset) : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
NX_INLINE bool romfsCanMoveToNextFileEntry(RomFileSystemContext *ctx)
|
|
||||||
{
|
|
||||||
return (ctx ? romfsCanMoveToNextEntry(ctx, ctx->file_table, ctx->file_table_size, sizeof(RomFileSystemFileEntry), ctx->cur_file_offset) : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Functions to update the current directory/file entry offset to make it point to the next directory/file entry.
|
|
||||||
|
|
||||||
NX_INLINE bool romfsMoveToNextEntry(RomFileSystemContext *ctx, void *entry_table, u64 entry_table_size, u64 entry_size, u64 *entry_offset)
|
|
||||||
{
|
|
||||||
if (!romfsIsValidContext(ctx) || !entry_table || !entry_table_size || entry_size < 4 || !entry_offset || (*entry_offset + entry_size) > entry_table_size) return false;
|
|
||||||
u32 name_length = *((u32*)((u8*)entry_table + *entry_offset + entry_size - 4));
|
|
||||||
*entry_offset += ALIGN_UP(entry_size + name_length, ROMFS_TABLE_ENTRY_ALIGNMENT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
NX_INLINE bool romfsMoveToNextDirectoryEntry(RomFileSystemContext *ctx)
|
|
||||||
{
|
|
||||||
return (ctx ? romfsMoveToNextEntry(ctx, ctx->dir_table, ctx->dir_table_size, sizeof(RomFileSystemDirectoryEntry), &(ctx->cur_dir_offset)) : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
NX_INLINE bool romfsMoveToNextFileEntry(RomFileSystemContext *ctx)
|
|
||||||
{
|
|
||||||
return (ctx ? romfsMoveToNextEntry(ctx, ctx->file_table, ctx->file_table_size, sizeof(RomFileSystemFileEntry), &(ctx->cur_file_offset)) : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// NCA patch management functions.
|
/// NCA patch management functions.
|
||||||
|
|
||||||
NX_INLINE void romfsWriteFileEntryPatchToMemoryBuffer(RomFileSystemContext *ctx, RomFileSystemFileEntryPatch *patch, void *buf, u64 buf_size, u64 buf_offset)
|
NX_INLINE void romfsWriteFileEntryPatchToMemoryBuffer(RomFileSystemContext *ctx, RomFileSystemFileEntryPatch *patch, void *buf, u64 buf_size, u64 buf_offset)
|
||||||
|
|
|
@ -22,14 +22,21 @@
|
||||||
#include "nxdt_utils.h"
|
#include "nxdt_utils.h"
|
||||||
#include "romfs.h"
|
#include "romfs.h"
|
||||||
|
|
||||||
|
/* Helper macros. */
|
||||||
|
|
||||||
|
#define ROMFS_ENTRY_OFFSET(entry, table) (u32)((uintptr_t)entry - (uintptr_t)table)
|
||||||
|
|
||||||
/* Function prototypes. */
|
/* Function prototypes. */
|
||||||
|
|
||||||
static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name);
|
static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name);
|
||||||
static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name);
|
static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name);
|
||||||
|
|
||||||
|
static u32 romfsCalculateEntryHash(RomFileSystemContext *ctx, u32 parent_offset, const char *name, size_t name_len, bool is_file);
|
||||||
|
|
||||||
bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base_nca_fs_ctx, NcaFsSectionContext *patch_nca_fs_ctx)
|
bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base_nca_fs_ctx, NcaFsSectionContext *patch_nca_fs_ctx)
|
||||||
{
|
{
|
||||||
u64 dir_table_offset = 0, file_table_offset = 0;
|
u64 dir_bucket_offset = 0, dir_table_offset = 0;
|
||||||
|
u64 file_bucket_offset = 0, file_table_offset = 0;
|
||||||
NcaContext *base_nca_ctx = NULL, *patch_nca_ctx = NULL;
|
NcaContext *base_nca_ctx = NULL, *patch_nca_ctx = NULL;
|
||||||
bool dump_fs_header = false, success = false;
|
bool dump_fs_header = false, success = false;
|
||||||
|
|
||||||
|
@ -102,6 +109,30 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read directory bucket. */
|
||||||
|
dir_bucket_offset = (is_nca0_romfs ? (u64)out->header.old_format.directory_bucket_offset : out->header.cur_format.directory_bucket_offset);
|
||||||
|
out->dir_bucket_size = (is_nca0_romfs ? (u64)out->header.old_format.directory_bucket_size : out->header.cur_format.directory_bucket_size);
|
||||||
|
|
||||||
|
if (!out->dir_bucket_size || (dir_bucket_offset + out->dir_bucket_size) > out->size)
|
||||||
|
{
|
||||||
|
LOG_MSG_ERROR("Invalid RomFS directory bucket!");
|
||||||
|
dump_fs_header = true;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->dir_bucket = malloc(out->dir_bucket_size);
|
||||||
|
if (!out->dir_bucket)
|
||||||
|
{
|
||||||
|
LOG_MSG_ERROR("Unable to allocate memory for RomFS directory bucket!");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ncaStorageRead(out->default_storage_ctx, out->dir_bucket, out->dir_bucket_size, out->offset + dir_bucket_offset))
|
||||||
|
{
|
||||||
|
LOG_MSG_ERROR("Failed to read RomFS directory bucket!");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read directory entries table. */
|
/* Read directory entries table. */
|
||||||
dir_table_offset = (is_nca0_romfs ? (u64)out->header.old_format.directory_entry_offset : out->header.cur_format.directory_entry_offset);
|
dir_table_offset = (is_nca0_romfs ? (u64)out->header.old_format.directory_entry_offset : out->header.cur_format.directory_entry_offset);
|
||||||
out->dir_table_size = (is_nca0_romfs ? (u64)out->header.old_format.directory_entry_size : out->header.cur_format.directory_entry_size);
|
out->dir_table_size = (is_nca0_romfs ? (u64)out->header.old_format.directory_entry_size : out->header.cur_format.directory_entry_size);
|
||||||
|
@ -126,6 +157,30 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read file bucket. */
|
||||||
|
file_bucket_offset = (is_nca0_romfs ? (u64)out->header.old_format.file_bucket_offset : out->header.cur_format.file_bucket_offset);
|
||||||
|
out->file_bucket_size = (is_nca0_romfs ? (u64)out->header.old_format.file_bucket_size : out->header.cur_format.file_bucket_size);
|
||||||
|
|
||||||
|
if (!out->file_bucket_size || (file_bucket_offset + out->file_bucket_size) > out->size)
|
||||||
|
{
|
||||||
|
LOG_MSG_ERROR("Invalid RomFS file bucket!");
|
||||||
|
dump_fs_header = true;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->file_bucket = malloc(out->file_bucket_size);
|
||||||
|
if (!out->file_bucket)
|
||||||
|
{
|
||||||
|
LOG_MSG_ERROR("Unable to allocate memory for RomFS file bucket!");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ncaStorageRead(out->default_storage_ctx, out->file_bucket, out->file_bucket_size, out->offset + file_bucket_offset))
|
||||||
|
{
|
||||||
|
LOG_MSG_ERROR("Failed to read RomFS file bucket!");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read file entries table. */
|
/* Read file entries table. */
|
||||||
file_table_offset = (is_nca0_romfs ? (u64)out->header.old_format.file_entry_offset : out->header.cur_format.file_entry_offset);
|
file_table_offset = (is_nca0_romfs ? (u64)out->header.old_format.file_entry_offset : out->header.cur_format.file_entry_offset);
|
||||||
out->file_table_size = (is_nca0_romfs ? (u64)out->header.old_format.file_entry_size : out->header.cur_format.file_entry_size);
|
out->file_table_size = (is_nca0_romfs ? (u64)out->header.old_format.file_entry_size : out->header.cur_format.file_entry_size);
|
||||||
|
@ -219,39 +274,32 @@ bool romfsGetTotalDataSize(RomFileSystemContext *ctx, bool only_updated, u64 *ou
|
||||||
}
|
}
|
||||||
|
|
||||||
RomFileSystemFileEntry *file_entry = NULL;
|
RomFileSystemFileEntry *file_entry = NULL;
|
||||||
u64 total_size = 0;
|
u64 total_size = 0, cur_entry_offset = 0;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
/* Reset current file table offset. */
|
|
||||||
romfsResetFileTableOffset(ctx);
|
|
||||||
|
|
||||||
/* Loop through all file entries. */
|
/* Loop through all file entries. */
|
||||||
while(romfsCanMoveToNextFileEntry(ctx))
|
while(cur_entry_offset < ctx->file_table_size)
|
||||||
{
|
{
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
|
|
||||||
/* Get current file entry. */
|
/* Get current file entry. */
|
||||||
if (!(file_entry = romfsGetCurrentFileEntry(ctx)))
|
if (!(file_entry = romfsGetFileEntryByOffset(ctx, cur_entry_offset)))
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Failed to retrieve current file entry! (0x%lX, 0x%lX).", ctx->cur_file_offset, ctx->file_table_size);
|
LOG_MSG_ERROR("Failed to retrieve current file entry! (0x%lX, 0x%lX).", cur_entry_offset, ctx->file_table_size);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update total data size, taking into account the only_updated flag. */
|
/* Update total data size, taking into account the only_updated flag. */
|
||||||
if (only_updated && !romfsIsFileEntryUpdated(ctx, file_entry, &updated))
|
if (only_updated && !romfsIsFileEntryUpdated(ctx, file_entry, &updated))
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Failed to determine if file entry is updated or not! (0x%lX, 0x%lX).", ctx->cur_file_offset, ctx->file_table_size);
|
LOG_MSG_ERROR("Failed to determine if file entry is updated or not! (0x%lX, 0x%lX).", cur_entry_offset, ctx->file_table_size);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!only_updated || (only_updated && updated)) total_size += file_entry->size;
|
if (!only_updated || (only_updated && updated)) total_size += file_entry->size;
|
||||||
|
|
||||||
/* Move to the next file entry. */
|
/* Get the offset for the next file entry. */
|
||||||
if (!romfsMoveToNextFileEntry(ctx))
|
cur_entry_offset += ALIGN_UP(sizeof(RomFileSystemFileEntry) + file_entry->name_length, ROMFS_TABLE_ENTRY_ALIGNMENT);
|
||||||
{
|
|
||||||
LOG_MSG_ERROR("Failed to move to the next file entry! (0x%lX, 0x%lX).", ctx->cur_file_offset, ctx->file_table_size);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update output values. */
|
/* Update output values. */
|
||||||
|
@ -259,9 +307,6 @@ bool romfsGetTotalDataSize(RomFileSystemContext *ctx, bool only_updated, u64 *ou
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
/* Reset current file table offset. */
|
|
||||||
romfsResetFileTableOffset(ctx);
|
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,33 +712,42 @@ bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEnt
|
||||||
|
|
||||||
static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name)
|
static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name)
|
||||||
{
|
{
|
||||||
u64 dir_offset = 0;
|
|
||||||
size_t name_len = 0;
|
size_t name_len = 0;
|
||||||
RomFileSystemDirectoryEntry *child_dir_entry = NULL;
|
RomFileSystemDirectoryEntry *child_dir_entry = NULL;
|
||||||
|
u32 hash = 0, parent_offset = 0, dir_offset = 0;
|
||||||
|
|
||||||
if (!dir_entry || (dir_offset = dir_entry->directory_offset) == ROMFS_VOID_ENTRY || !name || !(name_len = strlen(name)))
|
if (!dir_entry || !name || !(name_len = strlen(name)))
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Invalid parameters!");
|
LOG_MSG_ERROR("Invalid parameters!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through the child directory entries' linked list. */
|
/* Calculate hash for the child directory entry. */
|
||||||
|
parent_offset = ROMFS_ENTRY_OFFSET(dir_entry, ctx->dir_table);
|
||||||
|
hash = romfsCalculateEntryHash(ctx, parent_offset, name, name_len, false);
|
||||||
|
|
||||||
|
//LOG_MSG_DEBUG("parent_offset: 0x%X, parent_name: \"%.*s\", name: \"%s\", hash: 0x%X", parent_offset, (int)dir_entry->name_length, dir_entry->name, name, hash);
|
||||||
|
|
||||||
|
/* Perform lookup using the directory bucket. */
|
||||||
|
dir_offset = ctx->dir_bucket[hash];
|
||||||
while(dir_offset != ROMFS_VOID_ENTRY)
|
while(dir_offset != ROMFS_VOID_ENTRY)
|
||||||
{
|
{
|
||||||
/* Get current directory entry. */
|
/* Get current directory entry. */
|
||||||
if (!(child_dir_entry = romfsGetDirectoryEntryByOffset(ctx, dir_offset)))
|
if (!(child_dir_entry = romfsGetDirectoryEntryByOffset(ctx, dir_offset)))
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Failed to retrieve directory entry! (0x%lX, 0x%lX).", dir_offset, ctx->dir_table_size);
|
LOG_MSG_ERROR("Failed to retrieve directory entry! (0x%X, 0x%lX).", dir_offset, ctx->dir_table_size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//LOG_MSG_DEBUG("offset: 0x%X, parent: 0x%X, name: \"%.*s\"", dir_offset, child_dir_entry->parent_offset, (int)child_dir_entry->name_length, child_dir_entry->name);
|
||||||
|
|
||||||
/* Check if we found the right child directory entry. */
|
/* Check if we found the right child directory entry. */
|
||||||
/* strncmp() is used here instead of strcmp() because names stored in RomFS sections are not always NULL terminated. */
|
/* strncmp() is used here instead of strcmp() because names stored in RomFS sections are not always NULL terminated. */
|
||||||
/* If the name ends at a 4-byte boundary, the next entry starts immediately. */
|
/* If the name ends at a 4-byte boundary, the next entry starts immediately. */
|
||||||
if (child_dir_entry->name_length == name_len && !strncmp(child_dir_entry->name, name, name_len)) return child_dir_entry;
|
if (child_dir_entry->parent_offset == parent_offset && child_dir_entry->name_length == name_len && !strncmp(child_dir_entry->name, name, name_len)) return child_dir_entry;
|
||||||
|
|
||||||
/* Update current directory entry offset. */
|
/* Update current directory entry offset. */
|
||||||
dir_offset = child_dir_entry->next_offset;
|
dir_offset = child_dir_entry->bucket_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -701,33 +755,53 @@ static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSys
|
||||||
|
|
||||||
static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name)
|
static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name)
|
||||||
{
|
{
|
||||||
u64 file_offset = 0;
|
|
||||||
size_t name_len = 0;
|
size_t name_len = 0;
|
||||||
RomFileSystemFileEntry *child_file_entry = NULL;
|
RomFileSystemFileEntry *child_file_entry = NULL;
|
||||||
|
u32 hash = 0, parent_offset = 0, file_offset = 0;
|
||||||
|
|
||||||
if (!dir_entry || (file_offset = dir_entry->file_offset) == ROMFS_VOID_ENTRY || !name || !(name_len = strlen(name)))
|
if (!dir_entry || !name || !(name_len = strlen(name)))
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Invalid parameters!");
|
LOG_MSG_ERROR("Invalid parameters!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through the child file entries' linked list. */
|
/* Calculate hash for the child file entry. */
|
||||||
|
parent_offset = ROMFS_ENTRY_OFFSET(dir_entry, ctx->dir_table);
|
||||||
|
hash = romfsCalculateEntryHash(ctx, parent_offset, name, name_len, true);
|
||||||
|
|
||||||
|
//LOG_MSG_DEBUG("parent_offset: 0x%X, parent_name: \"%.*s\", name: \"%s\", hash: 0x%X", parent_offset, (int)dir_entry->name_length, dir_entry->name, name, hash);
|
||||||
|
|
||||||
|
/* Perform lookup using the file bucket. */
|
||||||
|
file_offset = ctx->file_bucket[hash];
|
||||||
while(file_offset != ROMFS_VOID_ENTRY)
|
while(file_offset != ROMFS_VOID_ENTRY)
|
||||||
{
|
{
|
||||||
/* Get current file entry. */
|
/* Get current file entry. */
|
||||||
if (!(child_file_entry = romfsGetFileEntryByOffset(ctx, file_offset)))
|
if (!(child_file_entry = romfsGetFileEntryByOffset(ctx, file_offset)))
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Failed to retrieve file entry! (0x%lX, 0x%lX).", file_offset, ctx->file_table_size);
|
LOG_MSG_ERROR("Failed to retrieve file entry! (0x%X, 0x%lX).", file_offset, ctx->file_table_size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//LOG_MSG_DEBUG("offset: 0x%X, parent: 0x%X, name: \"%.*s\"", file_offset, child_file_entry->parent_offset, (int)child_file_entry->name_length, child_file_entry->name);
|
||||||
|
|
||||||
/* Check if we found the right child file entry. */
|
/* Check if we found the right child file entry. */
|
||||||
/* strncmp() is used here instead of strcmp() because names stored in RomFS sections are not always NULL terminated. */
|
/* strncmp() is used here instead of strcmp() because names stored in RomFS sections are not always NULL terminated. */
|
||||||
/* If the name ends at a 4-byte boundary, the next entry starts immediately. */
|
/* If the name ends at a 4-byte boundary, the next entry starts immediately. */
|
||||||
if (child_file_entry->name_length == name_len && !strncmp(child_file_entry->name, name, name_len)) return child_file_entry;
|
if (child_file_entry->parent_offset == parent_offset && child_file_entry->name_length == name_len && !strncmp(child_file_entry->name, name, name_len)) return child_file_entry;
|
||||||
|
|
||||||
file_offset = child_file_entry->next_offset;
|
/* Update current file entry offset. */
|
||||||
|
file_offset = child_file_entry->bucket_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 romfsCalculateEntryHash(RomFileSystemContext *ctx, u32 parent_offset, const char *name, size_t name_len, bool is_file)
|
||||||
|
{
|
||||||
|
u32 hash = (parent_offset ^ 123456789);
|
||||||
|
u32 total = ((u32)(is_file ? ctx->file_bucket_size : ctx->dir_bucket_size) / sizeof(u32));
|
||||||
|
|
||||||
|
for(size_t i = 0; i < name_len; i++) hash = (((hash >> 5) | (hash << 27)) ^ name[i]);
|
||||||
|
|
||||||
|
return (hash % total);
|
||||||
|
}
|
||||||
|
|
|
@ -248,7 +248,7 @@ static int hfsdev_stat(struct _reent *r, const char *file, struct stat *st)
|
||||||
LOG_MSG_DEBUG("Getting file stats for \"%s:/%s\".", dev_ctx->name, file);
|
LOG_MSG_DEBUG("Getting file stats for \"%s:/%s\".", dev_ctx->name, file);
|
||||||
|
|
||||||
/* Get information about the requested Hash FS entry. */
|
/* Get information about the requested Hash FS entry. */
|
||||||
if (!hfsGetEntryIndexByName(fs_ctx, file, &index) || !(hfs_entry = hfsGetEntryByIndex(fs_ctx, index))) DEVOPTAB_SET_ERROR(ENOENT);
|
if (!hfsGetEntryIndexByName(fs_ctx, file, &index) || !(hfs_entry = hfsGetEntryByIndex(fs_ctx, index))) DEVOPTAB_SET_ERROR_AND_EXIT(ENOENT);
|
||||||
|
|
||||||
/* Fill stat info. */
|
/* Fill stat info. */
|
||||||
hfsdev_fill_stat(st, index, hfs_entry, dev_ctx->mount_time);
|
hfsdev_fill_stat(st, index, hfs_entry, dev_ctx->mount_time);
|
||||||
|
|
|
@ -254,7 +254,7 @@ static int romfsdev_stat(struct _reent *r, const char *file, struct stat *st)
|
||||||
LOG_MSG_DEBUG("Getting file stats for \"%s:%s\".", dev_ctx->name, file);
|
LOG_MSG_DEBUG("Getting file stats for \"%s:%s\".", dev_ctx->name, file);
|
||||||
|
|
||||||
/* Get information about the requested RomFS file entry. */
|
/* Get information about the requested RomFS file entry. */
|
||||||
if (!(file_entry = romfsGetFileEntryByPath(fs_ctx, file))) DEVOPTAB_SET_ERROR(ENOENT);
|
if (!(file_entry = romfsGetFileEntryByPath(fs_ctx, file))) DEVOPTAB_SET_ERROR_AND_EXIT(ENOENT);
|
||||||
|
|
||||||
/* Fill stat info. */
|
/* Fill stat info. */
|
||||||
romfsdev_fill_file_stat(st, fs_ctx, file_entry, dev_ctx->mount_time);
|
romfsdev_fill_file_stat(st, fs_ctx, file_entry, dev_ctx->mount_time);
|
||||||
|
@ -280,7 +280,7 @@ static DIR_ITER *romfsdev_diropen(struct _reent *r, DIR_ITER *dirState, const ch
|
||||||
memset(dir, 0, sizeof(RomFileSystemDirectoryState));
|
memset(dir, 0, sizeof(RomFileSystemDirectoryState));
|
||||||
|
|
||||||
/* Get information about the requested RomFS directory entry. */
|
/* Get information about the requested RomFS directory entry. */
|
||||||
if (!(dir->dir_entry = romfsGetDirectoryEntryByPath(fs_ctx, path))) DEVOPTAB_SET_ERROR(ENOENT);
|
if (!(dir->dir_entry = romfsGetDirectoryEntryByPath(fs_ctx, path))) DEVOPTAB_SET_ERROR_AND_EXIT(ENOENT);
|
||||||
|
|
||||||
dir->cur_dir_offset = dir->dir_entry->directory_offset;
|
dir->cur_dir_offset = dir->dir_entry->directory_offset;
|
||||||
dir->cur_file_offset = dir->dir_entry->file_offset;
|
dir->cur_file_offset = dir->dir_entry->file_offset;
|
||||||
|
|
|
@ -248,7 +248,7 @@ static int pfsdev_stat(struct _reent *r, const char *file, struct stat *st)
|
||||||
LOG_MSG_DEBUG("Getting file stats for \"%s:/%s\".", dev_ctx->name, file);
|
LOG_MSG_DEBUG("Getting file stats for \"%s:/%s\".", dev_ctx->name, file);
|
||||||
|
|
||||||
/* Get information about the requested Partition FS entry. */
|
/* Get information about the requested Partition FS entry. */
|
||||||
if (!pfsGetEntryIndexByName(fs_ctx, file, &index) || !(pfs_entry = pfsGetEntryByIndex(fs_ctx, index))) DEVOPTAB_SET_ERROR(ENOENT);
|
if (!pfsGetEntryIndexByName(fs_ctx, file, &index) || !(pfs_entry = pfsGetEntryByIndex(fs_ctx, index))) DEVOPTAB_SET_ERROR_AND_EXIT(ENOENT);
|
||||||
|
|
||||||
/* Fill stat info. */
|
/* Fill stat info. */
|
||||||
pfsdev_fill_stat(st, index, pfs_entry, dev_ctx->mount_time);
|
pfsdev_fill_stat(st, index, pfs_entry, dev_ctx->mount_time);
|
||||||
|
|
Loading…
Reference in a new issue