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
*
2023-04-08 12:42:22 +01:00
* Copyright ( c ) 2020 - 2023 , DarkMatterCore < pabloacurielz @ gmail . com > .
2020-07-03 10:31:22 +01:00
*
* This file is part of nxdumptool ( https : //github.com/DarkMatterCore/nxdumptool).
*
2021-03-25 19:26:58 +00:00
* nxdumptool is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
2020-04-26 09:35:01 +01:00
*
2021-03-25 19:26:58 +00:00
* nxdumptool is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2020-04-26 09:35:01 +01:00
*
* You should have received a copy of the GNU General Public License
2021-03-25 19:26:58 +00:00
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
2020-04-26 09:35:01 +01:00
*/
2021-03-26 04:35:14 +00:00
# include "nxdt_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 ) ;
2022-07-04 13:30:48 +01:00
bool romfsInitializeContext ( RomFileSystemContext * out , NcaFsSectionContext * base_nca_fs_ctx , NcaFsSectionContext * patch_nca_fs_ctx )
2020-04-26 09:35:01 +01:00
{
u64 dir_table_offset = 0 , file_table_offset = 0 ;
2022-07-04 13:30:48 +01:00
NcaContext * base_nca_ctx = NULL , * patch_nca_ctx = NULL ;
2022-07-05 00:25:28 +01:00
bool dump_fs_header = false , success = false ;
2022-07-05 02:04:28 +01:00
2022-07-05 05:01:07 +01:00
/* Check if the base RomFS is missing (e.g. Fortnite, World of Tanks Blitz, etc.). */
2023-11-03 01:22:47 +00:00
bool missing_base_romfs = ( ! base_nca_fs_ctx | | ! base_nca_fs_ctx - > enabled | | ( base_nca_fs_ctx - > section_type ! = NcaFsSectionType_RomFs & & \
base_nca_fs_ctx - > section_type ! = NcaFsSectionType_Nca0RomFs ) ) ;
2022-07-05 05:01:07 +01:00
2023-11-03 01:22:47 +00:00
if ( ! out | | ( ! patch_nca_fs_ctx & & ( missing_base_romfs | | base_nca_fs_ctx - > has_sparse_layer ) ) | | \
2022-09-12 19:19:10 +01:00
( ! missing_base_romfs & & ( ! ( base_nca_ctx = base_nca_fs_ctx - > nca_ctx ) | | ( base_nca_ctx - > format_version = = NcaVersion_Nca0 & & \
2022-07-05 05:01:07 +01:00
( base_nca_fs_ctx - > section_type ! = NcaFsSectionType_Nca0RomFs | | base_nca_fs_ctx - > hash_type ! = NcaHashType_HierarchicalSha256 ) ) | | \
( base_nca_ctx - > format_version ! = NcaVersion_Nca0 & & ( base_nca_fs_ctx - > section_type ! = NcaFsSectionType_RomFs | | \
( base_nca_fs_ctx - > hash_type ! = NcaHashType_HierarchicalIntegrity & & base_nca_fs_ctx - > hash_type ! = NcaHashType_HierarchicalIntegritySha3 ) ) ) | | \
( base_nca_ctx - > rights_id_available & & ! base_nca_ctx - > titlekey_retrieved ) ) ) | | ( patch_nca_fs_ctx & & ( ! patch_nca_fs_ctx - > enabled | | \
2022-09-12 19:19:10 +01:00
! ( patch_nca_ctx = patch_nca_fs_ctx - > nca_ctx ) | | ( ! missing_base_romfs & & patch_nca_ctx - > format_version ! = base_nca_ctx - > format_version ) | | \
2022-07-04 13:30:48 +01:00
patch_nca_fs_ctx - > section_type ! = NcaFsSectionType_PatchRomFs | | ( patch_nca_ctx - > rights_id_available & & ! patch_nca_ctx - > titlekey_retrieved ) ) ) )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-04-26 09:35:01 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2020-10-14 14:23:49 +01:00
/* Free output context beforehand. */
romfsFreeContext ( out ) ;
2022-07-05 02:04:28 +01:00
2022-07-04 13:30:48 +01:00
NcaStorageContext * base_storage_ctx = & ( out - > storage_ctx [ 0 ] ) , * patch_storage_ctx = & ( out - > storage_ctx [ 1 ] ) ;
2023-11-03 01:22:47 +00:00
bool is_nca0_romfs = ( base_nca_fs_ctx & & base_nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs ) ;
2022-07-05 02:04:28 +01:00
2022-07-04 13:30:48 +01:00
/* Initialize base NCA storage context. */
2023-09-24 17:41:39 +01:00
if ( ! missing_base_romfs & & ! ncaStorageInitializeContext ( base_storage_ctx , base_nca_fs_ctx , NULL ) )
2022-07-04 01:01:12 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to initialize base NCA storage context! " ) ;
2022-07-04 01:01:12 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2022-07-05 00:25:28 +01:00
if ( patch_nca_fs_ctx )
2022-07-04 13:30:48 +01:00
{
/* Initialize base NCA storage context. */
2023-10-12 10:24:03 +01:00
if ( ! ncaStorageInitializeContext ( patch_storage_ctx , patch_nca_fs_ctx , missing_base_romfs ? NULL : base_storage_ctx ) )
2022-07-04 13:30:48 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to initialize patch NCA storage context! " ) ;
2022-07-04 13:30:48 +01:00
goto end ;
}
2022-07-05 02:04:28 +01:00
2022-07-04 13:30:48 +01:00
/* Set default NCA FS storage context. */
2022-07-05 00:25:28 +01:00
out - > is_patch = true ;
2022-07-04 13:30:48 +01:00
out - > default_storage_ctx = patch_storage_ctx ;
} else {
/* Set default NCA FS storage context. */
2022-07-05 00:25:28 +01:00
out - > is_patch = false ;
2022-07-04 13:30:48 +01:00
out - > default_storage_ctx = base_storage_ctx ;
}
2022-07-05 02:04:28 +01:00
2022-07-04 01:01:12 +01:00
/* Get RomFS offset and size. */
2022-07-04 13:30:48 +01:00
if ( ! ncaStorageGetHashTargetExtents ( out - > default_storage_ctx , & ( out - > offset ) , & ( out - > size ) ) )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to get target hash layer extents! " ) ;
2022-06-29 07:55:35 +01:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +01:00
2020-07-06 01:10:07 +01:00
/* Read RomFS header. */
2022-07-04 13:30:48 +01:00
if ( ! ncaStorageRead ( out - > default_storage_ctx , & ( out - > header ) , sizeof ( RomFileSystemHeader ) , out - > offset ) )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to read RomFS header! " ) ;
2021-03-07 23:22:49 +00:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-04 13:30:48 +01:00
if ( ( is_nca0_romfs & & out - > header . old_format . header_size ! = ROMFS_OLD_HEADER_SIZE ) | | ( ! is_nca0_romfs & & out - > header . cur_format . header_size ! = ROMFS_HEADER_SIZE ) )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid RomFS header size! " ) ;
2021-03-07 23:22:49 +00:00
dump_fs_header = true ;
goto end ;
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +01:00
2020-07-06 01:10:07 +01:00
/* Read directory entries table. */
2022-07-04 13:30:48 +01:00
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 ) ;
2022-07-05 02:04:28 +01:00
2020-10-21 05:27:48 +01:00
if ( ! out - > dir_table_size | | ( dir_table_offset + out - > dir_table_size ) > out - > size )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid RomFS directory entries table! " ) ;
2021-03-07 23:22:49 +00:00
dump_fs_header = true ;
goto end ;
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +01:00
2020-04-26 09:35:01 +01:00
out - > dir_table = malloc ( out - > dir_table_size ) ;
if ( ! out - > dir_table )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Unable to allocate memory for RomFS directory entries table! " ) ;
2021-03-07 23:22:49 +00:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-04 13:30:48 +01:00
if ( ! ncaStorageRead ( out - > default_storage_ctx , out - > dir_table , out - > dir_table_size , out - > offset + dir_table_offset ) )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " 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
}
2022-07-05 02:04:28 +01:00
2020-07-06 01:10:07 +01:00
/* Read file entries table. */
2022-07-04 13:30:48 +01:00
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 ) ;
2022-07-05 02:04:28 +01:00
2020-10-21 05:27:48 +01:00
if ( ! out - > file_table_size | | ( file_table_offset + out - > file_table_size ) > out - > size )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid RomFS file entries table! " ) ;
2021-03-07 23:22:49 +00:00
dump_fs_header = true ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +01:00
2020-04-26 09:35:01 +01:00
out - > file_table = malloc ( out - > file_table_size ) ;
if ( ! out - > file_table )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " 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
}
2022-07-05 02:04:28 +01:00
2022-07-04 13:30:48 +01:00
if ( ! ncaStorageRead ( out - > default_storage_ctx , out - > file_table , out - > file_table_size , out - > offset + file_table_offset ) )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " 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
}
2022-07-05 02:04:28 +01:00
2020-07-06 01:10:07 +01:00
/* Get file data body offset. */
2022-07-04 13:30:48 +01:00
out - > body_offset = ( is_nca0_romfs ? ( 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
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid RomFS file data body! " ) ;
2021-03-07 23:22:49 +00:00
dump_fs_header = true ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +01:00
2021-03-07 23:22:49 +00:00
/* Update flag. */
2020-04-29 22:11:27 +01:00
success = true ;
2022-07-05 02:04:28 +01:00
2020-07-13 07:36:17 +01:00
end :
2021-03-07 23:22:49 +00:00
if ( ! success )
{
2022-07-12 17:34:49 +01:00
if ( dump_fs_header ) LOG_DATA_DEBUG ( & ( out - > header ) , sizeof ( RomFileSystemHeader ) , " RomFS header dump: " ) ;
2022-07-05 02:04:28 +01:00
2021-03-07 23:22:49 +00:00
romfsFreeContext ( out ) ;
}
2022-07-05 02:04:28 +01:00
2020-04-29 22:11:27 +01:00
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 )
{
2022-07-06 10:57:31 +01:00
if ( ! romfsIsValidContext ( ctx ) | | ! out | | ! read_size | | ( offset + read_size ) > ctx - > size )
2020-04-26 11:04:31 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-04-26 11:04:31 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2020-07-06 01:10:07 +01:00
/* Read filesystem data. */
2022-07-04 13:30:48 +01:00
if ( ! ncaStorageRead ( ctx - > default_storage_ctx , out , read_size , ctx - > offset + offset ) )
2020-04-26 11:04:31 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to read RomFS data! " ) ;
2020-04-26 11:04:31 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2020-04-26 11:04:31 +01:00
return true ;
}
2020-04-26 09:35:01 +01:00
bool romfsReadFileEntryData ( RomFileSystemContext * ctx , RomFileSystemFileEntry * file_entry , void * out , u64 read_size , u64 offset )
{
2022-07-06 10:57:31 +01:00
if ( ! romfsIsValidContext ( ctx ) | | ! file_entry | | ! file_entry - > size | | ( file_entry - > offset + file_entry - > size ) > ctx - > size | | ! out | | ! read_size | | \
( offset + read_size ) > file_entry - > size )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-04-26 09:35:01 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
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
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to read RomFS file entry data! " ) ;
2020-04-26 09:35:01 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2020-04-26 09:35:01 +01:00
return true ;
}
2022-07-07 01:30:45 +01:00
bool romfsGetTotalDataSize ( RomFileSystemContext * ctx , bool only_updated , u64 * out_size )
2020-04-26 09:35:01 +01:00
{
2022-07-07 01:30:45 +01:00
if ( ! romfsIsValidContext ( ctx ) | | ! out_size | | ( only_updated & & ( ! ctx - > is_patch | | ctx - > default_storage_ctx - > nca_fs_ctx - > section_type ! = NcaFsSectionType_PatchRomFs ) ) )
2020-04-27 23:37:15 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-04-27 23:37:15 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2020-04-26 09:35:01 +01:00
RomFileSystemFileEntry * file_entry = NULL ;
2022-07-06 10:57:31 +01:00
u64 total_size = 0 ;
bool success = false ;
/* Reset current file table offset. */
romfsResetFileTableOffset ( ctx ) ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Loop through all file entries. */
while ( romfsCanMoveToNextFileEntry ( ctx ) )
2020-04-26 09:35:01 +01:00
{
2022-07-10 05:41:18 +01:00
bool updated = false ;
2022-07-06 10:57:31 +01:00
/* Get current file entry. */
if ( ! ( file_entry = romfsGetCurrentFileEntry ( ctx ) ) )
2020-04-27 23:37:15 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to retrieve current file entry! (0x%lX, 0x%lX). " , ctx - > cur_file_offset , ctx - > file_table_size ) ;
2022-07-06 10:57:31 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-07 01:30:45 +01:00
/* Update total data size, taking into account the only_updated flag. */
2022-07-10 05:41:18 +01:00
if ( only_updated & & ! romfsIsFileEntryUpdated ( ctx , file_entry , & updated ) )
{
2022-07-12 17:34:49 +01:00
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 ) ;
2022-07-10 05:41:18 +01:00
goto end ;
}
if ( ! only_updated | | ( only_updated & & updated ) ) total_size + = file_entry - > size ;
2022-07-06 10:57:31 +01:00
/* Move to the next file entry. */
if ( ! romfsMoveToNextFileEntry ( ctx ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to move to the next file entry! (0x%lX, 0x%lX). " , ctx - > cur_file_offset , ctx - > file_table_size ) ;
2022-07-06 10:57:31 +01:00
goto end ;
}
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Update output values. */
2020-04-26 09:35:01 +01:00
* out_size = total_size ;
2022-07-06 10:57:31 +01:00
success = true ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
end :
/* Reset current file table offset. */
romfsResetFileTableOffset ( ctx ) ;
return success ;
2020-04-26 09:35:01 +01:00
}
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
{
2022-07-06 10:57:31 +01:00
if ( ! romfsIsValidContext ( ctx ) | | ! dir_entry | | ! out_size )
2020-04-27 23:37:15 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-04-27 23:37:15 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Short-circuit: check if we're dealing with an empty directory. */
if ( dir_entry - > file_offset = = ROMFS_VOID_ENTRY & & dir_entry - > directory_offset = = ROMFS_VOID_ENTRY )
{
* out_size = 0 ;
return true ;
}
2020-04-27 23:37:15 +01:00
RomFileSystemFileEntry * cur_file_entry = NULL ;
RomFileSystemDirectoryEntry * cur_dir_entry = NULL ;
2022-07-06 10:57:31 +01:00
u64 total_size = 0 , cur_entry_offset = 0 , child_dir_size = 0 ;
bool success = false ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Loop through the child file entries' linked list. */
cur_entry_offset = dir_entry - > file_offset ;
while ( cur_entry_offset ! = ROMFS_VOID_ENTRY )
2020-04-27 23:37:15 +01:00
{
2022-07-06 10:57:31 +01:00
/* Get current file entry. */
if ( ! ( cur_file_entry = romfsGetFileEntryByOffset ( ctx , cur_entry_offset ) ) )
2020-04-27 23:37:15 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to retrieve file entry! (0x%lX, 0x%lX). " , cur_entry_offset , ctx - > file_table_size ) ;
2022-07-06 10:57:31 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Update total data size. */
2020-04-27 23:37:15 +01:00
total_size + = cur_file_entry - > size ;
2022-07-06 10:57:31 +01:00
/* Update current file entry offset. */
cur_entry_offset = cur_file_entry - > next_offset ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Loop through the child directory entries' linked list. */
cur_entry_offset = dir_entry - > directory_offset ;
while ( cur_entry_offset ! = ROMFS_VOID_ENTRY )
2020-04-26 09:35:01 +01:00
{
2022-07-06 10:57:31 +01:00
/* Get current directory entry. */
if ( ! ( cur_dir_entry = romfsGetDirectoryEntryByOffset ( ctx , cur_entry_offset ) ) )
2020-04-27 23:37:15 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to retrieve directory entry! (0x%lX, 0x%lX). " , cur_entry_offset , ctx - > dir_table_size ) ;
2022-07-06 10:57:31 +01:00
goto end ;
}
/* Calculate directory size. */
if ( ! romfsGetDirectoryDataSize ( ctx , cur_dir_entry , & child_dir_size ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to get size for directory entry! (0x%lX, 0x%lX). " , cur_entry_offset , ctx - > dir_table_size ) ;
2022-07-06 10:57:31 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Update total data size. */
2020-04-27 23:37:15 +01:00
total_size + = child_dir_size ;
2022-07-06 10:57:31 +01:00
/* Update current directory entry offset. */
cur_entry_offset = cur_dir_entry - > next_offset ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Update output values. */
2020-04-27 23:37:15 +01:00
* out_size = total_size ;
2022-07-06 10:57:31 +01:00
success = true ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
end :
return success ;
2020-04-27 23:37:15 +01:00
}
RomFileSystemDirectoryEntry * romfsGetDirectoryEntryByPath ( RomFileSystemContext * ctx , const char * path )
{
size_t path_len = 0 ;
2021-07-21 16:04:18 +01:00
char * path_dup = NULL , * pch = NULL , * state = NULL ;
2020-04-27 23:37:15 +01:00
RomFileSystemDirectoryEntry * dir_entry = NULL ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
if ( ! romfsIsValidContext ( ctx ) | | ! path | | * path ! = ' / ' | | ! ( dir_entry = romfsGetDirectoryEntryByOffset ( ctx , 0 ) ) )
2020-04-27 23:37:15 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-04-27 23:37:15 +01:00
return NULL ;
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Retrieve path length. */
path_len = strlen ( path ) ;
/* Short-circuit: check if the root directory was requested. */
2020-04-27 23:37:15 +01:00
if ( path_len = = 1 ) return dir_entry ;
2022-07-05 02:04:28 +01:00
2021-07-21 16:04:18 +01:00
/* Duplicate path to avoid problems with strtok_r(). */
2020-04-27 23:37:15 +01:00
if ( ! ( path_dup = strdup ( path ) ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Unable to duplicate input path! ( \" %s \" ). " , path ) ;
2022-07-06 10:57:31 +01:00
dir_entry = NULL ;
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Tokenize duplicated path using path separators. */
2021-07-21 16:04:18 +01:00
pch = strtok_r ( path_dup , " / " , & state ) ;
2020-04-27 23:37:15 +01:00
if ( ! pch )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " 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
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Loop through all path elements. */
2020-04-27 23:37:15 +01:00
while ( pch )
{
2022-07-06 10:57:31 +01:00
/* Get child directory entry using the current token. */
2020-04-27 23:37:15 +01:00
if ( ! ( dir_entry = romfsGetChildDirectoryEntryByName ( ctx , dir_entry , pch ) ) )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " 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
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Move onto the next token. */
2021-07-21 16:04:18 +01:00
pch = strtok_r ( NULL , " / " , & state ) ;
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +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 ) ;
2022-07-05 02:04:28 +01:00
2020-04-27 23:37:15 +01:00
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 ;
2022-07-05 02:04:28 +01:00
2022-07-12 17:34:49 +01:00
if ( ! romfsIsValidContext ( ctx ) | | ! path | | * path ! = ' / ' )
2020-04-26 09:35:01 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-04-27 23:37:15 +01:00
return NULL ;
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Retrieve path length. */
path_len = strlen ( path ) ;
2020-07-06 01:10:07 +01:00
/* Duplicate path. */
2020-04-27 23:37:15 +01:00
if ( ! ( path_dup = strdup ( path ) ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Unable to duplicate input path! ( \" %s \" ). " , path ) ;
2022-07-06 10:57:31 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
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 - - ;
}
2022-07-05 02:04:28 +01:00
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 , ' / ' ) ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid input path! ( \" %s \" ). " , path ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +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 ' ;
2022-07-05 02:04:28 +01:00
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 ) ) ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " 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
}
2022-07-05 02:04:28 +01:00
2020-07-06 01:10:07 +01:00
/* Retrieve file entry. */
2022-07-12 17:34:49 +01:00
if ( ! ( file_entry = romfsGetChildFileEntryByName ( ctx , dir_entry , filename ) ) ) LOG_MSG_ERROR ( " Failed to retrieve file entry by name for \" %s \" ! ( \" %s \" ). " , filename , path ) ;
2022-07-05 02:04:28 +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 ) ;
2022-07-05 02:04:28 +01:00
2020-04-27 23:37:15 +01:00
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 ;
2022-07-06 10:57:31 +01:00
u64 dir_offset = ROMFS_VOID_ENTRY ;
u32 dir_entries_count = 0 ;
2020-04-27 23:37:15 +01:00
RomFileSystemDirectoryEntry * * dir_entries = NULL , * * tmp_dir_entries = NULL ;
bool success = false ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
if ( ! romfsIsValidContext ( ctx ) | | ! dir_entry | | ( ! dir_entry - > name_length & & dir_entry - > parent_offset ) | | ! out_path | | out_path_size < 2 | | \
2020-05-10 17:40:12 +01:00
illegal_char_replace_type > RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly )
2020-04-27 23:37:15 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-04-27 23:37:15 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Short-circuit: 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 ;
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Allocate memory for our directory entries pointer array. */
2020-04-27 23:37:15 +01:00
dir_entries = calloc ( 1 , sizeof ( RomFileSystemDirectoryEntry * ) ) ;
if ( ! dir_entries )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Unable to allocate memory for directory entries! " ) ;
2022-07-06 10:57:31 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Update stats. */
2020-04-27 23:37:15 +01:00
path_len = ( 1 + dir_entry - > name_length ) ;
* dir_entries = dir_entry ;
dir_entries_count + + ;
2022-07-05 02:04:28 +01:00
2020-04-27 23:37:15 +01:00
while ( true )
{
2022-07-06 10:57:31 +01:00
/* Get parent directory offset. Break out of the loop if we reached the root directory. */
2020-04-27 23:37:15 +01:00
dir_offset = dir_entries [ dir_entries_count - 1 ] - > parent_offset ;
if ( ! dir_offset ) break ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Reallocate directory entries pointer array. */
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
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Unable to reallocate directory entries buffer! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +01:00
2020-04-27 23:37:15 +01:00
dir_entries = tmp_dir_entries ;
tmp_dir_entries = NULL ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Retrieve parent directory entry using the offset we got earlier. */
2020-10-15 01:06:53 +01:00
RomFileSystemDirectoryEntry * * cur_dir_entry = & ( dir_entries [ dir_entries_count ] ) ;
if ( ! ( * cur_dir_entry = romfsGetDirectoryEntryByOffset ( ctx , dir_offset ) ) | | ! ( * cur_dir_entry ) - > name_length )
2020-04-27 23:37:15 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to retrieve directory entry! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Update stats. */
2020-10-15 01:06:53 +01:00
path_len + = ( 1 + ( * cur_dir_entry ) - > name_length ) ;
2020-04-27 23:37:15 +01:00
dir_entries_count + + ;
2020-04-26 09:35:01 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Make sure the output buffer is big enough to hold the full path + NULL terminator. */
2020-04-27 23:37:15 +01:00
if ( path_len > = out_path_size )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Output path length exceeds output buffer size! (%lu >= %lu). " , path_len , out_path_size ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Generate output path, looping through our directory entries pointer array in reverse order. */
2020-04-27 23:37:15 +01:00
* out_path = ' \0 ' ;
2020-10-15 01:06:53 +01:00
path_len = 0 ;
2022-07-05 02:04:28 +01:00
2020-04-27 23:37:15 +01:00
for ( u32 i = dir_entries_count ; i > 0 ; i - - )
{
2022-07-06 10:57:31 +01:00
/* Get current directory entry. */
RomFileSystemDirectoryEntry * cur_dir_entry = dir_entries [ i - 1 ] ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Concatenate path separator and current directory name to the output buffer. */
2020-04-27 23:37:15 +01:00
strcat ( out_path , " / " ) ;
2022-07-06 10:57:31 +01:00
strncat ( out_path , cur_dir_entry - > name , cur_dir_entry - > name_length ) ;
2020-10-15 01:06:53 +01:00
path_len + + ;
2022-07-05 02:04:28 +01:00
2021-06-01 02:12:15 +01:00
if ( illegal_char_replace_type )
{
2022-07-06 10:57:31 +01:00
/* Replace illegal characters within this directory name, then update the full path length. */
2021-06-01 02:12:15 +01:00
utilsReplaceIllegalCharacters ( out_path + path_len , illegal_char_replace_type = = RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly ) ;
path_len + = strlen ( out_path + path_len ) ;
} else {
2022-07-06 10:57:31 +01:00
/* Update full path length. */
path_len + = cur_dir_entry - > name_length ;
2021-06-01 02:12:15 +01:00
}
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Update return value. */
2020-04-27 23:37:15 +01:00
success = true ;
2022-07-05 02:04:28 +01:00
2020-07-13 07:36:17 +01:00
end :
2020-04-27 23:37:15 +01:00
if ( dir_entries ) free ( dir_entries ) ;
2022-07-05 02:04:28 +01:00
2020-04-27 23:37:15 +01:00
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 ;
2022-07-06 10:57:31 +01:00
bool success = false ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
if ( ! romfsIsValidContext ( ctx ) | | ! 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
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-04-27 23:37:15 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
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
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to retrieve RomFS directory path! " ) ;
2022-07-06 10:57:31 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Make sure the output buffer is big enough to hold the full path + NULL terminator. */
2020-04-27 23:37:15 +01:00
path_len = strlen ( out_path ) ;
2022-07-06 10:57:31 +01:00
if ( ( path_len + 1 + file_entry - > name_length ) > = out_path_size )
2020-04-27 23:37:15 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Output path length exceeds output buffer size! (%lu >= %lu). " , path_len + 1 + file_entry - > name_length , out_path_size ) ;
2022-07-06 10:57:31 +01:00
goto end ;
2020-04-27 23:37:15 +01:00
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Concatenate path separator if our parent directory isn't the root directory. */
2020-10-15 01:06:53 +01:00
if ( file_entry - > parent_offset )
{
strcat ( out_path , " / " ) ;
path_len + + ;
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Concatenate file entry name. */
2020-04-27 23:37:15 +01:00
strncat ( out_path , file_entry - > name , file_entry - > name_length ) ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Replace illegal characters within the file name, if needed. */
2020-10-15 01:06:53 +01:00
if ( illegal_char_replace_type ) utilsReplaceIllegalCharacters ( out_path + path_len , illegal_char_replace_type = = RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly ) ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Update return value. */
success = true ;
end :
return success ;
2020-04-26 09:35:01 +01:00
}
2020-04-27 23:37:15 +01:00
2022-07-07 01:30:45 +01:00
bool romfsIsFileEntryUpdated ( RomFileSystemContext * ctx , RomFileSystemFileEntry * file_entry , bool * out )
{
if ( ! romfsIsValidContext ( ctx ) | | ! ctx - > is_patch | | ctx - > default_storage_ctx - > nca_fs_ctx - > section_type ! = NcaFsSectionType_PatchRomFs | | \
! file_entry | | ! file_entry - > size | | ( file_entry - > offset + file_entry - > size ) > ctx - > size | | ! out )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2022-07-07 01:30:45 +01:00
return false ;
}
u64 file_offset = ( ctx - > offset + ctx - > body_offset + file_entry - > offset ) ;
bool success = false ;
/* Short-circuit: check if we're dealing with a Patch RomFS with a missing base RomFS. */
if ( ! ncaStorageIsValidContext ( & ( ctx - > storage_ctx [ 0 ] ) ) )
{
* out = success = true ;
goto end ;
}
/* Check if any sections from this block belong to the Patch storage. */
if ( ! ncaStorageIsBlockWithinPatchStorageRange ( ctx - > default_storage_ctx , file_offset , file_entry - > size , out ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to determine if file entry is within Patch storage range! " ) ;
2022-07-07 01:30:45 +01:00
goto end ;
}
/* Update return value. */
success = true ;
end :
return success ;
}
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 )
{
2022-07-06 10:57:31 +01:00
if ( ! romfsIsValidContext ( ctx ) | | ctx - > is_patch | | ctx - > default_storage_ctx - > base_storage_type ! = NcaStorageBaseStorageType_Regular | | \
( ctx - > default_storage_ctx - > nca_fs_ctx - > section_type ! = NcaFsSectionType_Nca0RomFs & & ctx - > default_storage_ctx - > nca_fs_ctx - > section_type ! = NcaFsSectionType_RomFs ) | | \
2022-07-04 13:30:48 +01:00
! file_entry | | ! file_entry - > size | | ( file_entry - > offset + file_entry - > size ) > ctx - > size | | ! data | | ! data_size | | ( data_offset + data_size ) > file_entry - > size | | ! out )
2020-04-28 09:58:17 +01:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2020-04-28 09:58:17 +01:00
return false ;
}
2022-07-05 02:04:28 +01:00
2022-07-04 13:30:48 +01:00
NcaFsSectionContext * nca_fs_ctx = ctx - > default_storage_ctx - > nca_fs_ctx ;
2020-04-28 09:58:17 +01:00
u64 fs_offset = ( ctx - > body_offset + file_entry - > offset + data_offset ) ;
2022-07-04 01:01:12 +01:00
bool success = false ;
2022-07-05 02:04:28 +01:00
2022-07-04 01:01:12 +01:00
if ( nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs )
2020-04-28 09:58:17 +01:00
{
out - > use_old_format_patch = true ;
2022-07-04 01:01:12 +01:00
success = ncaGenerateHierarchicalSha256Patch ( nca_fs_ctx , data , data_size , fs_offset , & ( out - > old_format_patch ) ) ;
2020-04-28 09:58:17 +01:00
} else {
out - > use_old_format_patch = false ;
2022-07-04 01:01:12 +01:00
success = ncaGenerateHierarchicalIntegrityPatch ( nca_fs_ctx , data , data_size , fs_offset , & ( out - > cur_format_patch ) ) ;
2020-04-28 09:58:17 +01:00
}
2022-07-05 02:04:28 +01:00
2020-10-28 22:48:46 +00:00
out - > written = false ;
2022-07-05 02:04:28 +01:00
2022-07-12 17:34:49 +01:00
if ( ! success ) LOG_MSG_ERROR ( " Failed to generate 0x%lX bytes Hierarchical%s patch at offset 0x%lX for RomFS file entry! " , data_size , \
nca_fs_ctx - > section_type = = NcaFsSectionType_Nca0RomFs ? " Sha256 " : " Integrity " , fs_offset ) ;
2022-07-05 02:04:28 +01:00
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 ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
if ( ! dir_entry | | ( dir_offset = dir_entry - > directory_offset ) = = ROMFS_VOID_ENTRY | | ! name | | ! ( name_len = strlen ( name ) ) )
2021-03-08 11:11:28 +00:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2021-03-08 11:11:28 +00:00
return NULL ;
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Loop through the child directory entries' linked list. */
2020-04-27 23:37:15 +01:00
while ( dir_offset ! = ROMFS_VOID_ENTRY )
{
2022-07-06 10:57:31 +01:00
/* Get current directory entry. */
2021-03-08 11:11:28 +00:00
if ( ! ( child_dir_entry = romfsGetDirectoryEntryByOffset ( ctx , dir_offset ) ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to retrieve directory entry! (0x%lX, 0x%lX). " , dir_offset , ctx - > dir_table_size ) ;
2021-03-08 11:11:28 +00:00
break ;
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Check if we found the right child directory entry. */
2021-03-08 11:11:28 +00:00
/* 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 ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Update current directory entry offset. */
2020-04-27 23:37:15 +01:00
dir_offset = child_dir_entry - > next_offset ;
}
2022-07-05 02:04:28 +01:00
2020-04-27 23:37:15 +01:00
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 ;
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
if ( ! dir_entry | | ( file_offset = dir_entry - > file_offset ) = = ROMFS_VOID_ENTRY | | ! name | | ! ( name_len = strlen ( name ) ) )
2021-03-08 11:11:28 +00:00
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Invalid parameters! " ) ;
2021-03-08 11:11:28 +00:00
return NULL ;
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Loop through the child file entries' linked list. */
2020-04-27 23:37:15 +01:00
while ( file_offset ! = ROMFS_VOID_ENTRY )
{
2022-07-06 10:57:31 +01:00
/* Get current file entry. */
2021-03-08 11:11:28 +00:00
if ( ! ( child_file_entry = romfsGetFileEntryByOffset ( ctx , file_offset ) ) )
{
2022-07-12 17:34:49 +01:00
LOG_MSG_ERROR ( " Failed to retrieve file entry! (0x%lX, 0x%lX). " , file_offset , ctx - > file_table_size ) ;
2021-03-08 11:11:28 +00:00
break ;
}
2022-07-05 02:04:28 +01:00
2022-07-06 10:57:31 +01:00
/* Check if we found the right child file entry. */
2021-03-08 11:11:28 +00:00
/* 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 ;
2022-07-05 02:04:28 +01:00
2020-04-27 23:37:15 +01:00
file_offset = child_file_entry - > next_offset ;
}
2022-07-05 02:04:28 +01:00
2020-04-27 23:37:15 +01:00
return NULL ;
}