From 364b3f39dcd4d770e1c5df334e31df39fa02ce5a Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Fri, 22 Dec 2023 12:20:27 +0100 Subject: [PATCH] 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. --- code_templates/nxdt_rw_poc.c | 17 ++-- include/core/romfs.h | 90 ++++----------------- source/core/romfs.c | 134 ++++++++++++++++++++++++------- source/devoptab/hfs_dev.c | 2 +- source/devoptab/nxdt_romfs_dev.c | 4 +- source/devoptab/pfs_dev.c | 2 +- 6 files changed, 130 insertions(+), 119 deletions(-) diff --git a/code_templates/nxdt_rw_poc.c b/code_templates/nxdt_rw_poc.c index 79dfdee..fe39cbd 100644 --- a/code_templates/nxdt_rw_poc.c +++ b/code_templates/nxdt_rw_poc.c @@ -4542,6 +4542,7 @@ static void extractedRomFsReadThreadFunc(void *arg) RomFileSystemContext *romfs_ctx = romfs_thread_data->romfs_ctx; RomFileSystemFileEntry *romfs_file_entry = NULL; + u64 cur_entry_offset = 0; char romfs_path[FS_MAX_PATH] = {0}, subdir[0x20] = {0}, *filename = NULL; size_t filename_len = 0; @@ -4611,11 +4612,8 @@ static void extractedRomFsReadThreadFunc(void *arg) goto end; } - /* Reset current file table offset. */ - romfsResetFileTableOffset(romfs_ctx); - /* 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. */ if (shared_thread_data->transfer_cancelled) @@ -4643,7 +4641,7 @@ static void extractedRomFsReadThreadFunc(void *arg) } /* 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)); 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; - /* Move to the next file entry. */ - shared_thread_data->read_error = !romfsMoveToNextFileEntry(romfs_ctx); - if (shared_thread_data->read_error) - { - condvarWakeAll(&g_writeCondvar); - break; - } + /* Get the offset for the next file entry. */ + cur_entry_offset += ALIGN_UP(sizeof(RomFileSystemFileEntry) + romfs_file_entry->name_length, ROMFS_TABLE_ENTRY_ALIGNMENT); } if (!shared_thread_data->read_error && !shared_thread_data->write_error && !shared_thread_data->transfer_cancelled) diff --git a/include/core/romfs.h b/include/core/romfs.h index 9500c16..29768af 100644 --- a/include/core/romfs.h +++ b/include/core/romfs.h @@ -40,12 +40,12 @@ extern "C" { /// Header used by NCA0 RomFS sections. typedef struct { u32 header_size; ///< Header size. Must be equal to ROMFS_OLD_HEADER_SIZE. - u32 directory_bucket_offset; ///< Directory buckets table offset. - u32 directory_bucket_size; ///< Directory buckets table size. + u32 directory_bucket_offset; ///< Directory bucket offset. + u32 directory_bucket_size; ///< Directory bucket size. u32 directory_entry_offset; ///< Directory entries table offset. u32 directory_entry_size; ///< Directory entries table size. - u32 file_bucket_offset; ///< File buckets table offset. - u32 file_bucket_size; ///< File buckets table size. + u32 file_bucket_offset; ///< File bucket offset. + u32 file_bucket_size; ///< File bucket size. u32 file_entry_offset; ///< File entries table offset. u32 file_entry_size; ///< File entries table size. 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. typedef struct { u64 header_size; ///< Header size. Must be equal to ROMFS_HEADER_SIZE. - u64 directory_bucket_offset; ///< Directory buckets table offset. - u64 directory_bucket_size; ///< Directory buckets table size. + u64 directory_bucket_offset; ///< Directory bucket offset. + u64 directory_bucket_size; ///< Directory bucket size. u64 directory_entry_offset; ///< Directory entries table offset. u64 directory_entry_size; ///< Directory entries table size. - u64 file_bucket_offset; ///< File buckets table offset. - u64 file_bucket_size; ///< File buckets table size. + u64 file_bucket_offset; ///< File bucket offset. + u64 file_bucket_size; ///< File bucket size. u64 file_entry_offset; ///< File entries table offset. u64 file_entry_size; ///< File entries table size. 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 size; ///< RomFS size. 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. 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. RomFileSystemFileEntry *file_table; ///< RomFS file entries table. 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; typedef struct { @@ -188,28 +190,19 @@ NX_INLINE void romfsFreeContext(RomFileSystemContext *ctx) if (!ctx) return; ncaStorageFreeContext(&(ctx->storage_ctx[0])); ncaStorageFreeContext(&(ctx->storage_ctx[1])); + if (ctx->dir_bucket) free(ctx->dir_bucket); if (ctx->dir_table) free(ctx->dir_table); + if (ctx->file_bucket) free(ctx->file_bucket); if (ctx->file_table) free(ctx->file_table); 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. 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 && \ - ctx->body_offset >= ctx->header.old_format.header_size && ctx->body_offset < ctx->size); + return (ctx && ncaStorageIsValidContext(ctx->default_storage_ctx) && ctx->size && ctx->dir_bucket_size && ctx->dir_bucket && ctx->dir_table_size && ctx->dir_table && \ + 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. @@ -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); } -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) { 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. NX_INLINE void romfsWriteFileEntryPatchToMemoryBuffer(RomFileSystemContext *ctx, RomFileSystemFileEntryPatch *patch, void *buf, u64 buf_size, u64 buf_offset) diff --git a/source/core/romfs.c b/source/core/romfs.c index 54193d4..21f8d18 100644 --- a/source/core/romfs.c +++ b/source/core/romfs.c @@ -22,14 +22,21 @@ #include "nxdt_utils.h" #include "romfs.h" +/* Helper macros. */ + +#define ROMFS_ENTRY_OFFSET(entry, table) (u32)((uintptr_t)entry - (uintptr_t)table) + /* Function prototypes. */ static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(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) { - 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; bool dump_fs_header = false, success = false; @@ -102,6 +109,30 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base 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. */ 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); @@ -126,6 +157,30 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base 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. */ 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); @@ -219,39 +274,32 @@ bool romfsGetTotalDataSize(RomFileSystemContext *ctx, bool only_updated, u64 *ou } RomFileSystemFileEntry *file_entry = NULL; - u64 total_size = 0; + u64 total_size = 0, cur_entry_offset = 0; bool success = false; - /* Reset current file table offset. */ - romfsResetFileTableOffset(ctx); - /* Loop through all file entries. */ - while(romfsCanMoveToNextFileEntry(ctx)) + while(cur_entry_offset < ctx->file_table_size) { bool updated = false; /* 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; } /* Update total data size, taking into account the only_updated flag. */ 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; } if (!only_updated || (only_updated && updated)) total_size += file_entry->size; - /* Move to the next file entry. */ - if (!romfsMoveToNextFileEntry(ctx)) - { - 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; - } + /* Get the offset for the next file entry. */ + cur_entry_offset += ALIGN_UP(sizeof(RomFileSystemFileEntry) + file_entry->name_length, ROMFS_TABLE_ENTRY_ALIGNMENT); } /* Update output values. */ @@ -259,9 +307,6 @@ bool romfsGetTotalDataSize(RomFileSystemContext *ctx, bool only_updated, u64 *ou success = true; end: - /* Reset current file table offset. */ - romfsResetFileTableOffset(ctx); - return success; } @@ -667,33 +712,42 @@ bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEnt static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name) { - u64 dir_offset = 0; size_t name_len = 0; 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!"); 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) { /* Get current directory entry. */ 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; } + //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. */ /* 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 (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. */ - dir_offset = child_dir_entry->next_offset; + dir_offset = child_dir_entry->bucket_offset; } return NULL; @@ -701,33 +755,53 @@ static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSys static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name) { - u64 file_offset = 0; size_t name_len = 0; 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!"); 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) { /* Get current file entry. */ 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; } + //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. */ /* 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 (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; } + +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); +} diff --git a/source/devoptab/hfs_dev.c b/source/devoptab/hfs_dev.c index 3bd4a28..ae031d8 100644 --- a/source/devoptab/hfs_dev.c +++ b/source/devoptab/hfs_dev.c @@ -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); /* 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. */ hfsdev_fill_stat(st, index, hfs_entry, dev_ctx->mount_time); diff --git a/source/devoptab/nxdt_romfs_dev.c b/source/devoptab/nxdt_romfs_dev.c index 5c5a0a9..686cf4f 100644 --- a/source/devoptab/nxdt_romfs_dev.c +++ b/source/devoptab/nxdt_romfs_dev.c @@ -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); /* 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. */ 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)); /* 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_file_offset = dir->dir_entry->file_offset; diff --git a/source/devoptab/pfs_dev.c b/source/devoptab/pfs_dev.c index 1de6d6b..751cda8 100644 --- a/source/devoptab/pfs_dev.c +++ b/source/devoptab/pfs_dev.c @@ -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); /* 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. */ pfsdev_fill_stat(st, index, pfs_entry, dev_ctx->mount_time);