mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-26 12:12:02 +00:00
RomFS (almost) done.
Need to test read functions.
This commit is contained in:
parent
bc93001525
commit
efe76093e4
6 changed files with 444 additions and 70 deletions
15
README.md
15
README.md
|
@ -2,15 +2,14 @@
|
||||||
|
|
||||||
hfs0: filelist generation methods
|
hfs0: filelist generation methods
|
||||||
|
|
||||||
nca: more data replacement methods ???
|
nca: continue reencryption methods
|
||||||
|
|
||||||
pfs0: filelist generation methods
|
pfs0: filelist generation methods
|
||||||
pfs0: full header aligned to 0x20 (nsp)
|
pfs0: full header aligned to 0x20 (nsp)
|
||||||
|
|
||||||
romfs: filelist generation methods
|
romfs: test read functions
|
||||||
romfs: data replacement methods
|
romfs: data replacement methods
|
||||||
|
romfs: filelist generation methods
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,6 +99,14 @@ If you like my work and you'd like to support me in any way, it's not necessary,
|
||||||
Changelog
|
Changelog
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
**v1.1.10:**
|
||||||
|
|
||||||
|
* Built using libnx v3.1.0.
|
||||||
|
* Updated save.c/h to reflect changes made by shchmue in Lockpick_RCM. Fixes crashes under HOS 10.0.0.
|
||||||
|
* Fixed a nasty stack corruption issue caused by improper handling of FatFs objects. Fixes ES savefile mounting errors throughout the application (e.g. batch mode, ticket dumping).
|
||||||
|
|
||||||
|
This is only a bugfix release. I don't expect to release any new versions until the rewrite is finished - the only exception being fixing some kind of feature-breaking bug. Please understand.
|
||||||
|
|
||||||
**v1.1.9:**
|
**v1.1.9:**
|
||||||
|
|
||||||
* Built using libnx commit d7e6207.
|
* Built using libnx commit d7e6207.
|
||||||
|
|
|
@ -92,7 +92,10 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
char romfs_path[FS_MAX_PATH] = {0};
|
||||||
u64 romfs_size = 0;
|
u64 romfs_size = 0;
|
||||||
|
RomFileSystemDirectoryEntry *romfs_dir_entry = NULL;
|
||||||
|
RomFileSystemFileEntry *romfs_file_entry = NULL;
|
||||||
RomFileSystemContext romfs_ctx = {0};
|
RomFileSystemContext romfs_ctx = {0};
|
||||||
|
|
||||||
buf = malloc(0x400000);
|
buf = malloc(0x400000);
|
||||||
|
@ -201,7 +204,72 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
consoleUpdate(NULL);
|
consoleUpdate(NULL);
|
||||||
|
|
||||||
|
romfs_dir_entry = romfsGetDirectoryEntryByOffset(&romfs_ctx, 0x74); // "Resources"
|
||||||
|
if (!romfs_dir_entry)
|
||||||
|
{
|
||||||
|
printf("romfs dir entry failed\n");
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("romfs dir entry success: %s | %p\n", romfs_dir_entry->name, romfs_dir_entry);
|
||||||
|
consoleUpdate(NULL);
|
||||||
|
|
||||||
|
if (romfsGetDirectoryDataSize(&romfs_ctx, romfs_dir_entry, &romfs_size))
|
||||||
|
{
|
||||||
|
printf("romfs dir size succeeded: 0x%lX\n", romfs_size);
|
||||||
|
} else {
|
||||||
|
printf("romfs dir size failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
consoleUpdate(NULL);
|
||||||
|
|
||||||
|
romfs_file_entry = romfsGetFileEntryByOffset(&romfs_ctx, romfs_dir_entry->file_offset); // "mscorlib.dll-resources.dat"
|
||||||
|
if (!romfs_file_entry)
|
||||||
|
{
|
||||||
|
printf("romfs file entry failed\n");
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("romfs file entry success: %s | %p\n", romfs_file_entry->name, romfs_file_entry);
|
||||||
|
consoleUpdate(NULL);
|
||||||
|
|
||||||
|
if (!romfsGeneratePathFromDirectoryEntry(&romfs_ctx, romfs_dir_entry, romfs_path, FS_MAX_PATH))
|
||||||
|
{
|
||||||
|
printf("romfs generate dir path failed\n");
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("romfs generate dir path success: %s\n", romfs_path);
|
||||||
|
consoleUpdate(NULL);
|
||||||
|
|
||||||
|
romfs_dir_entry = romfsGetDirectoryEntryByPath(&romfs_ctx, romfs_path);
|
||||||
|
if (!romfs_dir_entry)
|
||||||
|
{
|
||||||
|
printf("romfs get dir entry by path failed\n");
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("romfs get dir entry by path success: %s | %p\n", romfs_dir_entry->name, romfs_dir_entry);
|
||||||
|
consoleUpdate(NULL);
|
||||||
|
|
||||||
|
if (!romfsGeneratePathFromFileEntry(&romfs_ctx, romfs_file_entry, romfs_path, FS_MAX_PATH))
|
||||||
|
{
|
||||||
|
printf("romfs generate file path failed\n");
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("romfs generate file path success: %s\n", romfs_path);
|
||||||
|
consoleUpdate(NULL);
|
||||||
|
|
||||||
|
romfs_file_entry = romfsGetFileEntryByPath(&romfs_ctx, romfs_path);
|
||||||
|
if (!romfs_file_entry)
|
||||||
|
{
|
||||||
|
printf("romfs get file entry by path failed\n");
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("romfs get file entry by path success: %s | %p\n", romfs_file_entry->name, romfs_file_entry);
|
||||||
|
consoleUpdate(NULL);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
25
source/nca.h
25
source/nca.h
|
@ -34,6 +34,7 @@
|
||||||
#define NCA_HIERARCHICAL_SHA256_LAYER_COUNT 2
|
#define NCA_HIERARCHICAL_SHA256_LAYER_COUNT 2
|
||||||
|
|
||||||
#define NCA_IVFC_MAGIC 0x49564643 /* "IVFC" */
|
#define NCA_IVFC_MAGIC 0x49564643 /* "IVFC" */
|
||||||
|
#define NCA_IVFC_LAYER_COUNT 7
|
||||||
#define NCA_IVFC_HASH_DATA_LAYER_COUNT 5
|
#define NCA_IVFC_HASH_DATA_LAYER_COUNT 5
|
||||||
#define NCA_IVFC_BLOCK_SIZE(x) (1 << (x))
|
#define NCA_IVFC_BLOCK_SIZE(x) (1 << (x))
|
||||||
|
|
||||||
|
@ -70,7 +71,14 @@ typedef enum {
|
||||||
NcaKeyAreaEncryptionKeyIndex_System = 2
|
NcaKeyAreaEncryptionKeyIndex_System = 2
|
||||||
} NcaKeyAreaEncryptionKeyIndex;
|
} NcaKeyAreaEncryptionKeyIndex;
|
||||||
|
|
||||||
/// 'NcaKeyGeneration_Latest' will always point to the last known key generation value.
|
typedef struct {
|
||||||
|
u8 relstep;
|
||||||
|
u8 micro;
|
||||||
|
u8 minor;
|
||||||
|
u8 major;
|
||||||
|
} NcaSdkAddOnVersion;
|
||||||
|
|
||||||
|
/// 'NcaKeyGeneration_Current' will always point to the last known key generation value.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NcaKeyGeneration_301_302 = 3,
|
NcaKeyGeneration_301_302 = 3,
|
||||||
NcaKeyGeneration_400_410 = 4,
|
NcaKeyGeneration_400_410 = 4,
|
||||||
|
@ -81,7 +89,8 @@ typedef enum {
|
||||||
NcaKeyGeneration_810_811 = 9,
|
NcaKeyGeneration_810_811 = 9,
|
||||||
NcaKeyGeneration_900_901 = 10,
|
NcaKeyGeneration_900_901 = 10,
|
||||||
NcaKeyGeneration_910_920 = 11,
|
NcaKeyGeneration_910_920 = 11,
|
||||||
NcaKeyGeneration_Latest = NcaKeyGeneration_910_920
|
NcaKeyGeneration_1000_1001 = 12,
|
||||||
|
NcaKeyGeneration_Current = NcaKeyGeneration_1000_1001
|
||||||
} NcaKeyGeneration;
|
} NcaKeyGeneration;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -220,15 +229,7 @@ typedef struct {
|
||||||
u64 content_size;
|
u64 content_size;
|
||||||
u64 program_id;
|
u64 program_id;
|
||||||
u32 content_index;
|
u32 content_index;
|
||||||
union {
|
NcaSdkAddOnVersion sdk_addon_version;
|
||||||
u32 sdk_addon_version;
|
|
||||||
struct {
|
|
||||||
u8 sdk_addon_revision;
|
|
||||||
u8 sdk_addon_micro;
|
|
||||||
u8 sdk_addon_minor;
|
|
||||||
u8 sdk_addon_major;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
u8 key_generation; ///< NcaKeyGeneration.
|
u8 key_generation; ///< NcaKeyGeneration.
|
||||||
u8 main_signature_key_generation;
|
u8 main_signature_key_generation;
|
||||||
u8 reserved_1[0xE];
|
u8 reserved_1[0xE];
|
||||||
|
@ -370,7 +371,7 @@ NX_INLINE bool ncaValidateHierarchicalSha256Offsets(NcaHierarchicalSha256 *hiera
|
||||||
NX_INLINE bool ncaValidateHierarchicalIntegrityOffsets(NcaHierarchicalIntegrity *hierarchical_integrity, u64 section_size)
|
NX_INLINE bool ncaValidateHierarchicalIntegrityOffsets(NcaHierarchicalIntegrity *hierarchical_integrity, u64 section_size)
|
||||||
{
|
{
|
||||||
if (!hierarchical_integrity || !section_size || __builtin_bswap32(hierarchical_integrity->magic) != NCA_IVFC_MAGIC || !hierarchical_integrity->master_hash_size || \
|
if (!hierarchical_integrity || !section_size || __builtin_bswap32(hierarchical_integrity->magic) != NCA_IVFC_MAGIC || !hierarchical_integrity->master_hash_size || \
|
||||||
hierarchical_integrity->layer_count < NCA_IVFC_HASH_DATA_LAYER_COUNT) return false;
|
hierarchical_integrity->layer_count != NCA_IVFC_LAYER_COUNT) return false;
|
||||||
|
|
||||||
/* Validate layer offsets and sizes */
|
/* Validate layer offsets and sizes */
|
||||||
for(u8 i = 0; i < (NCA_IVFC_HASH_DATA_LAYER_COUNT + 1); i++)
|
for(u8 i = 0; i < (NCA_IVFC_HASH_DATA_LAYER_COUNT + 1); i++)
|
||||||
|
|
|
@ -53,7 +53,7 @@ typedef struct {
|
||||||
u64 hash_block_size; ///< New hash block size.
|
u64 hash_block_size; ///< New hash block size.
|
||||||
u8 *hash_block; ///< New hash block contents.
|
u8 *hash_block; ///< New hash block contents.
|
||||||
u64 data_block_offset; ///< New data block offset (relative to the start of the NCA content file).
|
u64 data_block_offset; ///< New data block offset (relative to the start of the NCA content file).
|
||||||
u64 data_block_size; ///< New data block size.
|
u64 data_block_size; ///< New data block size (aligned to the NcaHierarchicalSha256 block size).
|
||||||
u8 *data_block; ///< New data block contents.
|
u8 *data_block; ///< New data block contents.
|
||||||
} PartitionFileSystemPatchInfo;
|
} PartitionFileSystemPatchInfo;
|
||||||
|
|
||||||
|
|
334
source/romfs.c
334
source/romfs.c
|
@ -21,6 +21,11 @@
|
||||||
#include "romfs.h"
|
#include "romfs.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
/* Function prototypes. */
|
||||||
|
|
||||||
|
static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name);
|
||||||
|
static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name);
|
||||||
|
|
||||||
bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_fs_ctx)
|
bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_fs_ctx)
|
||||||
{
|
{
|
||||||
NcaContext *nca_ctx = NULL;
|
NcaContext *nca_ctx = NULL;
|
||||||
|
@ -181,57 +186,336 @@ bool romfsReadFileEntryData(RomFileSystemContext *ctx, RomFileSystemFileEntry *f
|
||||||
|
|
||||||
bool romfsGetTotalDataSize(RomFileSystemContext *ctx, u64 *out_size)
|
bool romfsGetTotalDataSize(RomFileSystemContext *ctx, u64 *out_size)
|
||||||
{
|
{
|
||||||
if (!ctx || !ctx->file_table_size || !ctx->file_table || !out_size) return false;
|
if (!ctx || !ctx->file_table_size || !ctx->file_table || !out_size)
|
||||||
|
{
|
||||||
|
LOGFILE("Invalid parameters!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
u64 offset = 0, total_size = 0;
|
u64 offset = 0, total_size = 0;
|
||||||
RomFileSystemFileEntry *file_entry = NULL;
|
RomFileSystemFileEntry *file_entry = NULL;
|
||||||
|
|
||||||
while(offset < ctx->file_table_size)
|
while(offset < ctx->file_table_size)
|
||||||
{
|
{
|
||||||
if (!(file_entry = romfsGetFileEntry(ctx, offset))) return false;
|
if (!(file_entry = romfsGetFileEntryByOffset(ctx, offset)))
|
||||||
|
{
|
||||||
|
LOGFILE("Failed to retrieve file entry!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
total_size += file_entry->size;
|
total_size += file_entry->size;
|
||||||
offset += ALIGN_UP(sizeof(RomFileSystemFileEntry) + file_entry->name_length, 4);
|
offset += ALIGN_UP(sizeof(RomFileSystemFileEntry) + file_entry->name_length, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_size = total_size;
|
*out_size = total_size;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, u32 dir_entry_offset, u64 *out_size)
|
bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, u64 *out_size)
|
||||||
{
|
{
|
||||||
|
if (!ctx || !ctx->dir_table_size || !ctx->dir_table || !ctx->file_table_size || !ctx->file_table || !dir_entry || (dir_entry->file_offset == ROMFS_VOID_ENTRY && \
|
||||||
|
dir_entry->directory_offset == ROMFS_VOID_ENTRY) || !out_size)
|
||||||
|
{
|
||||||
|
LOGFILE("Invalid parameters!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
u64 total_size = 0, child_dir_size = 0;
|
u64 total_size = 0, child_dir_size = 0;
|
||||||
RomFileSystemDirectoryEntry *dir_entry = NULL;
|
u32 cur_file_offset = 0, cur_dir_offset = 0;
|
||||||
RomFileSystemFileEntry *file_entry = NULL;
|
RomFileSystemFileEntry *cur_file_entry = NULL;
|
||||||
|
RomFileSystemDirectoryEntry *cur_dir_entry = NULL;
|
||||||
|
|
||||||
if (!ctx || !ctx->dir_table_size || !ctx->dir_table || !ctx->file_table_size || !ctx->file_table || !out_size || !(dir_entry = romfsGetDirectoryEntry(ctx, dir_entry_offset)) || \
|
cur_file_offset = dir_entry->file_offset;
|
||||||
(!dir_entry->name_length && dir_entry_offset > 0)) return false;
|
while(cur_file_offset != ROMFS_VOID_ENTRY)
|
||||||
|
|
||||||
if (dir_entry->file_offset != ROMFS_VOID_ENTRY)
|
|
||||||
{
|
{
|
||||||
if (!(file_entry = romfsGetFileEntry(ctx, dir_entry->file_offset))) return false;
|
if (!(cur_file_entry = romfsGetFileEntryByOffset(ctx, cur_file_offset)))
|
||||||
total_size += file_entry->size;
|
|
||||||
|
|
||||||
while(file_entry->next_offset != ROMFS_VOID_ENTRY)
|
|
||||||
{
|
{
|
||||||
if (!(file_entry = romfsGetFileEntry(ctx, file_entry->next_offset))) return false;
|
LOGFILE("Failed to retrieve file entry!");
|
||||||
total_size += file_entry->size;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir_entry->directory_offset != ROMFS_VOID_ENTRY)
|
total_size += cur_file_entry->size;
|
||||||
|
cur_file_offset = cur_file_entry->next_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_dir_offset = dir_entry->directory_offset;
|
||||||
|
while(cur_dir_offset != ROMFS_VOID_ENTRY)
|
||||||
{
|
{
|
||||||
if (!romfsGetDirectoryDataSize(ctx, dir_entry->directory_offset, &child_dir_size)) return false;
|
if (!(cur_dir_entry = romfsGetDirectoryEntryByOffset(ctx, cur_dir_offset)) || !romfsGetDirectoryDataSize(ctx, cur_dir_entry, &child_dir_size))
|
||||||
|
{
|
||||||
|
LOGFILE("Failed to retrieve directory entry/size!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
total_size += child_dir_size;
|
total_size += child_dir_size;
|
||||||
|
cur_dir_offset = cur_dir_entry->next_offset;
|
||||||
while(dir_entry->next_offset != ROMFS_VOID_ENTRY)
|
|
||||||
{
|
|
||||||
if (!romfsGetDirectoryDataSize(ctx, dir_entry->next_offset, &child_dir_size)) return false;
|
|
||||||
total_size += child_dir_size;
|
|
||||||
if (!(dir_entry = romfsGetDirectoryEntry(ctx, dir_entry->next_offset))) return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_size = total_size;
|
*out_size = total_size;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RomFileSystemDirectoryEntry *romfsGetDirectoryEntryByPath(RomFileSystemContext *ctx, const char *path)
|
||||||
|
{
|
||||||
|
size_t path_len = 0;
|
||||||
|
char *path_dup = NULL, *pch = NULL;
|
||||||
|
RomFileSystemDirectoryEntry *dir_entry = NULL;
|
||||||
|
|
||||||
|
if (!ctx || !ctx->dir_table || !ctx->dir_table_size || !path || *path != '/' || !(path_len = strlen(path)) || !(dir_entry = romfsGetDirectoryEntryByOffset(ctx, 0)))
|
||||||
|
{
|
||||||
|
LOGFILE("Invalid parameters!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the root directory was requested */
|
||||||
|
if (path_len == 1) return dir_entry;
|
||||||
|
|
||||||
|
/* Duplicate path to avoid problems with strtok() */
|
||||||
|
if (!(path_dup = strdup(path)))
|
||||||
|
{
|
||||||
|
LOGFILE("Unable to duplicate input path!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pch = strtok(path_dup, "/");
|
||||||
|
if (!pch)
|
||||||
|
{
|
||||||
|
LOGFILE("Failed to tokenize input path!");
|
||||||
|
dir_entry = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(pch)
|
||||||
|
{
|
||||||
|
if (!(dir_entry = romfsGetChildDirectoryEntryByName(ctx, dir_entry, pch)))
|
||||||
|
{
|
||||||
|
LOGFILE("Failed to retrieve directory entry by name!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pch = strtok(NULL, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (path_dup) free(path_dup);
|
||||||
|
|
||||||
|
return dir_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const char *path)
|
||||||
|
{
|
||||||
|
size_t path_len = 0;
|
||||||
|
char *path_dup = NULL, *filename = NULL;
|
||||||
|
RomFileSystemFileEntry *file_entry = NULL;
|
||||||
|
RomFileSystemDirectoryEntry *dir_entry = NULL;
|
||||||
|
|
||||||
|
if (!ctx || !ctx->file_table || !ctx->file_table_size || !path || *path != '/' || (path_len = strlen(path)) <= 1)
|
||||||
|
{
|
||||||
|
LOGFILE("Invalid parameters!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Duplicate path */
|
||||||
|
if (!(path_dup = strdup(path)))
|
||||||
|
{
|
||||||
|
LOGFILE("Unable to duplicate input path!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove any trailing slashes */
|
||||||
|
while(path_dup[path_len - 1] == '/')
|
||||||
|
{
|
||||||
|
path_dup[path_len - 1] = '\0';
|
||||||
|
path_len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Safety check */
|
||||||
|
if (!path_len || !(filename = strrchr(path_dup, '/')))
|
||||||
|
{
|
||||||
|
LOGFILE("Invalid input path!");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove leading slash and adjust filename string pointer */
|
||||||
|
*filename++ = '\0';
|
||||||
|
|
||||||
|
/* Retrieve directory entry */
|
||||||
|
/* If the first character is NULL, then just retrieve the root directory entry */
|
||||||
|
if (!(dir_entry = (*path_dup ? romfsGetDirectoryEntryByPath(ctx, path_dup) : romfsGetDirectoryEntryByOffset(ctx, 0))))
|
||||||
|
{
|
||||||
|
LOGFILE("Failed to retrieve directory entry!");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve file entry */
|
||||||
|
if (!(file_entry = romfsGetChildFileEntryByName(ctx, dir_entry, filename))) LOGFILE("Failed to retrieve file entry by name!");
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (path_dup) free(path_dup);
|
||||||
|
|
||||||
|
return file_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, char *out_path, size_t out_path_size)
|
||||||
|
{
|
||||||
|
size_t path_len = 0;
|
||||||
|
u32 dir_offset = ROMFS_VOID_ENTRY, dir_entries_count = 0;
|
||||||
|
RomFileSystemDirectoryEntry **dir_entries = NULL, **tmp_dir_entries = NULL;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
if (!ctx || !ctx->dir_table || !ctx->dir_table_size || !dir_entry || (!dir_entry->name_length && dir_entry->parent_offset) || !out_path || out_path_size < 2)
|
||||||
|
{
|
||||||
|
LOGFILE("Invalid parameters!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we're dealing with the root directory entry */
|
||||||
|
if (!dir_entry->name_length)
|
||||||
|
{
|
||||||
|
sprintf(out_path, "/");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate memory for our directory entries */
|
||||||
|
dir_entries = calloc(1, sizeof(RomFileSystemDirectoryEntry*));
|
||||||
|
if (!dir_entries)
|
||||||
|
{
|
||||||
|
LOGFILE("Unable to allocate memory for directory entries!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
path_len = (1 + dir_entry->name_length);
|
||||||
|
*dir_entries = dir_entry;
|
||||||
|
dir_entries_count++;
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
dir_offset = dir_entries[dir_entries_count - 1]->parent_offset;
|
||||||
|
if (!dir_offset) break;
|
||||||
|
|
||||||
|
/* Reallocate directory entries */
|
||||||
|
if (!(tmp_dir_entries = realloc(dir_entries, (dir_entries_count + 1) * sizeof(RomFileSystemDirectoryEntry*))))
|
||||||
|
{
|
||||||
|
LOGFILE("Unable to reallocate directory entries buffer!");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_entries = tmp_dir_entries;
|
||||||
|
tmp_dir_entries = NULL;
|
||||||
|
|
||||||
|
if (!(dir_entries[dir_entries_count] = romfsGetDirectoryEntryByOffset(ctx, dir_offset)) || !dir_entries[dir_entries_count]->name_length)
|
||||||
|
{
|
||||||
|
LOGFILE("Failed to retrieve directory entry!");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
path_len += (1 + dir_entries[dir_entries_count]->name_length);
|
||||||
|
dir_entries_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path_len >= out_path_size)
|
||||||
|
{
|
||||||
|
LOGFILE("Output path length exceeds output buffer size!");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate output path */
|
||||||
|
*out_path = '\0';
|
||||||
|
for(u32 i = dir_entries_count; i > 0; i--)
|
||||||
|
{
|
||||||
|
strcat(out_path, "/");
|
||||||
|
strncat(out_path, dir_entries[i - 1]->name, dir_entries[i - 1]->name_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (dir_entries) free(dir_entries);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool romfsGeneratePathFromFileEntry(RomFileSystemContext *ctx, RomFileSystemFileEntry *file_entry, char *out_path, size_t out_path_size)
|
||||||
|
{
|
||||||
|
size_t path_len = 0;
|
||||||
|
RomFileSystemDirectoryEntry *dir_entry = NULL;
|
||||||
|
|
||||||
|
if (!ctx || !ctx->file_table || !ctx->file_table_size || !file_entry || !file_entry->name_length || !out_path || out_path_size < 2 || \
|
||||||
|
!(dir_entry = romfsGetDirectoryEntryByOffset(ctx, file_entry->parent_offset)))
|
||||||
|
{
|
||||||
|
LOGFILE("Invalid parameters!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve full RomFS path up to the file entry name */
|
||||||
|
if (!romfsGeneratePathFromDirectoryEntry(ctx, dir_entry, out_path, out_path_size))
|
||||||
|
{
|
||||||
|
LOGFILE("Failed to retrieve RomFS directory path!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check path length */
|
||||||
|
path_len = strlen(out_path);
|
||||||
|
if ((1 + file_entry->name_length) >= (out_path_size - path_len))
|
||||||
|
{
|
||||||
|
LOGFILE("Output path length exceeds output buffer size!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Concatenate file entry name */
|
||||||
|
strcat(out_path, "/");
|
||||||
|
strncat(out_path, file_entry->name, file_entry->name_length);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!ctx || !ctx->dir_table || !ctx->dir_table_size || !dir_entry || (dir_offset = dir_entry->directory_offset) == ROMFS_VOID_ENTRY || !name || !(name_len = strlen(name))) return NULL;
|
||||||
|
|
||||||
|
while(dir_offset != ROMFS_VOID_ENTRY)
|
||||||
|
{
|
||||||
|
if (!(child_dir_entry = romfsGetDirectoryEntryByOffset(ctx, dir_offset)) || !child_dir_entry->name_length) return NULL;
|
||||||
|
if (!strncmp(child_dir_entry->name, name, name_len)) return child_dir_entry;
|
||||||
|
dir_offset = child_dir_entry->next_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!ctx || !ctx->dir_table || !ctx->dir_table_size || !ctx->file_table || !ctx->file_table_size || !dir_entry || (file_offset = dir_entry->file_offset) == ROMFS_VOID_ENTRY || !name || \
|
||||||
|
!(name_len = strlen(name))) return NULL;
|
||||||
|
|
||||||
|
while(file_offset != ROMFS_VOID_ENTRY)
|
||||||
|
{
|
||||||
|
if (!(child_file_entry = romfsGetFileEntryByOffset(ctx, file_offset)) || !child_file_entry->name_length) return NULL;
|
||||||
|
if (!strncmp(child_file_entry->name, name, name_len)) return child_file_entry;
|
||||||
|
file_offset = child_file_entry->next_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -124,17 +124,31 @@ bool romfsReadFileEntryData(RomFileSystemContext *ctx, RomFileSystemFileEntry *f
|
||||||
bool romfsGetTotalDataSize(RomFileSystemContext *ctx, u64 *out_size);
|
bool romfsGetTotalDataSize(RomFileSystemContext *ctx, u64 *out_size);
|
||||||
|
|
||||||
/// Calculates the extracted size from a RomFS directory.
|
/// Calculates the extracted size from a RomFS directory.
|
||||||
bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, u32 dir_entry_offset, u64 *out_size);
|
bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, u64 *out_size);
|
||||||
|
|
||||||
|
/// Retrieves a RomFS directory entry by path.
|
||||||
|
/// Input path must have a leading slash ('/'). If just a single slash is provided, a pointer to the root directory entry shall be returned.
|
||||||
|
RomFileSystemDirectoryEntry *romfsGetDirectoryEntryByPath(RomFileSystemContext *ctx, const char *path);
|
||||||
|
|
||||||
|
/// Retrieves a RomFS file entry by path.
|
||||||
|
/// Input path must have a leading slash ('/').
|
||||||
|
RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const char *path);
|
||||||
|
|
||||||
|
/// Generates a path string from a RomFS directory entry.
|
||||||
|
bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, char *out_path, size_t out_path_size);
|
||||||
|
|
||||||
|
/// Generates a path string from a RomFS file entry.
|
||||||
|
bool romfsGeneratePathFromFileEntry(RomFileSystemContext *ctx, RomFileSystemFileEntry *file_entry, char *out_path, size_t out_path_size);
|
||||||
|
|
||||||
/// Miscellaneous functions.
|
/// Miscellaneous functions.
|
||||||
|
|
||||||
NX_INLINE RomFileSystemDirectoryEntry *romfsGetDirectoryEntry(RomFileSystemContext *ctx, u32 dir_entry_offset)
|
NX_INLINE RomFileSystemDirectoryEntry *romfsGetDirectoryEntryByOffset(RomFileSystemContext *ctx, u32 dir_entry_offset)
|
||||||
{
|
{
|
||||||
if (!ctx || !ctx->dir_table || (dir_entry_offset + sizeof(RomFileSystemDirectoryEntry)) > ctx->dir_table_size) return NULL;
|
if (!ctx || !ctx->dir_table || (dir_entry_offset + sizeof(RomFileSystemDirectoryEntry)) > ctx->dir_table_size) return NULL;
|
||||||
return (RomFileSystemDirectoryEntry*)((u8*)ctx->dir_table + dir_entry_offset);
|
return (RomFileSystemDirectoryEntry*)((u8*)ctx->dir_table + dir_entry_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE RomFileSystemFileEntry *romfsGetFileEntry(RomFileSystemContext *ctx, u32 file_entry_offset)
|
NX_INLINE RomFileSystemFileEntry *romfsGetFileEntryByOffset(RomFileSystemContext *ctx, u32 file_entry_offset)
|
||||||
{
|
{
|
||||||
if (!ctx || !ctx->file_table || (file_entry_offset + sizeof(RomFileSystemFileEntry)) > ctx->file_table_size) return NULL;
|
if (!ctx || !ctx->file_table || (file_entry_offset + sizeof(RomFileSystemFileEntry)) > ctx->file_table_size) return NULL;
|
||||||
return (RomFileSystemFileEntry*)((u8*)ctx->file_table + file_entry_offset);
|
return (RomFileSystemFileEntry*)((u8*)ctx->file_table + file_entry_offset);
|
||||||
|
|
Loading…
Reference in a new issue