2020-04-26 09:35:01 +01:00
/*
2020-07-03 10:31:22 +01:00
* romfs . c
2020-04-26 09:35:01 +01:00
*
2020-07-03 10:31:22 +01:00
* Copyright ( c ) 2020 , DarkMatterCore < pabloacurielz @ gmail . com > .
*
* This file is part of nxdumptool ( https : //github.com/DarkMatterCore/nxdumptool).
*
* nxdumptool is free software ; you can redistribute it and / or modify it
2020-04-26 09:35:01 +01:00
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
2020-07-03 10:31:22 +01:00
* nxdumptool is distributed in the hope it will be useful , but WITHOUT
2020-04-26 09:35:01 +01:00
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "utils.h"
2020-07-03 10:31:22 +01:00
# include "romfs.h"
2020-04-26 09:35:01 +01:00
2020-04-27 23:37:15 +01:00
/* Function prototypes. */
static RomFileSystemDirectoryEntry * romfsGetChildDirectoryEntryByName ( RomFileSystemContext * ctx , RomFileSystemDirectoryEntry * dir_entry , const char * name ) ;
static RomFileSystemFileEntry * romfsGetChildFileEntryByName ( RomFileSystemContext * ctx , RomFileSystemDirectoryEntry * dir_entry , const char * name ) ;
2020-04-26 09:35:01 +01:00
bool romfsInitializeContext ( RomFileSystemContext * out , NcaFsSectionContext * nca_fs_ctx )
{
NcaContext * nca_ctx = NULL ;
u64 dir_table_offset = 0 , file_table_offset = 0 ;
2020-07-22 09:03:28 +01:00
if ( ! out | | ! nca_fs_ctx | | ! nca_fs_ctx - > enabled | | ! ( nca_ctx = ( NcaContext * ) nca_fs_ctx - > nca_ctx ) | | ( nca_ctx - > format_version = = NcaVersion_Nca0 & & \
( nca_fs_ctx - > section_type ! = NcaFsSectionType_Nca0RomFs | | nca_fs_ctx - > header . hash_type ! = NcaHashType_HierarchicalSha256 ) ) | | ( nca_ctx - > format_version ! = NcaVersion_Nca0 & & \
( nca_fs_ctx - > section_type ! = NcaFsSectionType_RomFs | | nca_fs_ctx - > header . hash_type ! = NcaHashType_HierarchicalIntegrity ) ) )
2020-04-26 09:35:01 +01:00
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
2020-07-22 09:03:28 +01:00
u32 layer_count = 0 ;
NcaRegion * hash_region = NULL ;
NcaHierarchicalIntegrityVerificationLevelInformation * level_information = NULL ;
2020-07-06 01:10:07 +01:00
/* Clear output RomFS context. */
memset ( out , 0 , sizeof ( RomFileSystemContext ) ) ;
/* Fill context. */
2020-04-26 09:35:01 +01:00
out - > nca_fs_ctx = nca_fs_ctx ;
if ( nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs )
{
2020-07-22 09:03:28 +01:00
if ( ! ncaValidateHierarchicalSha256Offsets ( & ( nca_fs_ctx - > header . hash_data . hierarchical_sha256_data ) , nca_fs_ctx - > section_size ) )
2020-04-26 09:35:01 +01:00
{
LOGFILE ( " Invalid HierarchicalSha256 block! " ) ;
return false ;
}
2020-07-22 09:03:28 +01:00
layer_count = nca_fs_ctx - > header . hash_data . hierarchical_sha256_data . hash_region_count ;
hash_region = & ( nca_fs_ctx - > header . hash_data . hierarchical_sha256_data . hash_region [ layer_count - 1 ] ) ;
out - > offset = hash_region - > offset ;
out - > size = hash_region - > size ;
2020-04-26 09:35:01 +01:00
} else {
2020-07-22 09:03:28 +01:00
if ( ! ncaValidateHierarchicalIntegrityOffsets ( & ( nca_fs_ctx - > header . hash_data . integrity_meta_info ) , nca_fs_ctx - > section_size ) )
2020-04-26 09:35:01 +01:00
{
LOGFILE ( " Invalid HierarchicalIntegrity block! " ) ;
return false ;
}
2020-07-22 09:03:28 +01:00
layer_count = NCA_IVFC_LEVEL_COUNT ;
level_information = & ( nca_fs_ctx - > header . hash_data . integrity_meta_info . info_level_hash . level_information [ layer_count - 1 ] ) ;
out - > offset = level_information - > offset ;
out - > size = level_information - > size ;
2020-04-26 09:35:01 +01:00
}
2020-07-06 01:10:07 +01:00
/* Read RomFS header. */
2020-04-26 09:35:01 +01:00
if ( ! ncaReadFsSection ( nca_fs_ctx , & ( out - > header ) , sizeof ( RomFileSystemHeader ) , out - > offset ) )
{
LOGFILE ( " Failed to read RomFS header! " ) ;
return false ;
}
if ( ( nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs & & out - > header . old_format . header_size ! = ROMFS_OLD_HEADER_SIZE ) | | \
( nca_fs_ctx - > section_type = = NcaFsSectionType_RomFs & & out - > header . cur_format . header_size ! = ROMFS_HEADER_SIZE ) )
{
LOGFILE ( " Invalid RomFS header size! " ) ;
return false ;
}
2020-04-29 22:11:27 +01:00
bool success = false ;
2020-07-06 01:10:07 +01:00
/* Read directory entries table. */
2020-04-26 11:04:31 +01:00
dir_table_offset = ( nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs ? ( u64 ) out - > header . old_format . directory_entry_offset : out - > header . cur_format . directory_entry_offset ) ;
2020-04-26 09:35:01 +01:00
out - > dir_table_size = ( nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs ? ( u64 ) out - > header . old_format . directory_entry_size : out - > header . cur_format . directory_entry_size ) ;
2020-04-30 09:25:03 +01:00
if ( ! out - > dir_table_size | | dir_table_offset > = out - > size | | ( dir_table_offset + out - > dir_table_size ) > out - > size )
2020-04-26 09:35:01 +01:00
{
LOGFILE ( " Invalid RomFS directory entries table! " ) ;
return false ;
}
out - > dir_table = malloc ( out - > dir_table_size ) ;
if ( ! out - > dir_table )
{
LOGFILE ( " Unable to allocate memory for RomFS directory entries table! " ) ;
return false ;
}
2020-04-26 11:04:31 +01:00
if ( ! ncaReadFsSection ( nca_fs_ctx , out - > dir_table , out - > dir_table_size , out - > offset + dir_table_offset ) )
2020-04-26 09:35:01 +01:00
{
LOGFILE ( " Failed to read RomFS directory entries table! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2020-07-06 01:10:07 +01:00
/* Read file entries table. */
2020-04-26 11:04:31 +01:00
file_table_offset = ( nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs ? ( u64 ) out - > header . old_format . file_entry_offset : out - > header . cur_format . file_entry_offset ) ;
2020-04-26 09:35:01 +01:00
out - > file_table_size = ( nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs ? ( u64 ) out - > header . old_format . file_entry_size : out - > header . cur_format . file_entry_size ) ;
2020-04-30 09:25:03 +01:00
if ( ! out - > file_table_size | | file_table_offset > = out - > size | | ( file_table_offset + out - > file_table_size ) > out - > size )
2020-04-26 09:35:01 +01:00
{
LOGFILE ( " Invalid RomFS file entries table! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-26 09:35:01 +01:00
}
out - > file_table = malloc ( out - > file_table_size ) ;
if ( ! out - > file_table )
{
LOGFILE ( " Unable to allocate memory for RomFS file entries table! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2020-04-26 11:04:31 +01:00
if ( ! ncaReadFsSection ( nca_fs_ctx , out - > file_table , out - > file_table_size , out - > offset + file_table_offset ) )
2020-04-26 09:35:01 +01:00
{
LOGFILE ( " Failed to read RomFS file entries table! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2020-07-06 01:10:07 +01:00
/* Get file data body offset. */
2020-04-26 11:04:31 +01:00
out - > body_offset = ( nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs ? ( u64 ) out - > header . old_format . body_offset : out - > header . cur_format . body_offset ) ;
2020-04-30 09:25:03 +01:00
if ( out - > body_offset > = out - > size )
2020-04-26 09:35:01 +01:00
{
LOGFILE ( " Invalid RomFS file data body! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2020-04-29 22:11:27 +01:00
success = true ;
2020-07-13 07:36:17 +01:00
end :
2020-04-29 22:11:27 +01:00
if ( ! success ) romfsFreeContext ( out ) ;
return success ;
2020-04-26 09:35:01 +01:00
}
2020-04-26 11:04:31 +01:00
bool romfsReadFileSystemData ( RomFileSystemContext * ctx , void * out , u64 read_size , u64 offset )
{
if ( ! ctx | | ! ctx - > nca_fs_ctx | | ! ctx - > size | | ! out | | ! read_size | | offset > = ctx - > size | | ( offset + read_size ) > ctx - > size )
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
2020-07-06 01:10:07 +01:00
/* Read filesystem data. */
2020-04-26 11:04:31 +01:00
if ( ! ncaReadFsSection ( ctx - > nca_fs_ctx , out , read_size , ctx - > offset + offset ) )
{
LOGFILE ( " Failed to read RomFS data! " ) ;
return false ;
}
return true ;
}
2020-04-26 09:35:01 +01:00
bool romfsReadFileEntryData ( RomFileSystemContext * ctx , RomFileSystemFileEntry * file_entry , void * out , u64 read_size , u64 offset )
{
2020-04-26 11:04:31 +01:00
if ( ! ctx | | ! ctx - > body_offset | | ! file_entry | | ! file_entry - > size | | file_entry - > offset > = ctx - > size | | ( file_entry - > offset + file_entry - > size ) > ctx - > size | | \
2020-04-26 09:35:01 +01:00
! out | | ! read_size | | offset > = file_entry - > size | | ( offset + read_size ) > file_entry - > size )
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
2020-07-06 01:10:07 +01:00
/* Read entry data. */
2020-04-26 11:04:31 +01:00
if ( ! romfsReadFileSystemData ( ctx , out , read_size , ctx - > body_offset + file_entry - > offset + offset ) )
2020-04-26 09:35:01 +01:00
{
LOGFILE ( " Failed to read RomFS file entry data! " ) ;
return false ;
}
return true ;
}
bool romfsGetTotalDataSize ( RomFileSystemContext * ctx , u64 * out_size )
{
2020-04-27 23:37:15 +01:00
if ( ! ctx | | ! ctx - > file_table_size | | ! ctx - > file_table | | ! out_size )
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
2020-04-26 09:35:01 +01:00
u64 offset = 0 , total_size = 0 ;
RomFileSystemFileEntry * file_entry = NULL ;
while ( offset < ctx - > file_table_size )
{
2020-04-27 23:37:15 +01:00
if ( ! ( file_entry = romfsGetFileEntryByOffset ( ctx , offset ) ) )
{
LOGFILE ( " Failed to retrieve file entry! " ) ;
return false ;
}
2020-04-26 09:35:01 +01:00
total_size + = file_entry - > size ;
offset + = ALIGN_UP ( sizeof ( RomFileSystemFileEntry ) + file_entry - > name_length , 4 ) ;
}
* out_size = total_size ;
2020-04-27 23:37:15 +01:00
2020-04-26 09:35:01 +01:00
return true ;
}
2020-04-27 23:37:15 +01:00
bool romfsGetDirectoryDataSize ( RomFileSystemContext * ctx , RomFileSystemDirectoryEntry * dir_entry , u64 * out_size )
2020-04-26 09:35:01 +01:00
{
2020-04-27 23:37:15 +01:00
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 ;
}
2020-04-26 09:35:01 +01:00
u64 total_size = 0 , child_dir_size = 0 ;
2020-04-27 23:37:15 +01:00
u32 cur_file_offset = 0 , cur_dir_offset = 0 ;
RomFileSystemFileEntry * cur_file_entry = NULL ;
RomFileSystemDirectoryEntry * cur_dir_entry = NULL ;
2020-04-26 09:35:01 +01:00
2020-04-27 23:37:15 +01:00
cur_file_offset = dir_entry - > file_offset ;
while ( cur_file_offset ! = ROMFS_VOID_ENTRY )
{
if ( ! ( cur_file_entry = romfsGetFileEntryByOffset ( ctx , cur_file_offset ) ) )
{
LOGFILE ( " Failed to retrieve file entry! " ) ;
return false ;
}
total_size + = cur_file_entry - > size ;
cur_file_offset = cur_file_entry - > next_offset ;
}
2020-04-26 09:35:01 +01:00
2020-04-27 23:37:15 +01:00
cur_dir_offset = dir_entry - > directory_offset ;
while ( cur_dir_offset ! = ROMFS_VOID_ENTRY )
2020-04-26 09:35:01 +01:00
{
2020-04-27 23:37:15 +01:00
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 ;
}
2020-04-26 09:35:01 +01:00
2020-04-27 23:37:15 +01:00
total_size + = child_dir_size ;
cur_dir_offset = cur_dir_entry - > next_offset ;
}
* out_size = total_size ;
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 ;
}
2020-07-06 01:10:07 +01:00
/* Check if the root directory was requested. */
2020-04-27 23:37:15 +01:00
if ( path_len = = 1 ) return dir_entry ;
2020-07-06 01:10:07 +01:00
/* Duplicate path to avoid problems with strtok(). */
2020-04-27 23:37:15 +01:00
if ( ! ( path_dup = strdup ( path ) ) )
{
2020-07-23 01:37:02 +01:00
LOGFILE ( " Unable to duplicate input path! ( \" %s \" ). " , path ) ;
2020-04-27 23:37:15 +01:00
return NULL ;
}
pch = strtok ( path_dup , " / " ) ;
if ( ! pch )
{
2020-07-23 01:37:02 +01:00
LOGFILE ( " Failed to tokenize input path! ( \" %s \" ). " , path ) ;
2020-04-27 23:37:15 +01:00
dir_entry = NULL ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
while ( pch )
{
if ( ! ( dir_entry = romfsGetChildDirectoryEntryByName ( ctx , dir_entry , pch ) ) )
2020-04-26 09:35:01 +01:00
{
2020-07-23 01:37:02 +01:00
LOGFILE ( " Failed to retrieve directory entry by name for \" %s \" ! ( \" %s \" ). " , pch , path ) ;
2020-04-27 23:37:15 +01:00
break ;
2020-04-26 09:35:01 +01:00
}
2020-04-27 23:37:15 +01:00
pch = strtok ( NULL , " / " ) ;
2020-04-26 09:35:01 +01:00
}
2020-07-13 07:36:17 +01:00
end :
2020-04-27 23:37:15 +01:00
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 )
2020-04-26 09:35:01 +01:00
{
2020-04-27 23:37:15 +01:00
LOGFILE ( " Invalid parameters! " ) ;
return NULL ;
}
2020-07-06 01:10:07 +01:00
/* Duplicate path. */
2020-04-27 23:37:15 +01:00
if ( ! ( path_dup = strdup ( path ) ) )
{
2020-07-23 01:37:02 +01:00
LOGFILE ( " Unable to duplicate input path! ( \" %s \" ). " , path ) ;
2020-04-27 23:37:15 +01:00
return NULL ;
}
2020-07-06 01:10:07 +01:00
/* Remove any trailing slashes. */
2020-04-27 23:37:15 +01:00
while ( path_dup [ path_len - 1 ] = = ' / ' )
{
path_dup [ path_len - 1 ] = ' \0 ' ;
path_len - - ;
}
2020-07-06 01:10:07 +01:00
/* Safety check. */
2020-04-27 23:37:15 +01:00
if ( ! path_len | | ! ( filename = strrchr ( path_dup , ' / ' ) ) )
{
2020-07-23 01:37:02 +01:00
LOGFILE ( " Invalid input path! ( \" %s \" ). " , path ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2020-07-06 01:10:07 +01:00
/* Remove leading slash and adjust filename string pointer. */
2020-04-27 23:37:15 +01:00
* filename + + = ' \0 ' ;
2020-07-06 01:10:07 +01:00
/* Retrieve directory entry. */
/* If the first character is NULL, then just retrieve the root directory entry. */
2020-04-27 23:37:15 +01:00
if ( ! ( dir_entry = ( * path_dup ? romfsGetDirectoryEntryByPath ( ctx , path_dup ) : romfsGetDirectoryEntryByOffset ( ctx , 0 ) ) ) )
{
2020-07-23 01:37:02 +01:00
LOGFILE ( " Failed to retrieve directory entry for \" %s \" ! ( \" %s \" ). " , * path_dup ? path_dup : " / " , path ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2020-07-06 01:10:07 +01:00
/* Retrieve file entry. */
2020-07-23 01:37:02 +01:00
if ( ! ( file_entry = romfsGetChildFileEntryByName ( ctx , dir_entry , filename ) ) ) LOGFILE ( " Failed to retrieve file entry by name for \" %s \" ! ( \" %s \" ). " , filename , path ) ;
2020-04-27 23:37:15 +01:00
2020-07-13 07:36:17 +01:00
end :
2020-04-27 23:37:15 +01:00
if ( path_dup ) free ( path_dup ) ;
return file_entry ;
}
2020-05-10 17:40:12 +01:00
bool romfsGeneratePathFromDirectoryEntry ( RomFileSystemContext * ctx , RomFileSystemDirectoryEntry * dir_entry , char * out_path , size_t out_path_size , u8 illegal_char_replace_type )
2020-04-27 23:37:15 +01:00
{
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 ;
2020-05-10 17:40:12 +01:00
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 | | \
illegal_char_replace_type > RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly )
2020-04-27 23:37:15 +01:00
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
2020-07-06 01:10:07 +01:00
/* Check if we're dealing with the root directory entry. */
2020-04-27 23:37:15 +01:00
if ( ! dir_entry - > name_length )
{
sprintf ( out_path , " / " ) ;
return true ;
}
2020-07-06 01:10:07 +01:00
/* Allocate memory for our directory entries. */
2020-04-27 23:37:15 +01:00
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 ;
2020-04-26 09:35:01 +01:00
2020-07-06 01:10:07 +01:00
/* Reallocate directory entries. */
2020-04-27 23:37:15 +01:00
if ( ! ( tmp_dir_entries = realloc ( dir_entries , ( dir_entries_count + 1 ) * sizeof ( RomFileSystemDirectoryEntry * ) ) ) )
2020-04-26 09:35:01 +01:00
{
2020-04-27 23:37:15 +01:00
LOGFILE ( " Unable to reallocate directory entries buffer! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2020-04-27 23:37:15 +01:00
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! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
path_len + = ( 1 + dir_entries [ dir_entries_count ] - > name_length ) ;
dir_entries_count + + ;
2020-04-26 09:35:01 +01:00
}
2020-04-27 23:37:15 +01:00
if ( path_len > = out_path_size )
{
LOGFILE ( " Output path length exceeds output buffer size! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2020-07-06 01:10:07 +01:00
/* Generate output path. */
2020-04-27 23:37:15 +01:00
* 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 ) ;
2020-05-10 17:40:12 +01:00
if ( illegal_char_replace_type ) utilsReplaceIllegalCharacters ( out_path + ( strlen ( out_path ) - dir_entries [ i - 1 ] - > name_length ) , \
illegal_char_replace_type = = RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly ) ;
2020-04-27 23:37:15 +01:00
}
success = true ;
2020-07-13 07:36:17 +01:00
end :
2020-04-27 23:37:15 +01:00
if ( dir_entries ) free ( dir_entries ) ;
return success ;
}
2020-05-10 17:40:12 +01:00
bool romfsGeneratePathFromFileEntry ( RomFileSystemContext * ctx , RomFileSystemFileEntry * file_entry , char * out_path , size_t out_path_size , u8 illegal_char_replace_type )
2020-04-27 23:37:15 +01:00
{
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 | | \
2020-05-10 17:40:12 +01:00
! ( dir_entry = romfsGetDirectoryEntryByOffset ( ctx , file_entry - > parent_offset ) ) | | illegal_char_replace_type > RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly )
2020-04-27 23:37:15 +01:00
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
2020-07-06 01:10:07 +01:00
/* Retrieve full RomFS path up to the file entry name. */
2020-05-10 17:40:12 +01:00
if ( ! romfsGeneratePathFromDirectoryEntry ( ctx , dir_entry , out_path , out_path_size , illegal_char_replace_type ) )
2020-04-27 23:37:15 +01:00
{
LOGFILE ( " Failed to retrieve RomFS directory path! " ) ;
return false ;
}
2020-07-06 01:10:07 +01:00
/* Check path length. */
2020-04-27 23:37:15 +01:00
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 ;
}
2020-07-06 01:10:07 +01:00
/* Concatenate file entry name. */
2020-05-10 17:40:12 +01:00
if ( file_entry - > parent_offset ) strcat ( out_path , " / " ) ;
2020-04-27 23:37:15 +01:00
strncat ( out_path , file_entry - > name , file_entry - > name_length ) ;
2020-05-10 17:40:12 +01:00
if ( illegal_char_replace_type ) utilsReplaceIllegalCharacters ( out_path + ( strlen ( out_path ) - file_entry - > name_length ) , \
illegal_char_replace_type = = RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly ) ;
2020-04-26 09:35:01 +01:00
return true ;
}
2020-04-27 23:37:15 +01:00
2020-04-28 09:58:17 +01:00
bool romfsGenerateFileEntryPatch ( RomFileSystemContext * ctx , RomFileSystemFileEntry * file_entry , const void * data , u64 data_size , u64 data_offset , RomFileSystemFileEntryPatch * out )
{
if ( ! ctx | | ! ctx - > nca_fs_ctx | | ! ctx - > body_offset | | ( ctx - > nca_fs_ctx - > section_type ! = NcaFsSectionType_Nca0RomFs & & ctx - > nca_fs_ctx - > section_type ! = NcaFsSectionType_RomFs ) | | ! file_entry | | \
! file_entry - > size | | file_entry - > offset > = ctx - > size | | ( file_entry - > offset + file_entry - > size ) > ctx - > size | | ! data | | ! data_size | | data_offset > = file_entry - > size | | \
( data_offset + data_size ) > file_entry - > size | | ! out )
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
bool success = false ;
u64 fs_offset = ( ctx - > body_offset + file_entry - > offset + data_offset ) ;
if ( ctx - > nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs )
{
out - > use_old_format_patch = true ;
success = ncaGenerateHierarchicalSha256Patch ( ctx - > nca_fs_ctx , data , data_size , fs_offset , & ( out - > old_format_patch ) ) ;
} else {
out - > use_old_format_patch = false ;
2020-04-29 10:54:40 +01:00
success = ncaGenerateHierarchicalIntegrityPatch ( ctx - > nca_fs_ctx , data , data_size , fs_offset , & ( out - > cur_format_patch ) ) ;
2020-04-28 09:58:17 +01:00
}
2020-07-22 21:35:23 +01:00
if ( ! success ) LOGFILE ( " Failed to generate 0x%lX bytes Hierarchical%s patch at offset 0x%lX for RomFS file entry! " , data_size , \
ctx - > nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs ? " Sha256 " : " Integrity " , fs_offset ) ;
2020-04-28 09:58:17 +01:00
return success ;
}
2020-04-27 23:37:15 +01:00
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 ;
2020-07-23 01:37:02 +01:00
if ( child_dir_entry - > name_length = = name_len & & ! strncmp ( child_dir_entry - > name , name , name_len ) ) return child_dir_entry ;
2020-04-27 23:37:15 +01:00
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 ;
2020-07-23 01:37:02 +01:00
if ( child_file_entry - > name_length = = name_len & & ! strncmp ( child_file_entry - > name , name , name_len ) ) return child_file_entry ;
2020-04-27 23:37:15 +01:00
file_offset = child_file_entry - > next_offset ;
}
return NULL ;
}