From a5857a39360d0441a376a7d7526e54b0f244b7ea Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sat, 4 Mar 2023 12:15:53 +0100 Subject: [PATCH 01/59] Define exiso_warn macro, set 's_warned' --- extract-xiso.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 8279769..d2be0f9 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -423,8 +423,9 @@ -v Print version information and exit.\n\ ", banner, argv[ 0 ], argv[ 0 ] ); -#define exiso_log if ( ! s_quiet ) printf -#define flush() if ( ! s_quiet ) fflush( stdout ) +#define exiso_log(...) if ( ! s_quiet ) { printf(__VA_ARGS__); } +#define exiso_warn(...) if ( ! s_quiet ) { printf(__VA_ARGS__); s_warned = true; } +#define flush() if ( ! s_quiet ) { fflush( stdout ); } #define mem_err() { log_err( __FILE__, __LINE__, "out of memory error\n" ); err = 1; } #define read_err() { log_err( __FILE__, __LINE__, "read error: %s\n", strerror( errno ) ); err = 1; } @@ -630,7 +631,7 @@ static bool s_real_quiet = false; static bool s_media_enable = true; static xoff_t s_total_bytes_all_isos = 0; static int s_total_files_all_isos = 0; -static bool s_warned = 0; +static bool s_warned = false; static bool s_remove_systemupdate = false; static char *s_systemupdate = "$SystemUpdate"; @@ -1677,7 +1678,7 @@ int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { size = min(in_file->file_size - i, READWRITE_BUFFER_SIZE); } while (i < in_file->file_size && read_size > 0); if (!err && i < in_file->file_size) { - exiso_log("\nWARNING: File %s is truncated. Reported size: %u bytes, read size: %u bytes!", in_file->filename, in_file->file_size, i); + exiso_warn("\nWARNING: File %s is truncated. Reported size: %u bytes, read size: %u bytes!", in_file->filename, in_file->file_size, i); in_file->file_size = i; } } @@ -1826,7 +1827,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep exiso_log(err ? "failed\n" : "[OK]\n"); if (!err && i != in_avl->file_size) { - exiso_log("WARNING: File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!\n", in_avl->filename, i, in_avl->file_size); + exiso_warn("WARNING: File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!\n", in_avl->filename, i, in_avl->file_size); } if (!err) { From 90f09452576f52e74b0c53f682666af8f833e9cc Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sat, 4 Mar 2023 17:51:52 +0100 Subject: [PATCH 02/59] Rewrite traverse_xiso() to use recursion In the past it was rewritten to avoid recursion because of some stack overflows. I think it's unlikely that the recursion was the real problem, and the code was impossible to read and understand. --- extract-xiso.c | 306 ++++++++++++++++++++----------------------------- 1 file changed, 127 insertions(+), 179 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index d2be0f9..50cdfa0 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -525,18 +525,11 @@ typedef struct create_list create_list; typedef struct dir_node_avl dir_node_avl; struct dir_node { - dir_node *left; - dir_node *parent; - dir_node_avl *avl_node; - - char *filename; - - uint16_t r_offset; - uint8_t attributes; - uint8_t filename_length; - uint32_t file_size; uint32_t start_sector; + uint8_t attributes; + uint8_t filename_length; + char* filename; }; struct dir_node_avl { @@ -596,9 +589,10 @@ int boyer_moore_init( char *in_pattern, long in_pat_len, long in_alphabet_size ) int free_dir_node_avl( void *in_dir_node_avl, void *, long ); int extract_file( int in_xiso, dir_node *in_file, modes in_mode, char *path ); -int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path, bool in_ll_compat ); +int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ); int verify_xiso( int in_xiso, int32_t *out_root_dir_sector, int32_t *out_root_dir_size, char *in_iso_name ); -int traverse_xiso( int in_xiso, dir_node *in_dir_node, xoff_t in_dir_start, char *in_path, modes in_mode, dir_node_avl **in_root, bool in_ll_compat ); +int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, char* in_path, modes in_mode, dir_node_avl** in_root); +int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_node_avl** in_root); int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ); FILE_TIME *alloc_filetime_now( void ); @@ -817,13 +811,13 @@ int main( int argc, char **argv ) { if ( err ) { err = 0; free( buf ); continue; } } - if ( ! err ) err = decode_xiso( buf, path, k_rewrite, &new_iso_path, true ); + if ( ! err ) err = decode_xiso( buf, path, k_rewrite, &new_iso_path ); if ( ! err && delete && unlink( buf ) == -1 ) log_err( __FILE__, __LINE__, "unable to delete %s\n", buf ); if ( buf ) free( buf ); } else { // the order of the mutually exclusive options here is important, the extract ? k_extract : k_list test *must* be the final comparison - if ( ! err ) err = decode_xiso( argv[ i ], path, extract ? k_extract : k_list, nil, ! optimized ); + if ( ! err ) err = decode_xiso( argv[ i ], path, extract ? k_extract : k_list, nil ); } } } @@ -1096,7 +1090,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av } -int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path, bool in_ll_compat ) { +int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ) { dir_node_avl *root = nil; bool repair = false; int32_t root_dir_sect, root_dir_size; @@ -1107,16 +1101,16 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if ( ! err ) { len = (int) strlen( in_xiso ); - + if ( in_mode == k_rewrite ) { in_xiso[ len -= 4 ] = 0; repair = true; } - + for ( name = &in_xiso[ len ]; name >= in_xiso && *name != PATH_CHAR; --name ) ; ++name; - + len = (int) strlen( name ); - + // create a directory of the same name as the file we are working on, minus the ".iso" portion if (len > 4 && strcasecmp(&name[len - 4], ".iso") == 0) { name[ len -= 4 ] = 0; @@ -1124,7 +1118,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat name[ len ] = '.'; } } - + if ( ! err && ! len ) misc_err( "invalid xiso image name: %s\n", in_xiso, 0, 0 ); if ( ! err && in_mode == k_extract && in_path ) { @@ -1147,7 +1141,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat } } } - + if ( ! err && root_dir_sect && root_dir_size ) { if ( in_path ) { path_len = (int) strlen( in_path ); @@ -1159,17 +1153,16 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if ( ! err ) { sprintf( buf, "%s%s%s%c", in_path ? in_path : "", add_slash && ( ! in_path ) ? PATH_CHAR_STR : "", in_mode != k_list && ( ! in_path ) ? iso_name : "", PATH_CHAR ); + if (!err && lseek(xiso, (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); + if ( in_mode == k_rewrite ) { - - if ( ! err && lseek( xiso, (xoff_t) root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET ) == -1 ) seek_err(); - if ( ! err ) err = traverse_xiso( xiso, nil, (xoff_t) root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, buf, k_generate_avl, &root, in_ll_compat ); - if ( ! err ) err = create_xiso( iso_name, in_path, root, xiso, out_iso_path, nil, nil ); - - } else { - if ( ! err && lseek( xiso, (xoff_t) root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET ) == -1) seek_err(); - if ( ! err ) err = traverse_xiso( xiso, nil, (xoff_t) root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, buf, in_mode, nil, in_ll_compat ); + if (!err) err = traverse_xiso(xiso, (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, 0, buf, k_generate_avl, &root); + if (!err) err = create_xiso( iso_name, in_path, root, xiso, out_iso_path, nil, nil ); } - + else { + if (!err) err = traverse_xiso(xiso, (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, 0, buf, in_mode, nil); + } + free( buf ); } } @@ -1178,7 +1171,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if ( err ) misc_err( "failed to %s xbox iso image %s\n", in_mode == k_rewrite ? "rewrite" : in_mode == k_extract ? "extract" : "list", name, 0 ); if ( xiso != -1 ) close( xiso ); - + if ( short_name ) free( short_name ); if ( cwd ) { chdir( cwd ); @@ -1191,188 +1184,143 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat } -int traverse_xiso( int in_xiso, dir_node *in_dir_node, xoff_t in_dir_start, char *in_path, modes in_mode, dir_node_avl **in_root, bool in_ll_compat ) { - dir_node_avl *avl; - char *path; - xoff_t curpos; - dir_node subdir; - dir_node *dir, node; - int err = 0, sector; - uint16_t l_offset = 0, tmp; - - if ( in_dir_node == nil ) in_dir_node = &node; - - memset( dir = in_dir_node, 0, sizeof(dir_node) ); - -read_entry: - - if ( ! err && read( in_xiso, &tmp, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) read_err(); - - if ( ! err ) { - if ( tmp == XISO_PAD_SHORT ) { - if ( l_offset == 0 ) { // Directory is empty - if (in_mode == k_generate_avl) { - avl_insert(in_root, EMPTY_SUBDIRECTORY); - } - goto end_traverse; - } +int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, char* in_path, modes in_mode, dir_node_avl** in_root) { + dir_node_avl* avl = nil; + dir_node* node = nil; + uint16_t l_offset, r_offset; + int err = 0; - l_offset = l_offset * XISO_DWORD_SIZE + ( XISO_SECTOR_SIZE - ( l_offset * XISO_DWORD_SIZE ) % XISO_SECTOR_SIZE ); - err = lseek( in_xiso, in_dir_start + (xoff_t) l_offset, SEEK_SET ) == -1 ? 1 : 0; + if (lseek(in_xiso, in_dir_start + (xoff_t)entry_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); - if ( ! err ) goto read_entry; // me and my silly comments - } else { - l_offset = tmp; + if (!err && read(in_xiso, &l_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); + if (!err && l_offset == XISO_PAD_SHORT) { + if (entry_offset == 0) { // Empty directory + if (in_mode == k_generate_avl) err = (avl_insert(in_root, EMPTY_SUBDIRECTORY) == k_avl_error); + } + else { + exiso_warn("WARNING: Invalid node found and skipped!\n"); } + return err; } - if ( ! err && read( in_xiso, &dir->r_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) read_err(); - if ( ! err && read( in_xiso, &dir->start_sector, XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) read_err(); - if ( ! err && read( in_xiso, &dir->file_size, XISO_FILESIZE_SIZE ) != XISO_FILESIZE_SIZE ) read_err(); - if ( ! err && read( in_xiso, &dir->attributes, XISO_ATTRIBUTES_SIZE ) != XISO_ATTRIBUTES_SIZE ) read_err(); - if ( ! err && read( in_xiso, &dir->filename_length, XISO_FILENAME_LENGTH_SIZE ) != XISO_FILENAME_LENGTH_SIZE ) read_err(); + // Read node + if (!err) if (!(node = calloc(1, sizeof(dir_node)))) mem_err(); + if (!err && read(in_xiso, &r_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); + if (!err && read(in_xiso, &node->start_sector, XISO_SECTOR_OFFSET_SIZE) != XISO_SECTOR_OFFSET_SIZE) read_err(); + if (!err && read(in_xiso, &node->file_size, XISO_FILESIZE_SIZE) != XISO_FILESIZE_SIZE) read_err(); + if (!err && read(in_xiso, &node->attributes, XISO_ATTRIBUTES_SIZE) != XISO_ATTRIBUTES_SIZE) read_err(); + if (!err && read(in_xiso, &node->filename_length, XISO_FILENAME_LENGTH_SIZE) != XISO_FILENAME_LENGTH_SIZE) read_err(); + + if (!err) { + little16(l_offset); + little16(r_offset); + little32(node->file_size); + little32(node->start_sector); + + if ((node->filename = (char*)malloc(node->filename_length + 1)) == nil) mem_err(); + } - if ( ! err ) { - little16( l_offset ); - little16( dir->r_offset ); - little32( dir->file_size ); - little32( dir->start_sector ); + if (!err) { + if (read(in_xiso, node->filename, node->filename_length) != node->filename_length) read_err(); + if (!err) { + node->filename[node->filename_length] = 0; - if ( ( dir->filename = (char *) malloc( dir->filename_length + 1 ) ) == nil ) mem_err(); - } - - if ( ! err ) { - if ( read( in_xiso, dir->filename, dir->filename_length ) != dir->filename_length ) read_err(); - if ( ! err ) { - dir->filename[ dir->filename_length ] = 0; - // security patch (Chris Bainbridge), modified by in to support "...", etc. 02.14.06 (in) - if ( ! strcmp( dir->filename, "." ) || ! strcmp( dir->filename, ".." ) || strchr( dir->filename, '/' ) || strchr( dir->filename, '\\' ) ) { - log_err( __FILE__, __LINE__, "filename '%s' contains invalid character(s), aborting.", dir->filename ); - exit( 1 ); + if (!strcmp(node->filename, ".") || !strcmp(node->filename, "..") || strchr(node->filename, '/') || strchr(node->filename, '\\')) { + log_err(__FILE__, __LINE__, "filename '%s' contains invalid character(s), aborting.", node->filename); + exit(1); } } } - - if ( ! err && in_mode == k_generate_avl ) { - if ( ( avl = (dir_node_avl *) malloc( sizeof(dir_node_avl) ) ) == nil ) mem_err(); - if ( ! err ) { - memset( avl, 0, sizeof(dir_node_avl) ); - - if ( ( avl->filename = strdup( dir->filename ) ) == nil ) mem_err(); + + // Insert node in tree + if (!err && in_mode == k_generate_avl) { + if ((avl = (dir_node_avl*)calloc(1, sizeof(dir_node_avl))) == nil) mem_err(); + if (!err) if ((avl->filename = strdup(node->filename)) == nil) mem_err(); + if (!err) { + avl->file_size = node->file_size; + avl->old_start_sector = node->start_sector; + if (avl_insert(in_root, avl) == k_avl_error) misc_err("this iso appears to be corrupt\n", 0, 0, 0); } - if ( ! err ) { - dir->avl_node = avl; + } - avl->file_size = dir->file_size; - avl->old_start_sector = dir->start_sector; + // Process the node, according to mode + if (!err) err = process_node(in_xiso, node, in_path, in_mode, (in_mode == k_generate_avl) ? &avl->subdirectory : nil); - if ( avl_insert( in_root, avl ) == k_avl_error ) misc_err( "this iso appears to be corrupt\n", 0, 0, 0 ); - } + // Free memory before recurring + if (node->filename) free(node->filename); + if (node) free(node); + + // Repeat on left node + if (!err && l_offset) { + if (!err) if (lseek(in_xiso, in_dir_start + (xoff_t)l_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); + if (!err) err = traverse_xiso(in_xiso, in_dir_start, l_offset, in_path, in_mode, &avl); } - if ( ! err && l_offset ) { - in_ll_compat = false; - - if ( ( dir->left = (dir_node *) malloc( sizeof(dir_node) ) ) == nil ) mem_err(); - if ( ! err ) { - memset( dir->left, 0, sizeof(dir_node) ); - if ( lseek( in_xiso, in_dir_start + (xoff_t) l_offset * XISO_DWORD_SIZE, SEEK_SET ) == -1 ) seek_err(); - } - if ( ! err ) { - dir->left->parent = dir; - dir = dir->left; - - goto read_entry; - } + // Repeat on right node + if (!err && r_offset) { + if (!err) if (lseek(in_xiso, in_dir_start + (xoff_t)r_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); + if (!err) err = traverse_xiso(in_xiso, in_dir_start, r_offset, in_path, in_mode, &avl); } -left_processed: - - if ( dir->left ) { free( dir->left ); dir->left = nil; } + return err; +} - if ( ! err && ( curpos = lseek( in_xiso, 0, SEEK_CUR ) ) == -1 ) seek_err(); - - if ( ! err ) { - if ( dir->attributes & XISO_ATTRIBUTE_DIR ) { - if ( in_path ) { - if ( ( path = (char *) malloc( strlen( in_path ) + dir->filename_length + 2 ) ) == nil ) mem_err(); - - if ( ! err ) { - sprintf( path, "%s%s%c", in_path, dir->filename, PATH_CHAR ); - if ( lseek( in_xiso, (xoff_t) dir->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET ) == -1 ) seek_err(); - } - } else path = nil; - - if ( ! err ) { - if ( !s_remove_systemupdate || !strstr( dir->filename, s_systemupdate ) ) - { - if ( in_mode == k_extract ) { - if ( ( err = mkdir( dir->filename, 0755 ) ) ) mkdir_err( dir->filename ); - if ( ! err && ( err = chdir( dir->filename ) ) ) chdir_err( dir->filename ); +int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_node_avl** in_root) { + char* path = nil; + int err = 0; + + if (node->attributes & XISO_ATTRIBUTE_DIR) { // Process directory + + if (!err) if (lseek(in_xiso, (xoff_t)node->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); + + if (!err) { + if (!s_remove_systemupdate || !strstr(node->filename, s_systemupdate)) + { + if (in_mode == k_extract) { + if ((err = mkdir(node->filename, 0755))) mkdir_err(node->filename); + if (!err && (err = chdir(node->filename))) chdir_err(node->filename); } - if( ! err && in_mode != k_generate_avl ) { - exiso_log("%s%s%s%s (0 bytes)%s", in_mode == k_extract ? "creating " : "", in_path, dir->filename, PATH_CHAR_STR, in_mode == k_extract ? " [OK]" : ""); flush(); + if (!err && in_mode != k_generate_avl) { + exiso_log("%s%s%s%s (0 bytes)%s", in_mode == k_extract ? "creating " : "", in_path, node->filename, PATH_CHAR_STR, in_mode == k_extract ? " [OK]" : ""); flush(); exiso_log("\n"); } } - } - - if ( ! err ) { - memcpy( &subdir, dir, sizeof(dir_node) ); - - subdir.parent = nil; - if ( ! err && dir->file_size > 0 ) err = traverse_xiso( in_xiso, &subdir, (xoff_t) dir->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, path, in_mode, in_mode == k_generate_avl ? &dir->avl_node->subdirectory : nil, in_ll_compat ); + } - if ( !s_remove_systemupdate || !strstr( dir->filename, s_systemupdate ) ) - { - - if ( ! err && in_mode == k_extract && ( err = chdir( ".." ) ) ) chdir_err( ".." ); - } + if (!err) { + // Recurse on subdirectory + if (in_path) if (asprintf(&path, "%s%s%c", in_path, node->filename, PATH_CHAR) == -1) mem_err(); + if (!err && node->file_size > 0) err = traverse_xiso(in_xiso, (xoff_t)node->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, 0, path, in_mode, in_root); + + if (!s_remove_systemupdate || !strstr(node->filename, s_systemupdate)) + { + if (!err && in_mode == k_extract && (err = chdir(".."))) chdir_err(".."); } - - if ( path ) free( path ); - } else if ( in_mode != k_generate_avl ) { - if ( ! err ) { - if ( !s_remove_systemupdate || !strstr( in_path, s_systemupdate ) ) - { + } - if ( in_mode == k_extract ) { - err = extract_file( in_xiso, dir, in_mode, in_path ); - } else { - exiso_log( "%s%s%s (%u bytes)%s", in_mode == k_extract ? "extracting " : "", in_path, dir->filename, dir->file_size , "" ); flush(); - exiso_log( "\n" ); + if (path) free(path); + } + else if (in_mode != k_generate_avl) { // Write file + if (!err) { + if (!s_remove_systemupdate || !strstr(in_path, s_systemupdate)) + { + if (in_mode == k_extract) { + err = extract_file(in_xiso, node, in_mode, in_path); + } + else { + exiso_log("%s%s (%u bytes)", in_path, node->filename, node->file_size); flush(); + exiso_log("\n"); } ++s_total_files; ++s_total_files_all_isos; - s_total_bytes += dir->file_size; - s_total_bytes_all_isos += dir->file_size; - } + s_total_bytes += node->file_size; + s_total_bytes_all_isos += node->file_size; } } } - - if ( ! err && dir->r_offset ) { - // compatibility for iso's built as linked lists (bleh!) - if ( in_ll_compat && (xoff_t) dir->r_offset * XISO_DWORD_SIZE / XISO_SECTOR_SIZE > ( sector = (int) (( curpos - in_dir_start ) / XISO_SECTOR_SIZE )) ) dir->r_offset = sector * ( XISO_SECTOR_SIZE / XISO_DWORD_SIZE ) + ( XISO_SECTOR_SIZE / XISO_DWORD_SIZE ); - - if ( ! err && lseek( in_xiso, in_dir_start + (xoff_t) dir->r_offset * XISO_DWORD_SIZE, SEEK_SET ) == -1 ) seek_err(); - if ( ! err ) { - if ( dir->filename ) { free( dir->filename ); dir->filename = nil; } - l_offset = dir->r_offset; - - goto read_entry; - } - } - -end_traverse: - - if ( dir->filename ) free( dir->filename ); - - if ( ( dir = dir->parent ) ) goto left_processed; - return err; } From 01f8bb12c62201e41f4b311f95769ae802605f63 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sat, 4 Mar 2023 18:02:48 +0100 Subject: [PATCH 03/59] Fix some warnings Add one decimal place when showing file percentage --- extract-xiso.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 50cdfa0..54f6a7a 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -334,7 +334,7 @@ #include "win32/asprintf.c" #endif #define lseek _lseeki64 - #define mkdir( a, b ) mkdir( a ) + #define mkdir( a, b ) _mkdir( (a) ) typedef __int32 int32_t; typedef __int64 xoff_t; @@ -598,7 +598,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av FILE_TIME *alloc_filetime_now( void ); int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ); int generate_avl_tree_remote( dir_node_avl **out_root, int *io_n ); -int write_directory( dir_node_avl *in_avl, int in_xiso, int in_depth ); +int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int in_depth ); int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ); int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ); int calculate_total_files_and_bytes( dir_node_avl *in_avl, void *in_context, int in_depth ); @@ -1058,9 +1058,12 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av } if ( ! err && ( pos = lseek( xiso, (xoff_t) 0, SEEK_END ) ) == -1 ) seek_err(); - if ( ! err && write( xiso, buf, i = (int) (( XISO_FILE_MODULUS - pos % XISO_FILE_MODULUS ) % XISO_FILE_MODULUS) ) != i ) write_err(); + if (!err) { + i = (int)((XISO_FILE_MODULUS - pos % XISO_FILE_MODULUS) % XISO_FILE_MODULUS); + if (write(xiso, buf, i) != i) write_err(); + } - if ( ! err ) err = write_volume_descriptors( xiso, ( pos + (xoff_t) i ) / XISO_SECTOR_SIZE ); + if ( ! err ) err = write_volume_descriptors( xiso, (uint32_t)((pos + (xoff_t)i) / XISO_SECTOR_SIZE) ); if ( ! err && lseek( xiso, (xoff_t) XISO_OPTIMIZED_TAG_OFFSET, SEEK_SET ) == -1 ) seek_err(); if ( ! err && write( xiso, XISO_OPTIMIZED_TAG, XISO_OPTIMIZED_TAG_LENGTH ) != XISO_OPTIMIZED_TAG_LENGTH ) write_err(); @@ -1123,7 +1126,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if ( ! err && in_mode == k_extract && in_path ) { if ( ( cwd = getcwd( nil, 0 ) ) == nil ) mem_err(); - if ( ! err && mkdir( in_path, 0755 ) ); + if ( ! err && mkdir( in_path, 0755 ) == -1 ) mkdir_err( in_path ); if ( ! err && chdir( in_path ) == -1 ) chdir_err( in_path ); } @@ -1587,7 +1590,8 @@ char *boyer_moore_search( char *in_text, long in_text_len ) { int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { int err = 0; bool warn = false; - uint32_t i, size, read_size, totalsize = 0, totalpercent = 0; + uint32_t i, size, read_size, totalsize = 0; + float totalpercent = 0.0f; int out; if ( s_remove_systemupdate && strstr( path, s_systemupdate ) ){ @@ -1619,8 +1623,8 @@ int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { } } totalsize += read_size; - totalpercent = (totalsize * 100.0) / in_file->file_size; - exiso_log("%s%s%s (%u bytes) [%u%%]%s\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename, in_file->file_size, totalpercent, ""); + totalpercent = (totalsize * 100.0f) / in_file->file_size; + exiso_log("%s%s%s (%u bytes) [%.1f%%]%s\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename, in_file->file_size, totalpercent, ""); i += read_size; size = min(in_file->file_size - i, READWRITE_BUFFER_SIZE); @@ -1679,7 +1683,7 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep if ( ! err ) err = avl_traverse_depth_first( in_avl->subdirectory, (traversal_callback) write_tree, &context, k_prefix, 0 ); if (!err && lseek(in_context->xiso, (xoff_t)in_avl->start_sector * XISO_SECTOR_SIZE, SEEK_SET) == -1) seek_err(); - if (!err) err = avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)write_directory, (void*)in_context->xiso, k_prefix, 0); + if (!err) err = avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)write_directory, in_context, k_prefix, 0); if (!err && (pos = lseek(in_context->xiso, 0, SEEK_CUR)) == -1) seek_err(); if (!err && (pad = (int)((XISO_SECTOR_SIZE - (pos % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE))) { memset(sector, XISO_PAD_BYTE, pad); @@ -1742,7 +1746,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep } bytes -= n; if (s_media_enable && (len = strlen(in_avl->filename)) >= 4 && strcasecmp(&in_avl->filename[len - 4], ".xbe") == 0) { - for (buf[n += i] = 0, p = buf; (p = boyer_moore_search(p, n - (p - buf))) != nil; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; + for (buf[n += i] = 0, p = buf; (p = boyer_moore_search(p, n - (long)(p - buf))) != nil; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; if (bytes) { i = XISO_MEDIA_ENABLE_LENGTH - 1; if (write(in_context->xiso, buf, n - i) != (int)n - i) { @@ -1793,7 +1797,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep } -int write_directory( dir_node_avl *in_avl, int in_xiso, int in_depth ) { +int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int in_depth ) { xoff_t pos; int err = 0, pad; uint16_t l_offset, r_offset; @@ -1811,15 +1815,15 @@ int write_directory( dir_node_avl *in_avl, int in_xiso, int in_depth ) { memset( sector, XISO_PAD_BYTE, XISO_SECTOR_SIZE ); - if ( ( pos = lseek( in_xiso, 0, SEEK_CUR ) ) == -1 ) seek_err(); - if ( ! err && ( pad = (int) ( (xoff_t) in_avl->offset + in_avl->dir_start - pos ) ) && write( in_xiso, sector, pad ) != pad ) write_err(); - if ( ! err && write( in_xiso, &l_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err(); - if ( ! err && write( in_xiso, &r_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err(); - if ( ! err && write( in_xiso, &in_avl->start_sector, XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) write_err(); - if ( ! err && write( in_xiso, &file_size, XISO_FILESIZE_SIZE ) != XISO_FILESIZE_SIZE ) write_err(); - if ( ! err && write( in_xiso, &attributes, XISO_ATTRIBUTES_SIZE ) != XISO_ATTRIBUTES_SIZE ) write_err(); - if ( ! err && write( in_xiso, &length, XISO_FILENAME_LENGTH_SIZE ) != XISO_FILENAME_LENGTH_SIZE ) write_err(); - if ( ! err && write( in_xiso, in_avl->filename, length ) != length ) write_err(); + if ( ( pos = lseek( in_context->xiso, 0, SEEK_CUR ) ) == -1 ) seek_err(); + if ( ! err && ( pad = (int) ( (xoff_t) in_avl->offset + in_avl->dir_start - pos ) ) && write( in_context->xiso, sector, pad ) != pad ) write_err(); + if ( ! err && write( in_context->xiso, &l_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err(); + if ( ! err && write( in_context->xiso, &r_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err(); + if ( ! err && write( in_context->xiso, &in_avl->start_sector, XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) write_err(); + if ( ! err && write( in_context->xiso, &file_size, XISO_FILESIZE_SIZE ) != XISO_FILESIZE_SIZE ) write_err(); + if ( ! err && write( in_context->xiso, &attributes, XISO_ATTRIBUTES_SIZE ) != XISO_ATTRIBUTES_SIZE ) write_err(); + if ( ! err && write( in_context->xiso, &length, XISO_FILENAME_LENGTH_SIZE ) != XISO_FILENAME_LENGTH_SIZE ) write_err(); + if ( ! err && write( in_context->xiso, in_avl->filename, length ) != length ) write_err(); little32( in_avl->start_sector ); little32( in_avl->file_size ); @@ -1894,7 +1898,7 @@ int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, long in_ if ( in_depth == 0 ) *out_size = 0; - length = XISO_FILENAME_OFFSET + strlen( in_avl->filename ); + length = XISO_FILENAME_OFFSET + (uint32_t)strlen( in_avl->filename ); length += ( XISO_DWORD_SIZE - ( length % XISO_DWORD_SIZE ) ) % XISO_DWORD_SIZE; if ( n_sectors( *out_size + length ) > n_sectors( *out_size ) ) { From 0b1804fecac5087ac4dfb787aa0689a766e596de Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sat, 4 Mar 2023 20:08:59 +0100 Subject: [PATCH 04/59] Replace all malloc+sprintf with asprintf --- extract-xiso.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 54f6a7a..071dc27 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -802,11 +802,10 @@ int main( int argc, char **argv ) { exiso_log( "%s is already optimized, skipping...\n", argv[ i ] ); continue; } - - if ( ! err && ( buf = (char *) malloc( strlen( argv[ i ] ) + 5 ) ) == nil ) mem_err(); // + 5 magic number is for ".old\0" + if ( ! err ) { - sprintf( buf, "%s.old", argv[ i ] ); - if ( stat( buf, &sb ) != -1 ) misc_err( "%s already exists, cannot rewrite %s\n", buf, argv[ i ], 0 ); + if (asprintf(&buf, "%s.old", argv[i]) == -1) mem_err(); + if ( ! err && stat( buf, &sb ) != -1 ) misc_err( "%s already exists, cannot rewrite %s\n", buf, argv[ i ], 0 ); if ( ! err && rename( argv[ i ], buf ) == -1 ) misc_err( "cannot rename %s to %s\n", argv[ i ], buf, 0 ); if ( err ) { err = 0; free( buf ); continue; } @@ -1151,10 +1150,8 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if ( in_path[ path_len - 1 ] != PATH_CHAR ) ++add_slash; } - if ( ( buf = (char *) malloc( path_len + add_slash + strlen( iso_name ) + 2 ) ) == nil ) mem_err(); - - if ( ! err ) { - sprintf( buf, "%s%s%s%c", in_path ? in_path : "", add_slash && ( ! in_path ) ? PATH_CHAR_STR : "", in_mode != k_list && ( ! in_path ) ? iso_name : "", PATH_CHAR ); + if (!err) { + if (asprintf(&buf, "%s%s%s%c", in_path ? in_path : "", add_slash && (!in_path) ? PATH_CHAR_STR : "", in_mode != k_list && (!in_path) ? iso_name : "", PATH_CHAR) == -1) mem_err() if (!err && lseek(xiso, (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); @@ -1166,7 +1163,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if (!err) err = traverse_xiso(xiso, (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, 0, buf, in_mode, nil); } - free( buf ); + if(buf) free(buf); } } From c07d0899343bddf2259a9ac17d81b8b7b44b94a7 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sun, 5 Mar 2023 12:31:07 +0100 Subject: [PATCH 05/59] Rewrite path separation to use strrchr and avoid empty for loops --- extract-xiso.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 071dc27..5b5a8f3 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -248,10 +248,11 @@ #include #include #include +#include +#include #include #include #include -#include #if defined( __FREEBSD__ ) || defined( __OPENBSD__ ) #include @@ -751,21 +752,20 @@ int main( int argc, char **argv ) { if ( ! err && create ) { for ( p = create; ! err && p != nil; ) { - char *tmp = nil; - - if ( p->name ) { - for ( i = (int) strlen( p->name ); i >= 0 && p->name[ i ] != PATH_CHAR; --i ) ; ++i; + char* tmp = nil; + ptrdiff_t diff = 0; - if ( i ) { - if ( ( tmp = (char *) malloc( i + 1 ) ) == nil ) mem_err(); - if ( ! err ) { - strncpy( tmp, p->name, i ); - tmp[ i ] = 0; - } + if ( p->name && (tmp = strrchr(p->name, PATH_CHAR)) ) { + diff = tmp - p->name; + if ( ( tmp = (char *) malloc( diff + 1 ) ) == nil ) mem_err(); + if ( ! err ) { + strncpy( tmp, p->name, diff ); + tmp[ diff ] = 0; } + diff += 1; } - if ( ! err ) err = create_xiso( p->path, tmp, nil, -1, nil, p->name ? p->name + i : nil, nil ); + if ( ! err ) err = create_xiso( p->path, tmp, nil, -1, nil, p->name ? p->name + diff : nil, nil ); if ( tmp ) free( tmp ); @@ -949,8 +949,10 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av if ( ! in_root ) { if ( chdir( in_root_directory ) == -1 ) chdir_err( in_root_directory ); if ( ! err ) { - if ( in_root_directory[ i = (int) strlen( in_root_directory ) - 1 ] == '/' || in_root_directory[ i ] == '\\' ) in_root_directory[ i-- ] = 0; - for ( iso_dir = &in_root_directory[ i ]; iso_dir >= in_root_directory && *iso_dir != PATH_CHAR; --iso_dir ) ; ++iso_dir; + i = (int)strlen(in_root_directory) - 1; + if ( in_root_directory[i] == '/' || in_root_directory[i] == '\\' ) in_root_directory[i] = 0; + if ((iso_dir = strrchr(in_root_directory, PATH_CHAR))) iso_dir++; + else iso_dir = in_root_directory; iso_name = in_name ? in_name : iso_dir; } @@ -961,7 +963,8 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av if ( ! err ) { if ( ! *iso_dir ) iso_dir = PATH_CHAR_STR; if ( ! in_output_directory ) in_output_directory = cwd; - if ( in_output_directory[ i = (int) strlen( in_output_directory ) - 1 ] == PATH_CHAR ) in_output_directory[ i-- ] = 0; + i = (int)strlen(in_output_directory) - 1; + if ( in_output_directory[i] == PATH_CHAR ) in_output_directory[i] = 0; if ( ! iso_name || ! *iso_name ) iso_name = "root"; else if ( iso_name[ 1 ] == ':' ) { iso_name[ 1 ] = iso_name[ 0 ]; ++iso_name; } #if defined( _WIN32 ) @@ -1109,7 +1112,8 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat repair = true; } - for ( name = &in_xiso[ len ]; name >= in_xiso && *name != PATH_CHAR; --name ) ; ++name; + if ((name = strrchr(in_xiso, PATH_CHAR))) name++; + else name = in_xiso; len = (int) strlen( name ); From b04abd0dc1d0dd6eb6065bb47f67d59e1e35c61c Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sun, 5 Mar 2023 17:58:13 +0100 Subject: [PATCH 06/59] Move all newlines to beginning of strings --- extract-xiso.c | 119 +++++++++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 58 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 5b5a8f3..13421b4 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -425,23 +425,23 @@ ", banner, argv[ 0 ], argv[ 0 ] ); #define exiso_log(...) if ( ! s_quiet ) { printf(__VA_ARGS__); } -#define exiso_warn(...) if ( ! s_quiet ) { printf(__VA_ARGS__); s_warned = true; } +#define exiso_warn(...) if ( ! s_quiet ) { printf("\nWARNING: " __VA_ARGS__); s_warned = true; } #define flush() if ( ! s_quiet ) { fflush( stdout ); } -#define mem_err() { log_err( __FILE__, __LINE__, "out of memory error\n" ); err = 1; } -#define read_err() { log_err( __FILE__, __LINE__, "read error: %s\n", strerror( errno ) ); err = 1; } -#define seek_err() { log_err( __FILE__, __LINE__, "seek error: %s\n", strerror( errno ) ); err = 1; } -#define write_err() { log_err( __FILE__, __LINE__, "write error: %s\n", strerror( errno ) ); err = 1; } -#define rread_err() { log_err( __FILE__, __LINE__, "unable to read remote file\n" ); err = 1; } -#define rwrite_err() { log_err( __FILE__, __LINE__, "unable to write to remote file\n" ); err = 1; } -#define unknown_err() { log_err( __FILE__, __LINE__, "an unrecoverable error has occurred\n" ); err = 1; } -#define open_err( in_file ) { log_err( __FILE__, __LINE__, "open error: %s %s\n", ( in_file ), strerror( errno ) ); err = 1; } -#define chdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to change to directory %s: %s\n", ( in_dir ), strerror( errno ) ); err = 1; } -#define mkdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to create directory %s: %s\n", ( in_dir ), strerror( errno ) ); err = 1; } -#define ropen_err( in_file ) { log_err( __FILE__, __LINE__, "unable to open remote file %s\n", ( in_file ) ); err = 1; } -#define rchdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to change to remote directory %s\n", ( in_dir ) ); err = 1; } -#define rmkdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to create remote directory %s\n", ( in_dir ) ); err = 1; } -#define misc_err( in_format, a, b, c ) { log_err( __FILE__, __LINE__, ( in_format ), ( a ), ( b ), ( c ) ); err = 1; } +#define mem_err() { log_err( __FILE__, __LINE__, "out of memory error" ); err = 1; } +#define read_err() { log_err( __FILE__, __LINE__, "read error: %s", strerror( errno ) ); err = 1; } +#define seek_err() { log_err( __FILE__, __LINE__, "seek error: %s", strerror( errno ) ); err = 1; } +#define write_err() { log_err( __FILE__, __LINE__, "write error: %s", strerror( errno ) ); err = 1; } +#define rread_err() { log_err( __FILE__, __LINE__, "unable to read remote file" ); err = 1; } +#define rwrite_err() { log_err( __FILE__, __LINE__, "unable to write to remote file" ); err = 1; } +#define unknown_err() { log_err( __FILE__, __LINE__, "an unrecoverable error has occurred" ); err = 1; } +#define open_err( in_file ) { log_err( __FILE__, __LINE__, "open error: %s %s", ( in_file ), strerror( errno ) ); err = 1; } +#define chdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to change to directory %s: %s", ( in_dir ), strerror( errno ) ); err = 1; } +#define mkdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to create directory %s: %s", ( in_dir ), strerror( errno ) ); err = 1; } +#define ropen_err( in_file ) { log_err( __FILE__, __LINE__, "unable to open remote file %s", ( in_file ) ); err = 1; } +#define rchdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to change to remote directory %s", ( in_dir ) ); err = 1; } +#define rmkdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to create remote directory %s", ( in_dir ) ); err = 1; } +#define misc_err( ... ) { log_err( __FILE__, __LINE__, __VA_ARGS__ ); err = 1; } #ifndef min @@ -779,7 +779,6 @@ int main( int argc, char **argv ) { } } else for ( i = optind; ! err && i < argc; ++i ) { ++isos; - exiso_log( "\n" ); s_total_bytes = s_total_files = 0; @@ -799,19 +798,19 @@ int main( int argc, char **argv ) { if ( rewrite ) { if ( optimized ) { - exiso_log( "%s is already optimized, skipping...\n", argv[ i ] ); + exiso_log( "\n%s is already optimized, skipping...\n", argv[ i ] ); continue; } if ( ! err ) { if (asprintf(&buf, "%s.old", argv[i]) == -1) mem_err(); - if ( ! err && stat( buf, &sb ) != -1 ) misc_err( "%s already exists, cannot rewrite %s\n", buf, argv[ i ], 0 ); - if ( ! err && rename( argv[ i ], buf ) == -1 ) misc_err( "cannot rename %s to %s\n", argv[ i ], buf, 0 ); + if ( ! err && stat( buf, &sb ) != -1 ) misc_err( "%s already exists, cannot rewrite %s", buf, argv[ i ] ); + if ( ! err && rename( argv[ i ], buf ) == -1 ) misc_err( "cannot rename %s to %s", argv[ i ], buf ); if ( err ) { err = 0; free( buf ); continue; } } if ( ! err ) err = decode_xiso( buf, path, k_rewrite, &new_iso_path ); - if ( ! err && delete && unlink( buf ) == -1 ) log_err( __FILE__, __LINE__, "unable to delete %s\n", buf ); + if ( ! err && delete && unlink( buf ) == -1 ) log_err( __FILE__, __LINE__, "unable to delete %s", buf ); if ( buf ) free( buf ); } else { @@ -821,7 +820,7 @@ int main( int argc, char **argv ) { } } - if ( ! err ) exiso_log( "\n%u files in %s total %lld bytes\n", s_total_files, rewrite ? new_iso_path : argv[ i ], (long long int) s_total_bytes ); + if ( ! err ) exiso_log( "\n\n%u files in %s total %lld bytes\n", s_total_files, rewrite ? new_iso_path : argv[ i ], (long long int) s_total_bytes ); if ( new_iso_path ) { if ( ! err ) exiso_log( "\n%s successfully rewritten%s%s\n", argv[ i ], path ? " as " : ".", path ? new_iso_path : "" ); @@ -834,7 +833,7 @@ int main( int argc, char **argv ) { } if ( ! err && isos > 1 ) exiso_log( "\n%u files in %u xiso's total %lld bytes\n", s_total_files_all_isos, isos, (long long int) s_total_bytes_all_isos ); - if ( s_warned ) exiso_log( "\nWARNING: Warning(s) were issued during execution--review stderr!\n" ); + if ( s_warned ) exiso_warn( "Warning(s) were issued during execution--review stderr!\n" ); boyer_moore_done(); @@ -845,26 +844,33 @@ int main( int argc, char **argv ) { } -int log_err( const char *in_file, int in_line, const char *in_format, ... ) { +int log_err(const char* in_file, int in_line, const char* in_format, ...) { va_list ap; - char *format; + char *format; int ret; #if DEBUG - asprintf( &format, "%s:%u %s", in_file, in_line, in_format ); + asprintf(&format, "%s:%u %s", in_file, in_line, in_format); #else - format = (char *) in_format; + format = (char*)in_format; #endif - - if ( s_real_quiet ) ret = 0; + + if (s_real_quiet) { + ret = 0; + } + else if(format){ + va_start(ap, in_format); + fprintf(stderr, "\n"); + ret = vfprintf(stderr, format, ap); + fprintf(stderr, "\n"); + va_end(ap); + } else { - va_start( ap, in_format ); - ret = vfprintf( stderr, format, ap ); - va_end( ap ); + ret = 1; } #if DEBUG - free( format ); + if(format) free(format); #endif return ret; @@ -894,7 +900,7 @@ int verify_xiso( int in_xiso, int32_t *out_root_dir_sector, int32_t *out_root_di { if (lseek(in_xiso, (xoff_t)XISO_HEADER_OFFSET + XGD1_LSEEK_OFFSET, SEEK_SET) == -1) seek_err(); if (!err && read(in_xiso, buffer, XISO_HEADER_DATA_LENGTH) != XISO_HEADER_DATA_LENGTH) read_err(); - if (!err && memcmp(buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH)) misc_err("%s does not appear to be a valid xbox iso image\n", in_iso_name, 0, 0) + if (!err && memcmp(buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH)) misc_err("%s does not appear to be a valid xbox iso image", in_iso_name) else s_xbox_disc_lseek = XGD1_LSEEK_OFFSET; } else s_xbox_disc_lseek = XGD3_LSEEK_OFFSET; @@ -913,12 +919,12 @@ int verify_xiso( int in_xiso, int32_t *out_root_dir_sector, int32_t *out_root_di // seek to header tail and verify media tag if ( ! err && lseek( in_xiso, (xoff_t) XISO_FILETIME_SIZE + XISO_UNUSED_SIZE, SEEK_CUR ) == -1 ) seek_err(); if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err(); - if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) ) misc_err( "%s appears to be corrupt\n", in_iso_name, 0, 0 ); + if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) ) misc_err( "%s appears to be corrupt", in_iso_name ); // seek to root directory sector if ( ! err ) { if ( ! *out_root_dir_sector && ! *out_root_dir_size ) { - exiso_log( "xbox image %s contains no files.\n", in_iso_name ); + exiso_log( "\nxbox image %s contains no files.\n", in_iso_name ); err = err_iso_no_files; } else { if ( lseek( in_xiso, (xoff_t) *out_root_dir_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err(); @@ -974,7 +980,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av #endif } if ( ! err ) { - exiso_log( "%s %s%s:\n\n", in_root ? "rewriting" : "\ncreating", iso_name, in_name ? "" : ".iso" ); + exiso_log( "\n%s %s%s:\n", in_root ? "rewriting" : "creating", iso_name, in_name ? "" : ".iso" ); root.start_sector = XISO_ROOT_DIRECTORY_SECTOR; @@ -986,7 +992,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av } else { int i, n = 0; - exiso_log( "generating avl tree from %sfilesystem: ", "" ); flush(); + exiso_log("\ngenerating avl tree from filesystem: "); flush(); err = generate_avl_tree_local( &root.subdirectory, &n ); @@ -994,7 +1000,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av for ( i = 0; i < n; ++i ) exiso_log( " " ); for ( i = 0; i < n; ++i ) exiso_log( "\b" ); - exiso_log( "%s\n\n", err ? "failed!" : "[OK]" ); + exiso_log( "%s\n", err ? "failed!" : "[OK]" ); } } if ( ! err && in_progress_callback ) (*in_progress_callback)( 0, s_total_bytes ); @@ -1125,7 +1131,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat } } - if ( ! err && ! len ) misc_err( "invalid xiso image name: %s\n", in_xiso, 0, 0 ); + if ( ! err && ! len ) misc_err( "invalid xiso image name: %s", in_xiso ); if ( ! err && in_mode == k_extract && in_path ) { if ( ( cwd = getcwd( nil, 0 ) ) == nil ) mem_err(); @@ -1138,7 +1144,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat iso_name = short_name ? short_name : name; if ( ! err && in_mode != k_rewrite ) { - exiso_log( "%s %s:\n\n", in_mode == k_extract ? "extracting" : "listing", name ); + exiso_log( "\n%s %s:\n", in_mode == k_extract ? "extracting" : "listing", name ); if ( in_mode == k_extract ) { if ( ! in_path ) { @@ -1172,7 +1178,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat } if ( err == err_iso_rewritten ) err = 0; - if ( err ) misc_err( "failed to %s xbox iso image %s\n", in_mode == k_rewrite ? "rewrite" : in_mode == k_extract ? "extract" : "list", name, 0 ); + if ( err ) misc_err( "failed to %s xbox iso image %s", in_mode == k_rewrite ? "rewrite" : in_mode == k_extract ? "extract" : "list", name ); if ( xiso != -1 ) close( xiso ); @@ -1202,7 +1208,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, char* if (in_mode == k_generate_avl) err = (avl_insert(in_root, EMPTY_SUBDIRECTORY) == k_avl_error); } else { - exiso_warn("WARNING: Invalid node found and skipped!\n"); + exiso_warn("Invalid node found and skipped!"); } return err; } @@ -1244,7 +1250,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, char* if (!err) { avl->file_size = node->file_size; avl->old_start_sector = node->start_sector; - if (avl_insert(in_root, avl) == k_avl_error) misc_err("this iso appears to be corrupt\n", 0, 0, 0); + if (avl_insert(in_root, avl) == k_avl_error) misc_err("this iso appears to be corrupt"); } } @@ -1286,8 +1292,7 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ if (!err && (err = chdir(node->filename))) chdir_err(node->filename); } if (!err && in_mode != k_generate_avl) { - exiso_log("%s%s%s%s (0 bytes)%s", in_mode == k_extract ? "creating " : "", in_path, node->filename, PATH_CHAR_STR, in_mode == k_extract ? " [OK]" : ""); flush(); - exiso_log("\n"); + exiso_log("\n%s%s%s%s (0 bytes)%s", in_mode == k_extract ? "creating " : "", in_path, node->filename, PATH_CHAR_STR, in_mode == k_extract ? " [OK]" : ""); flush(); } } } @@ -1313,8 +1318,7 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ err = extract_file(in_xiso, node, in_mode, in_path); } else { - exiso_log("%s%s (%u bytes)", in_path, node->filename, node->file_size); flush(); - exiso_log("\n"); + exiso_log("\n%s%s (%u bytes)", in_path, node->filename, node->file_size); flush(); } ++s_total_files; @@ -1606,8 +1610,9 @@ int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { if ( ! err && lseek( in_xiso, (xoff_t) in_file->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET ) == -1 ) seek_err(); if ( ! err ) { + exiso_log("\n"); if (in_file->file_size == 0) { - exiso_log("%s%s%s (0 bytes) [100%%]%s\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename, ""); + exiso_log("%s%s%s (0 bytes) [100%%]\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename); } else { i = 0; @@ -1625,13 +1630,13 @@ int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { } totalsize += read_size; totalpercent = (totalsize * 100.0f) / in_file->file_size; - exiso_log("%s%s%s (%u bytes) [%.1f%%]%s\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename, in_file->file_size, totalpercent, ""); + exiso_log("%s%s%s (%u bytes) [%.1f%%]\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename, in_file->file_size, totalpercent); i += read_size; size = min(in_file->file_size - i, READWRITE_BUFFER_SIZE); } while (i < in_file->file_size && read_size > 0); if (!err && i < in_file->file_size) { - exiso_warn("\nWARNING: File %s is truncated. Reported size: %u bytes, read size: %u bytes!", in_file->filename, in_file->file_size, i); + exiso_warn("File %s is truncated. Reported size: %u bytes, read size: %u bytes!", in_file->filename, in_file->file_size, i); in_file->file_size = i; } } @@ -1639,8 +1644,6 @@ int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { } } - if ( ! err ) exiso_log( "\n" ); - return err; } @@ -1668,7 +1671,7 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep else { if ( asprintf( &context.path, "%c", PATH_CHAR ) == -1 ) mem_err(); } if ( ! err ) { - exiso_log( "adding %s (0 bytes) [OK]\n", context.path ); + exiso_log( "\nadding %s (0 bytes) [OK]", context.path ); if ( in_avl->subdirectory != EMPTY_SUBDIRECTORY ) { context.xiso = in_context->xiso; @@ -1727,7 +1730,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep } if ( ! err ) { - exiso_log( "adding %s%s (%u bytes) ", in_context->path, in_avl->filename, in_avl->file_size ); flush(); + exiso_log( "\nadding %s%s (%u bytes) ", in_context->path, in_avl->filename, in_avl->file_size ); flush(); i = 0; bytes = in_avl->file_size; @@ -1777,10 +1780,10 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep memset(buf, XISO_PAD_BYTE, bytes); if (write(in_context->xiso, buf, bytes) != (int)bytes) write_err(); } - exiso_log(err ? "failed\n" : "[OK]\n"); + exiso_log(err ? "failed" : "[OK]"); if (!err && i != in_avl->file_size) { - exiso_warn("WARNING: File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!\n", in_avl->filename, i, in_avl->file_size); + exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", in_avl->filename, i, in_avl->file_size); } if (!err) { @@ -1951,7 +1954,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { } else if ( S_ISREG( sb.st_mode ) ) { empty_dir = false; if ( sb.st_size > ULONG_MAX ) { - log_err( __FILE__, __LINE__, "file %s is too large for xiso, skipping...\n", avl->filename ); + log_err( __FILE__, __LINE__, "file %s is too large for xiso, skipping...", avl->filename ); free( avl->filename ); free( avl ); continue; @@ -1965,7 +1968,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { } } if ( ! err ) { - if ( avl_insert( out_root, avl ) == k_avl_error ) misc_err( "error inserting file %s into tree (duplicate filename?)\n", avl->filename, 0, 0 ); + if ( avl_insert( out_root, avl ) == k_avl_error ) misc_err( "error inserting file %s into tree (duplicate filename?)", avl->filename ); } else { if ( avl ) { if ( avl->filename ) free( avl->filename ); From 2e81f675c29e7371bce9ab80c291d0ef12762f21 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Mon, 6 Mar 2023 00:24:37 +0100 Subject: [PATCH 07/59] Fix: don't count empty subdirectories as files --- extract-xiso.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 13421b4..ccf3e26 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -1872,13 +1872,14 @@ int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io int calculate_total_files_and_bytes( dir_node_avl *in_avl, void *in_context, int in_depth ) { - if ( in_avl->subdirectory && in_avl->subdirectory != EMPTY_SUBDIRECTORY ) { - avl_traverse_depth_first( in_avl->subdirectory, (traversal_callback) calculate_total_files_and_bytes, nil, k_prefix, 0 ); + if (in_avl->subdirectory) { + if (in_avl->subdirectory != EMPTY_SUBDIRECTORY) { + avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_total_files_and_bytes, nil, k_prefix, 0); + } } else { ++s_total_files; s_total_bytes += in_avl->file_size; } - return 0; } From 093f36a1b09ce73598498fbcecf8151e904bc820 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Mon, 6 Mar 2023 00:59:15 +0100 Subject: [PATCH 08/59] Fix memory leak in write_tree --- extract-xiso.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index ccf3e26..87d8c5a 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -1184,7 +1184,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if ( short_name ) free( short_name ); if ( cwd ) { - chdir( cwd ); + if (chdir(cwd) == -1) chdir_err(cwd); free( cwd ); } @@ -1697,13 +1697,13 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep if ( ! err && in_context->from == -1 ) { if ( chdir( ".." ) == -1 ) chdir_err( ".." ); } - - if ( context.path ) free( context.path ); } else { memset(sector, XISO_PAD_BYTE, XISO_SECTOR_SIZE); if ((pos = lseek(in_context->xiso, in_avl->start_sector * XISO_SECTOR_SIZE, SEEK_SET)) == -1) seek_err(); if (!err && write(in_context->xiso, sector, XISO_SECTOR_SIZE) != XISO_SECTOR_SIZE) write_err(); } + + if (context.path) free(context.path); } } From c14ddce226b596947790ef5d2548fc4a996f7a98 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Mon, 6 Mar 2023 09:46:50 +0100 Subject: [PATCH 09/59] Check before free --- extract-xiso.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 87d8c5a..8200c5c 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -807,7 +807,7 @@ int main( int argc, char **argv ) { if ( ! err && stat( buf, &sb ) != -1 ) misc_err( "%s already exists, cannot rewrite %s", buf, argv[ i ] ); if ( ! err && rename( argv[ i ], buf ) == -1 ) misc_err( "cannot rename %s to %s", argv[ i ], buf ); - if ( err ) { err = 0; free( buf ); continue; } + if ( err ) { err = 0; if ( buf ) free( buf ); continue; } } if ( ! err ) err = decode_xiso( buf, path, k_rewrite, &new_iso_path ); if ( ! err && delete && unlink( buf ) == -1 ) log_err( __FILE__, __LINE__, "unable to delete %s", buf ); @@ -1017,8 +1017,11 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av if ( ! err && ( buf = (char *) malloc( n = max( READWRITE_BUFFER_SIZE, XISO_HEADER_OFFSET ) ) ) == nil ) mem_err(); if ( ! err ) { if ( ( xiso = open( xiso_path, WRITEFLAGS, 0644 ) ) == -1 ) open_err( xiso_path ); - if ( out_iso_path ) *out_iso_path = xiso_path; - else free( xiso_path ); + if (out_iso_path) *out_iso_path = xiso_path; + else { + free(xiso_path); + xiso_path = nil; + } } if ( ! err ) { memset( buf, 0, n ); @@ -1085,7 +1088,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av if ( xiso != -1 ) { close( xiso ); - if ( err ) unlink( xiso_path ); + if (err && xiso_path) unlink(xiso_path); } if ( root.filename ) free( root.filename ); @@ -1214,7 +1217,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, char* } // Read node - if (!err) if (!(node = calloc(1, sizeof(dir_node)))) mem_err(); + if (!err) if ((node = calloc(1, sizeof(dir_node))) == nil) mem_err(); if (!err && read(in_xiso, &r_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); if (!err && read(in_xiso, &node->start_sector, XISO_SECTOR_OFFSET_SIZE) != XISO_SECTOR_OFFSET_SIZE) read_err(); if (!err && read(in_xiso, &node->file_size, XISO_FILESIZE_SIZE) != XISO_FILESIZE_SIZE) read_err(); @@ -1258,8 +1261,10 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, char* if (!err) err = process_node(in_xiso, node, in_path, in_mode, (in_mode == k_generate_avl) ? &avl->subdirectory : nil); // Free memory before recurring - if (node->filename) free(node->filename); - if (node) free(node); + if (node) { + if (node->filename) free(node->filename); + free(node); + } // Repeat on left node if (!err && l_offset) { From 4759c86fc182f99b62922b509c12171da5be4733 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Mon, 6 Mar 2023 12:51:12 +0100 Subject: [PATCH 10/59] Add new strategy to list files in directory Discover files not in tree in rewrite mode --- extract-xiso.c | 207 +++++++++++++++++++++++++++++-------------------- 1 file changed, 122 insertions(+), 85 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 8200c5c..a5678c0 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -500,6 +500,8 @@ #define XISO_MEDIA_ENABLE_LENGTH 8 #define XISO_MEDIA_ENABLE_BYTE_POS 7 +#define n_dword(offset) ( (offset) / XISO_DWORD_SIZE + ( (offset) % XISO_DWORD_SIZE ? 1 : 0 ) ) + #define EMPTY_SUBDIRECTORY ( (dir_node_avl *) 1 ) #define READWRITE_BUFFER_SIZE 0x00200000 @@ -517,6 +519,7 @@ typedef enum bm_constants { k_default_alphabet_size = 256 } bm_constants; typedef enum modes { k_generate_avl, k_extract, k_list, k_rewrite } modes; typedef enum errors { err_end_of_sector = -5001, err_iso_rewritten = -5002, err_iso_no_files = -5003 } errors; +typedef enum strategies { tree_strategy, discover_strategy } strategies; typedef void (*progress_callback)( xoff_t in_current_value, xoff_t in_final_value ); typedef int (*traversal_callback)( void *in_node, void *in_context, long in_depth ); @@ -592,8 +595,8 @@ int free_dir_node_avl( void *in_dir_node_avl, void *, long ); int extract_file( int in_xiso, dir_node *in_file, modes in_mode, char *path ); int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ); int verify_xiso( int in_xiso, int32_t *out_root_dir_sector, int32_t *out_root_dir_size, char *in_iso_name ); -int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, char* in_path, modes in_mode, dir_node_avl** in_root); -int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_node_avl** in_root); +int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); +int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ); FILE_TIME *alloc_filetime_now( void ); @@ -1107,7 +1110,9 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ) { dir_node_avl *root = nil; bool repair = false; + xoff_t root_dir_start; int32_t root_dir_sect, root_dir_size; + uint16_t root_end_offset; int xiso, err = 0, len, path_len = 0, add_slash = 0; char *buf, *cwd = nil, *name = nil, *short_name = nil, *iso_name, *folder = nil; @@ -1166,14 +1171,18 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if (!err) { if (asprintf(&buf, "%s%s%s%c", in_path ? in_path : "", add_slash && (!in_path) ? PATH_CHAR_STR : "", in_mode != k_list && (!in_path) ? iso_name : "", PATH_CHAR) == -1) mem_err() - if (!err && lseek(xiso, (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); + root_dir_start = (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek; + root_end_offset = n_sectors(root_dir_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE; + if (!err && lseek(xiso, root_dir_start, SEEK_SET) == -1) seek_err(); + if ( in_mode == k_rewrite ) { - if (!err) err = traverse_xiso(xiso, (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, 0, buf, k_generate_avl, &root); + if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, k_generate_avl, &root, tree_strategy); + if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, k_generate_avl, &root, discover_strategy); if (!err) err = create_xiso( iso_name, in_path, root, xiso, out_iso_path, nil, nil ); } else { - if (!err) err = traverse_xiso(xiso, (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek, 0, buf, in_mode, nil); + if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, in_mode, nil, discover_strategy); } if(buf) free(buf); @@ -1197,97 +1206,122 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat } -int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, char* in_path, modes in_mode, dir_node_avl** in_root) { - dir_node_avl* avl = nil; - dir_node* node = nil; - uint16_t l_offset, r_offset; +int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { + dir_node_avl *avl = nil; + dir_node *node = nil; + uint16_t l_offset = 0, r_offset = 0; int err = 0; - if (lseek(in_xiso, in_dir_start + (xoff_t)entry_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); + if (entry_offset >= end_offset) misc_err("attempt to read node entry beyond directory end"); - if (!err && read(in_xiso, &l_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); - if (!err && l_offset == XISO_PAD_SHORT) { - if (entry_offset == 0) { // Empty directory - if (in_mode == k_generate_avl) err = (avl_insert(in_root, EMPTY_SUBDIRECTORY) == k_avl_error); - } - else { - exiso_warn("Invalid node found and skipped!"); + do { + if (!err && lseek(in_xiso, in_dir_start + (xoff_t)entry_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); + + if (!err && read(in_xiso, &l_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); + if (!err && l_offset == XISO_PAD_SHORT) { + if (entry_offset == 0) { // Empty directories have padding starting at the beginning + if (in_mode == k_generate_avl) err = (avl_insert(in_root, EMPTY_SUBDIRECTORY) == k_avl_error); + return err; // Done + } + else if (strategy != discover_strategy) { // When discovering, the padding means end of sector + exiso_warn("Invalid node found and skipped!"); // When not discovering, the padding means a bad entry, skip it without failing + return err; // We're done if not discovering + } + // We're discovering, so set the offset to the start of the next sector + if (!err) entry_offset = n_sectors(entry_offset * XISO_DWORD_SIZE) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE; + continue; } - return err; - } - // Read node - if (!err) if ((node = calloc(1, sizeof(dir_node))) == nil) mem_err(); - if (!err && read(in_xiso, &r_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); - if (!err && read(in_xiso, &node->start_sector, XISO_SECTOR_OFFSET_SIZE) != XISO_SECTOR_OFFSET_SIZE) read_err(); - if (!err && read(in_xiso, &node->file_size, XISO_FILESIZE_SIZE) != XISO_FILESIZE_SIZE) read_err(); - if (!err && read(in_xiso, &node->attributes, XISO_ATTRIBUTES_SIZE) != XISO_ATTRIBUTES_SIZE) read_err(); - if (!err && read(in_xiso, &node->filename_length, XISO_FILENAME_LENGTH_SIZE) != XISO_FILENAME_LENGTH_SIZE) read_err(); + // Read node + if (!err) if ((node = calloc(1, sizeof(dir_node))) == nil) mem_err(); + if (!err && read(in_xiso, &r_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); + if (!err && read(in_xiso, &node->start_sector, XISO_SECTOR_OFFSET_SIZE) != XISO_SECTOR_OFFSET_SIZE) read_err(); + if (!err && read(in_xiso, &node->file_size, XISO_FILESIZE_SIZE) != XISO_FILESIZE_SIZE) read_err(); + if (!err && read(in_xiso, &node->attributes, XISO_ATTRIBUTES_SIZE) != XISO_ATTRIBUTES_SIZE) read_err(); + if (!err && read(in_xiso, &node->filename_length, XISO_FILENAME_LENGTH_SIZE) != XISO_FILENAME_LENGTH_SIZE) read_err(); - if (!err) { - little16(l_offset); - little16(r_offset); - little32(node->file_size); - little32(node->start_sector); + if (!err && (entry_offset * XISO_DWORD_SIZE + XISO_FILENAME_OFFSET + node->filename_length) > (end_offset * XISO_DWORD_SIZE)) misc_err("node entry spans beyond directory end"); - if ((node->filename = (char*)malloc(node->filename_length + 1)) == nil) mem_err(); - } + if (!err) { + little16(l_offset); + little16(r_offset); + little32(node->file_size); + little32(node->start_sector); + + if ((node->filename = (char*)malloc(node->filename_length + 1)) == nil) mem_err(); + } - if (!err) { - if (read(in_xiso, node->filename, node->filename_length) != node->filename_length) read_err(); if (!err) { - node->filename[node->filename_length] = 0; + if (read(in_xiso, node->filename, node->filename_length) != node->filename_length) read_err(); + if (!err) { + node->filename[node->filename_length] = 0; - // security patch (Chris Bainbridge), modified by in to support "...", etc. 02.14.06 (in) - if (!strcmp(node->filename, ".") || !strcmp(node->filename, "..") || strchr(node->filename, '/') || strchr(node->filename, '\\')) { - log_err(__FILE__, __LINE__, "filename '%s' contains invalid character(s), aborting.", node->filename); - exit(1); + // security patch (Chris Bainbridge), modified by in to support "...", etc. 02.14.06 (in) + if (!strcmp(node->filename, ".") || !strcmp(node->filename, "..") || strchr(node->filename, '/') || strchr(node->filename, '\\')) { + log_err(__FILE__, __LINE__, "filename '%s' contains invalid character(s), aborting.", node->filename); + exit(1); + } } } - } - // Insert node in tree - if (!err && in_mode == k_generate_avl) { - if ((avl = (dir_node_avl*)calloc(1, sizeof(dir_node_avl))) == nil) mem_err(); - if (!err) if ((avl->filename = strdup(node->filename)) == nil) mem_err(); + // Process the node according to the mode if (!err) { - avl->file_size = node->file_size; - avl->old_start_sector = node->start_sector; - if (avl_insert(in_root, avl) == k_avl_error) misc_err("this iso appears to be corrupt"); + if (in_mode == k_generate_avl) { + if ((avl = (dir_node_avl*)calloc(1, sizeof(dir_node_avl))) == nil) mem_err(); + if (!err) if ((avl->filename = strdup(node->filename)) == nil) mem_err(); + if (!err) { + avl->file_size = node->file_size; + avl->old_start_sector = node->start_sector; + if (avl_insert(in_root, avl) == k_avl_error) { // Insert node in tree + // If we're discovering files outside trees, we don't care about avl_insert errors, + // since they represent nodes already discovered before, and we don't want to process them again + if (strategy != discover_strategy) misc_err("this iso appears to be corrupt"); + } + else err = process_node(in_xiso, node, in_path, in_mode, &avl->subdirectory, strategy); + } + } + else { + err = process_node(in_xiso, node, in_path, in_mode, nil, strategy); + } } - } - // Process the node, according to mode - if (!err) err = process_node(in_xiso, node, in_path, in_mode, (in_mode == k_generate_avl) ? &avl->subdirectory : nil); + // Save next offset for discovery + if (!err) entry_offset = n_dword(entry_offset * XISO_DWORD_SIZE + XISO_FILENAME_OFFSET + node->filename_length); - // Free memory before recurring - if (node) { - if (node->filename) free(node->filename); - free(node); - } + // Free memory before recurring or iterating + if (node) { + if (node->filename) free(node->filename); + free(node); + } - // Repeat on left node - if (!err && l_offset) { - if (!err) if (lseek(in_xiso, in_dir_start + (xoff_t)l_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); - if (!err) err = traverse_xiso(in_xiso, in_dir_start, l_offset, in_path, in_mode, &avl); - } + } while (!err && entry_offset < end_offset && strategy == discover_strategy); // Iterate only if using discover_strategy + + if (strategy != discover_strategy) { + // Recurse on left node + if (!err && l_offset) { + if (lseek(in_xiso, in_dir_start + (xoff_t)l_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); + if (!err) err = traverse_xiso(in_xiso, in_dir_start, l_offset, end_offset, in_path, in_mode, &avl, strategy); + } - // Repeat on right node - if (!err && r_offset) { - if (!err) if (lseek(in_xiso, in_dir_start + (xoff_t)r_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); - if (!err) err = traverse_xiso(in_xiso, in_dir_start, r_offset, in_path, in_mode, &avl); + // Recurse on right node + if (!err && r_offset) { + if (lseek(in_xiso, in_dir_start + (xoff_t)r_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); + if (!err) err = traverse_xiso(in_xiso, in_dir_start, r_offset, end_offset, in_path, in_mode, &avl, strategy); + } } return err; } -int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_node_avl** in_root) { - char* path = nil; - int err = 0; +int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { + char *path = nil; + int err = 0; + xoff_t dir_start = (xoff_t)node->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; + uint16_t end_offset; if (node->attributes & XISO_ATTRIBUTE_DIR) { // Process directory - if (!err) if (lseek(in_xiso, (xoff_t)node->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); + if (!err) if (lseek(in_xiso, dir_start, SEEK_SET) == -1) seek_err(); if (!err) { if (!s_remove_systemupdate || !strstr(node->filename, s_systemupdate)) @@ -1304,16 +1338,19 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ if (!err) { // Recurse on subdirectory - if (in_path) if (asprintf(&path, "%s%s%c", in_path, node->filename, PATH_CHAR) == -1) mem_err(); - if (!err && node->file_size > 0) err = traverse_xiso(in_xiso, (xoff_t)node->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, 0, path, in_mode, in_root); + if (!err && node->file_size > 0) { + if (in_path) if (asprintf(&path, "%s%s%c", in_path, node->filename, PATH_CHAR) == -1) mem_err(); + end_offset = n_sectors(node->file_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE; + err = traverse_xiso(in_xiso, dir_start, 0, end_offset, path, in_mode, in_root, strategy); + if (path) free(path); + } if (!s_remove_systemupdate || !strstr(node->filename, s_systemupdate)) { if (!err && in_mode == k_extract && (err = chdir(".."))) chdir_err(".."); } } - - if (path) free(path); + } else if (in_mode != k_generate_avl) { // Write file if (!err) { @@ -1600,19 +1637,17 @@ char *boyer_moore_search( char *in_text, long in_text_len ) { int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { int err = 0; bool warn = false; + xoff_t file_start = (xoff_t)in_file->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; uint32_t i, size, read_size, totalsize = 0; float totalpercent = 0.0f; int out; - if ( s_remove_systemupdate && strstr( path, s_systemupdate ) ){ - if ( ! err && lseek( in_xiso, (xoff_t) in_file->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET ) == -1 ) seek_err(); - } - else { + if (lseek(in_xiso, file_start, SEEK_SET) == -1) seek_err(); + + if ( !s_remove_systemupdate || !strstr( path, s_systemupdate ) ) { if ( in_mode == k_extract ) { - if ( ( out = open( in_file->filename, WRITEFLAGS, 0644 ) ) == -1 ) open_err( in_file->filename ); + if (!err && (out = open(in_file->filename, WRITEFLAGS, 0644)) == -1) open_err(in_file->filename); } else err = 1; - - if ( ! err && lseek( in_xiso, (xoff_t) in_file->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET ) == -1 ) seek_err(); if ( ! err ) { exiso_log("\n"); @@ -1807,11 +1842,13 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int in_depth ) { - xoff_t pos; - int err = 0, pad; - uint16_t l_offset, r_offset; - uint32_t file_size = in_avl->file_size + (in_avl->subdirectory ? (XISO_SECTOR_SIZE - (in_avl->file_size % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE : 0); - char length = (char) strlen( in_avl->filename ), attributes = in_avl->subdirectory ? XISO_ATTRIBUTE_DIR : XISO_ATTRIBUTE_ARC, sector[ XISO_SECTOR_SIZE ]; + xoff_t pos; + int err = 0, pad; + uint16_t l_offset, r_offset; + uint32_t file_size = in_avl->file_size + (in_avl->subdirectory ? (XISO_SECTOR_SIZE - (in_avl->file_size % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE : 0); + char length = (char)strlen(in_avl->filename); + char attributes = in_avl->subdirectory ? XISO_ATTRIBUTE_DIR : XISO_ATTRIBUTE_ARC; + char sector[XISO_SECTOR_SIZE]; little32( in_avl->file_size ); little32( in_avl->start_sector ); From b9a36ea18d1b6b1710c9a5b0a2de10cb469ecc9a Mon Sep 17 00:00:00 2001 From: rapperskull Date: Mon, 6 Mar 2023 20:22:28 +0100 Subject: [PATCH 11/59] Many fixes for directories with size 0 Fix rewriting of ISOs with empty root Allow root directory to be in sector 0 Don't give error in case of empty ISO, just rewrite a new empty one --- extract-xiso.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index a5678c0..0525cb7 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -925,14 +925,7 @@ int verify_xiso( int in_xiso, int32_t *out_root_dir_sector, int32_t *out_root_di if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) ) misc_err( "%s appears to be corrupt", in_iso_name ); // seek to root directory sector - if ( ! err ) { - if ( ! *out_root_dir_sector && ! *out_root_dir_size ) { - exiso_log( "\nxbox image %s contains no files.\n", in_iso_name ); - err = err_iso_no_files; - } else { - if ( lseek( in_xiso, (xoff_t) *out_root_dir_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err(); - } - } + if (!err && lseek(in_xiso, (xoff_t)*out_root_dir_sector * XISO_SECTOR_SIZE, SEEK_SET) == -1) seek_err(); return err; } @@ -991,7 +984,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av if ( in_root ) { root.subdirectory = in_root; - avl_traverse_depth_first( in_root, (traversal_callback) calculate_total_files_and_bytes, nil, k_prefix, 0 ); + avl_traverse_depth_first( &root, (traversal_callback) calculate_total_files_and_bytes, nil, k_prefix, 0 ); } else { int i, n = 0; @@ -1162,7 +1155,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat } } - if ( ! err && root_dir_sect && root_dir_size ) { + if ( ! err ) { if ( in_path ) { path_len = (int) strlen( in_path ); if ( in_path[ path_len - 1 ] != PATH_CHAR ) ++add_slash; @@ -1177,12 +1170,15 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if (!err && lseek(xiso, root_dir_start, SEEK_SET) == -1) seek_err(); if ( in_mode == k_rewrite ) { - if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, k_generate_avl, &root, tree_strategy); - if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, k_generate_avl, &root, discover_strategy); - if (!err) err = create_xiso( iso_name, in_path, root, xiso, out_iso_path, nil, nil ); + if (!err && root_dir_size == 0) root = EMPTY_SUBDIRECTORY; + else { + if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, k_generate_avl, &root, tree_strategy); + if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, k_generate_avl, &root, discover_strategy); + } + if (!err) err = create_xiso(iso_name, in_path, root, xiso, out_iso_path, nil, nil); } else { - if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, in_mode, nil, discover_strategy); + if (!err && root_dir_size != 0) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, in_mode, nil, discover_strategy); } if(buf) free(buf); @@ -1220,7 +1216,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 if (!err && read(in_xiso, &l_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); if (!err && l_offset == XISO_PAD_SHORT) { if (entry_offset == 0) { // Empty directories have padding starting at the beginning - if (in_mode == k_generate_avl) err = (avl_insert(in_root, EMPTY_SUBDIRECTORY) == k_avl_error); + if (in_mode == k_generate_avl) *in_root = EMPTY_SUBDIRECTORY; return err; // Done } else if (strategy != discover_strategy) { // When discovering, the padding means end of sector @@ -1338,10 +1334,15 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ if (!err) { // Recurse on subdirectory - if (!err && node->file_size > 0) { - if (in_path) if (asprintf(&path, "%s%s%c", in_path, node->filename, PATH_CHAR) == -1) mem_err(); - end_offset = n_sectors(node->file_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE; - err = traverse_xiso(in_xiso, dir_start, 0, end_offset, path, in_mode, in_root, strategy); + if (node->file_size == 0) { + if (in_mode == k_generate_avl) *in_root = EMPTY_SUBDIRECTORY; + } + else { + if (in_path && asprintf(&path, "%s%s%c", in_path, node->filename, PATH_CHAR) == -1) mem_err(); + if (!err) { + end_offset = n_sectors(node->file_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE; + err = traverse_xiso(in_xiso, dir_start, 0, end_offset, path, in_mode, in_root, strategy); + } if (path) free(path); } From 2fda995672ccc79bce7058bf4340c17e6bafbe44 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Mon, 6 Mar 2023 20:25:03 +0100 Subject: [PATCH 12/59] Fix integer overflow in write_tree --- extract-xiso.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 0525cb7..188192a 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -1704,8 +1704,9 @@ int free_dir_node_avl( void *in_dir_node_avl, void *in_context, long in_depth ) int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ) { xoff_t pos; write_tree_context context; + xoff_t dir_start = (xoff_t)in_avl->start_sector * XISO_SECTOR_SIZE; int err = 0, pad; - char sector[ XISO_SECTOR_SIZE ]; + char sector[XISO_SECTOR_SIZE]; if ( in_avl->subdirectory ) { if ( in_context->path ) { if ( asprintf( &context.path, "%s%s%c", in_context->path, in_avl->filename, PATH_CHAR ) == -1 ) mem_err(); } @@ -1727,7 +1728,7 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep if ( ! err ) err = avl_traverse_depth_first( in_avl->subdirectory, (traversal_callback) write_file, &context, k_prefix, 0 ); if ( ! err ) err = avl_traverse_depth_first( in_avl->subdirectory, (traversal_callback) write_tree, &context, k_prefix, 0 ); - if (!err && lseek(in_context->xiso, (xoff_t)in_avl->start_sector * XISO_SECTOR_SIZE, SEEK_SET) == -1) seek_err(); + if (!err && lseek(in_context->xiso, dir_start, SEEK_SET) == -1) seek_err(); if (!err) err = avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)write_directory, in_context, k_prefix, 0); if (!err && (pos = lseek(in_context->xiso, 0, SEEK_CUR)) == -1) seek_err(); if (!err && (pad = (int)((XISO_SECTOR_SIZE - (pos % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE))) { @@ -1740,7 +1741,7 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep } } else { memset(sector, XISO_PAD_BYTE, XISO_SECTOR_SIZE); - if ((pos = lseek(in_context->xiso, in_avl->start_sector * XISO_SECTOR_SIZE, SEEK_SET)) == -1) seek_err(); + if ((pos = lseek(in_context->xiso, dir_start, SEEK_SET)) == -1) seek_err(); if (!err && write(in_context->xiso, sector, XISO_SECTOR_SIZE) != XISO_SECTOR_SIZE) write_err(); } From 54375af5a4d77bbdff59951e0314d6b48e84ebca Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 7 Mar 2023 15:48:55 +0100 Subject: [PATCH 13/59] Various changes for legibility Fix some warinings and possible integer overflows --- extract-xiso.c | 74 ++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 188192a..1e2fc99 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -858,9 +858,7 @@ int log_err(const char* in_file, int in_line, const char* in_format, ...) { format = (char*)in_format; #endif - if (s_real_quiet) { - ret = 0; - } + if (s_real_quiet) ret = 0; else if(format){ va_start(ap, in_format); fprintf(stderr, "\n"); @@ -868,9 +866,7 @@ int log_err(const char* in_file, int in_line, const char* in_format, ...) { fprintf(stderr, "\n"); va_end(ap); } - else { - ret = 1; - } + else ret = 1; #if DEBUG if(format) free(format); @@ -937,7 +933,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av xoff_t pos; dir_node_avl root; FILE_TIME *ft = nil; - write_tree_context wt_context; + write_tree_context wt_context = { 0 }; uint32_t start_sector; int i, n, xiso = -1, err = 0; char *cwd = nil, *buf = nil, *iso_name, *xiso_path, *iso_dir; @@ -1244,7 +1240,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 little32(node->file_size); little32(node->start_sector); - if ((node->filename = (char*)malloc(node->filename_length + 1)) == nil) mem_err(); + if ((node->filename = (char*)malloc((size_t)node->filename_length + 1)) == nil) mem_err(); } if (!err) { @@ -1357,9 +1353,7 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ if (!err) { if (!s_remove_systemupdate || !strstr(in_path, s_systemupdate)) { - if (in_mode == k_extract) { - err = extract_file(in_xiso, node, in_mode, in_path); - } + if (in_mode == k_extract) err = extract_file(in_xiso, node, in_mode, in_path); else { exiso_log("\n%s%s (%u bytes)", in_path, node->filename, node->file_size); flush(); } @@ -1703,7 +1697,7 @@ int free_dir_node_avl( void *in_dir_node_avl, void *in_context, long in_depth ) int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ) { xoff_t pos; - write_tree_context context; + write_tree_context context = { 0 }; xoff_t dir_start = (xoff_t)in_avl->start_sector * XISO_SECTOR_SIZE; int err = 0, pad; char sector[XISO_SECTOR_SIZE]; @@ -1731,7 +1725,8 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep if (!err && lseek(in_context->xiso, dir_start, SEEK_SET) == -1) seek_err(); if (!err) err = avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)write_directory, in_context, k_prefix, 0); if (!err && (pos = lseek(in_context->xiso, 0, SEEK_CUR)) == -1) seek_err(); - if (!err && (pad = (int)((XISO_SECTOR_SIZE - (pos % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE))) { + if (!err) { + pad = (int)((XISO_SECTOR_SIZE - (pos % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE); memset(sector, XISO_PAD_BYTE, pad); if (write(in_context->xiso, sector, pad) != pad) write_err(); } @@ -1755,14 +1750,14 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ) { char *buf, *p; - uint32_t bytes, n, size; + uint32_t bytes, n, size = max(XISO_SECTOR_SIZE, READWRITE_BUFFER_SIZE); int err = 0, fd = -1, i; size_t len; if ( ! in_avl->subdirectory ) { if ( lseek( in_context->xiso, (xoff_t) in_avl->start_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err(); - if ( ! err && ( buf = (char *) malloc( ( size = max( XISO_SECTOR_SIZE, READWRITE_BUFFER_SIZE ) ) + 1 ) ) == nil ) mem_err(); + if ( ! err && ( buf = (char *) malloc( (size_t)size + 1 ) ) == nil ) mem_err(); if ( ! err ) { if ( in_context->from == -1 ) { if ( ( fd = open( in_avl->filename, READFLAGS, 0 ) ) == -1 ) open_err( in_avl->filename ); @@ -1776,56 +1771,56 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep i = 0; bytes = in_avl->file_size; + len = strlen(in_avl->filename); do { - if ((int)(n = read(fd, buf + i, min(bytes, size - i))) < 0) { + n = read(fd, buf + i, min(bytes, size - i)); + if ((signed)n < 0) { read_err(); break; } - if (n == 0) { - if (i) { - if (write(in_context->xiso, buf, i) != i) { - write_err(); - break; - } - } + else if (n == 0) { // End of file + if (i && write(in_context->xiso, buf, i) != i) write_err(); // Write remaining 'i' bytes break; } bytes -= n; - if (s_media_enable && (len = strlen(in_avl->filename)) >= 4 && strcasecmp(&in_avl->filename[len - 4], ".xbe") == 0) { + if (s_media_enable && len >= 4 && strcasecmp(&in_avl->filename[len - 4], ".xbe") == 0) { for (buf[n += i] = 0, p = buf; (p = boyer_moore_search(p, n - (long)(p - buf))) != nil; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; if (bytes) { i = XISO_MEDIA_ENABLE_LENGTH - 1; - if (write(in_context->xiso, buf, n - i) != (int)n - i) { + if (write(in_context->xiso, buf, n - i) != (signed)n - i) { write_err(); break; } memcpy(buf, &buf[n - i], i); } else { - if (write(in_context->xiso, buf, n + i) != (int)n + i) { + if (write(in_context->xiso, buf, n + i) != (signed)n + i) { write_err(); break; } } } else { - if (write(in_context->xiso, buf, n + i) != (int)n + i) { + if (write(in_context->xiso, buf, n + i) != (signed)n + i) { write_err(); break; } } } while (bytes); - i = in_avl->file_size; + n = in_avl->file_size; in_avl->file_size -= bytes; - if (!err && (bytes = (XISO_SECTOR_SIZE - (in_avl->file_size % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE)) { - memset(buf, XISO_PAD_BYTE, bytes); - if (write(in_context->xiso, buf, bytes) != (int)bytes) write_err(); + if (!err) { + bytes = (XISO_SECTOR_SIZE - (in_avl->file_size % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE; + if (bytes) { + memset(buf, XISO_PAD_BYTE, bytes); + if (write(in_context->xiso, buf, bytes) != (signed)bytes) write_err(); + } } exiso_log(err ? "failed" : "[OK]"); - if (!err && i != in_avl->file_size) { - exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", in_avl->filename, i, in_avl->file_size); + if (!err && n != in_avl->file_size) { + exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", in_avl->filename, n, in_avl->file_size); } if (!err) { @@ -1845,12 +1840,12 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int in_depth ) { xoff_t pos; - int err = 0, pad; uint16_t l_offset, r_offset; - uint32_t file_size = in_avl->file_size + (in_avl->subdirectory ? (XISO_SECTOR_SIZE - (in_avl->file_size % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE : 0); - char length = (char)strlen(in_avl->filename); - char attributes = in_avl->subdirectory ? XISO_ATTRIBUTE_DIR : XISO_ATTRIBUTE_ARC; + uint32_t file_size = in_avl->subdirectory ? n_sectors(in_avl->file_size) * XISO_SECTOR_SIZE : in_avl->file_size; + uint8_t length = (uint8_t)strlen(in_avl->filename); + uint8_t attributes = in_avl->subdirectory ? XISO_ATTRIBUTE_DIR : XISO_ATTRIBUTE_ARC; char sector[XISO_SECTOR_SIZE]; + int err = 0, pad; little32( in_avl->file_size ); little32( in_avl->start_sector ); @@ -1864,7 +1859,8 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int i memset( sector, XISO_PAD_BYTE, XISO_SECTOR_SIZE ); if ( ( pos = lseek( in_context->xiso, 0, SEEK_CUR ) ) == -1 ) seek_err(); - if ( ! err && ( pad = (int) ( (xoff_t) in_avl->offset + in_avl->dir_start - pos ) ) && write( in_context->xiso, sector, pad ) != pad ) write_err(); + if ( ! err ) pad = (int)((xoff_t)in_avl->offset + in_avl->dir_start - pos); + if ( ! err && write( in_context->xiso, sector, pad ) != pad ) write_err(); if ( ! err && write( in_context->xiso, &l_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err(); if ( ! err && write( in_context->xiso, &r_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err(); if ( ! err && write( in_context->xiso, &in_avl->start_sector, XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) write_err(); @@ -1881,7 +1877,7 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int i int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_current_sector, int in_depth ) { - wdsafp_context context; + wdsafp_context context = { 0 }; if ( in_avl->subdirectory ) { if (in_avl->subdirectory == EMPTY_SUBDIRECTORY) { From ccc5373db8b80898bdeb57c0b58a554da649248d Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sat, 4 Mar 2023 19:26:51 +0100 Subject: [PATCH 14/59] Fixed bug that would not skip files >= 4 GiB Use signed ints for read() and write() return values Bump cmake version to 3.20 and set C_STANDARD to 99 Compile with higher warning level, suppress useless warnings and fix many new warnings Properly build Debug builds Compile Release build with -O2 optimization Merge compiler-dependant definitions and pragmas --- CMakeLists.txt | 17 ++++- extract-xiso.c | 187 +++++++++++++++++++++++++------------------------ 2 files changed, 113 insertions(+), 91 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7aec9fa..6b54f64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.20) project(extract-xiso) string(TOUPPER __${CMAKE_SYSTEM_NAME}__ TARGET_OS) @@ -7,6 +7,21 @@ set(SOURCE_FILES extract-xiso.c ) +if(MSVC) + set(CMAKE_C_FLAGS_RELEASE_INIT "/O2") + add_compile_options(/W4) + add_compile_options("$<$:/DDEBUG=1>") + add_definitions(-D_CRT_NONSTDC_NO_WARNINGS) # POSIX function names + add_definitions(-D_CRT_SECURE_NO_WARNINGS) # Unsafe CRT Library functions +else() + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) + endif() + set(CMAKE_C_FLAGS_DEBUG "-g -DDEBUG=1") + set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG") + add_compile_options(-Wall -Wextra -Wpedantic -Wno-comment) +endif() add_executable(extract-xiso ${SOURCE_FILES}) target_compile_definitions(extract-xiso PRIVATE ${TARGET_OS}) +set_property(TARGET extract-xiso PROPERTY C_STANDARD 99) install(TARGETS extract-xiso RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/extract-xiso.c b/extract-xiso.c index 1e2fc99..3d796d9 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -237,10 +237,26 @@ #if defined( __LINUX__ ) #define _LARGEFILE64_SOURCE #endif + #if defined( __GNUC__ ) #define _GNU_SOURCE + #define unused __attribute__((__unused__)) +#elif defined(_MSC_VER) + #pragma warning(disable: 4706) // C4706: assignment within conditional expression + #define unused __pragma(warning(suppress:4100)) /* This unfortunately disables the warning for the whole line and the next one */ +#else + #define unused +#endif + +#ifndef DEBUG + #define DEBUG 0 #endif +#if DEBUG + #define unused_release +#else + #define unused_release unused +#endif #include #include @@ -251,6 +267,7 @@ #include #include #include +#include #include #include @@ -268,6 +285,8 @@ #endif #if defined(_MSC_VER) + #include + typedef SSIZE_T ssize_t; #define strcasecmp _stricmp #define strncasecmp _strnicmp #else @@ -336,16 +355,16 @@ #endif #define lseek _lseeki64 #define mkdir( a, b ) _mkdir( (a) ) + #define stat _stat64 - typedef __int32 int32_t; - typedef __int64 xoff_t; + typedef int64_t xoff_t; #else #error unknown target, cannot compile! #endif #define swap16( n ) ( ( n ) = ( n ) << 8 | ( n ) >> 8 ) -#define swap32( n ) ( ( n ) = ( n ) << 24 | ( n ) << 8 & 0xff0000 | ( n ) >> 8 & 0xff00 | ( n ) >> 24 ) +#define swap32( n ) ( ( n ) = ( n ) << 24 | ( ( ( n ) << 8 ) & 0xff0000 ) | ( ( ( n ) >> 8 ) & 0xff00 ) | ( n ) >> 24 ) #ifdef USE_BIG_ENDIAN #define big16( n ) @@ -365,11 +384,6 @@ #define DEBUG_TRAVERSE_XISO_DIR 0 -#ifndef DEBUG - #define DEBUG 0 -#endif - - #if ! defined( __cplusplus ) && ! defined( bool ) typedef int bool; enum { false, true }; @@ -522,7 +536,7 @@ typedef enum errors { err_end_of_sector = -5001, err_iso_rewritten = -5002, err_ typedef enum strategies { tree_strategy, discover_strategy } strategies; typedef void (*progress_callback)( xoff_t in_current_value, xoff_t in_final_value ); -typedef int (*traversal_callback)( void *in_node, void *in_context, long in_depth ); +typedef int (*traversal_callback)( void *in_node, void *in_context, int in_depth ); typedef struct dir_node dir_node; typedef struct create_list create_list; @@ -585,13 +599,13 @@ avl_result avl_left_grown( dir_node_avl **in_root ); avl_result avl_right_grown( dir_node_avl **in_root ); dir_node_avl *avl_fetch( dir_node_avl *in_root, char *in_filename ); avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ); -int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, long in_depth ); +int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, int in_depth ); void boyer_moore_done(); char *boyer_moore_search( char *in_text, long in_text_len ); int boyer_moore_init( char *in_pattern, long in_pat_len, long in_alphabet_size ); -int free_dir_node_avl( void *in_dir_node_avl, void *, long ); +int free_dir_node_avl(void* in_dir_node_avl, void* in_context, int in_depth); int extract_file( int in_xiso, dir_node *in_file, modes in_mode, char *path ); int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ); int verify_xiso( int in_xiso, int32_t *out_root_dir_sector, int32_t *out_root_dir_size, char *in_iso_name ); @@ -606,7 +620,7 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int i int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ); int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ); int calculate_total_files_and_bytes( dir_node_avl *in_avl, void *in_context, int in_depth ); -int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, long in_depth ); +int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, int in_depth ); int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, int in_depth ); int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_context, int in_depth ); int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io_context, int in_depth ); @@ -646,8 +660,8 @@ int main( int argc, char **argv ) { struct stat sb; create_list *create = nil, *p, *q, **r; int i, fd, opt_char, err = 0, isos = 0; - bool extract = true, rewrite = false, free_user = false, free_pass = false, x_seen = false, delete = false, optimized; - char *cwd = nil, *path = nil, *buf = nil, *new_iso_path = nil, tag[ XISO_OPTIMIZED_TAG_LENGTH * sizeof(long) ]; + bool extract = true, rewrite = false, x_seen = false, delete = false, optimized; + char *path = nil, *buf = nil, *new_iso_path = nil, tag[ XISO_OPTIMIZED_TAG_LENGTH * sizeof(long) ]; if ( argc < 2 ) { usage(); exit( 1 ); } @@ -847,7 +861,7 @@ int main( int argc, char **argv ) { } -int log_err(const char* in_file, int in_line, const char* in_format, ...) { +int log_err(unused_release const char* in_file, unused_release int in_line, const char* in_format, ...) { va_list ap; char *format; int ret; @@ -930,18 +944,16 @@ int verify_xiso( int in_xiso, int32_t *out_root_dir_sector, int32_t *out_root_di int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ) { - xoff_t pos; - dir_node_avl root; + xoff_t pos = 0; + dir_node_avl root = { 0 }; FILE_TIME *ft = nil; write_tree_context wt_context = { 0 }; - uint32_t start_sector; - int i, n, xiso = -1, err = 0; - char *cwd = nil, *buf = nil, *iso_name, *xiso_path, *iso_dir; + uint32_t start_sector = 0; + int i = 0, n = 0, xiso = -1, err = 0; + char *cwd = nil, *buf = nil, *iso_name = nil, *xiso_path = nil, *iso_dir = nil; s_total_bytes = s_total_files = 0; - memset( &root, 0, sizeof(dir_node_avl) ); - if ( ( cwd = getcwd( nil, 0 ) ) == nil ) mem_err(); if ( ! err ) { if ( ! in_root ) { @@ -982,7 +994,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av root.subdirectory = in_root; avl_traverse_depth_first( &root, (traversal_callback) calculate_total_files_and_bytes, nil, k_prefix, 0 ); } else { - int i, n = 0; + n = 0; exiso_log("\ngenerating avl tree from filesystem: "); flush(); @@ -1100,10 +1112,10 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat dir_node_avl *root = nil; bool repair = false; xoff_t root_dir_start; - int32_t root_dir_sect, root_dir_size; + int32_t root_dir_sect = 0, root_dir_size = 0; uint16_t root_end_offset; - int xiso, err = 0, len, path_len = 0, add_slash = 0; - char *buf, *cwd = nil, *name = nil, *short_name = nil, *iso_name, *folder = nil; + int xiso = 0, err = 0, len = 0, path_len = 0, add_slash = 0; + char *buf = nil, *cwd = nil, *name = nil, *short_name = nil, *iso_name = nil; if ( ( xiso = open( in_xiso, READFLAGS, 0 ) ) == -1 ) open_err( in_xiso ); @@ -1161,7 +1173,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if (asprintf(&buf, "%s%s%s%c", in_path ? in_path : "", add_slash && (!in_path) ? PATH_CHAR_STR : "", in_mode != k_list && (!in_path) ? iso_name : "", PATH_CHAR) == -1) mem_err() root_dir_start = (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek; - root_end_offset = n_sectors(root_dir_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE; + root_end_offset = (uint16_t)(n_sectors(root_dir_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE); if (!err && lseek(xiso, root_dir_start, SEEK_SET) == -1) seek_err(); @@ -1272,9 +1284,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 else err = process_node(in_xiso, node, in_path, in_mode, &avl->subdirectory, strategy); } } - else { - err = process_node(in_xiso, node, in_path, in_mode, nil, strategy); - } + else err = process_node(in_xiso, node, in_path, in_mode, nil, strategy); } // Save next offset for discovery @@ -1309,7 +1319,7 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ char *path = nil; int err = 0; xoff_t dir_start = (xoff_t)node->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; - uint16_t end_offset; + uint16_t end_offset = 0; if (node->attributes & XISO_ATTRIBUTE_DIR) { // Process directory @@ -1336,7 +1346,7 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ else { if (in_path && asprintf(&path, "%s%s%c", in_path, node->filename, PATH_CHAR) == -1) mem_err(); if (!err) { - end_offset = n_sectors(node->file_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE; + end_offset = (uint16_t)(n_sectors(node->file_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE); err = traverse_xiso(in_xiso, dir_start, 0, end_offset, path, in_mode, in_root, strategy); } if (path) free(path); @@ -1523,7 +1533,7 @@ int avl_compare_key( char *in_lhs, char *in_rhs ) { } -int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, long in_depth ) { +int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, int in_depth ) { int err; if ( in_root == nil ) return 0; @@ -1631,11 +1641,11 @@ char *boyer_moore_search( char *in_text, long in_text_len ) { int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { int err = 0; - bool warn = false; xoff_t file_start = (xoff_t)in_file->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; - uint32_t i, size, read_size, totalsize = 0; + uint32_t i, size, totalsize = 0; + int read_size; float totalpercent = 0.0f; - int out; + int out = -1; if (lseek(in_xiso, file_start, SEEK_SET) == -1) seek_err(); @@ -1653,23 +1663,20 @@ int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { i = 0; size = min(in_file->file_size, READWRITE_BUFFER_SIZE); do { - if ((int)(read_size = read(in_xiso, s_copy_buffer, size)) < 0) { - read_err(); - break; - } - if (in_mode == k_extract && read_size != 0) { - if (write(out, s_copy_buffer, read_size) != (int)read_size) { - write_err(); - break; - } + read_size = read(in_xiso, s_copy_buffer, size); + if (read_size < 0) { read_err(); } + else if (in_mode == k_extract && read_size != 0) { + if (write(out, s_copy_buffer, read_size) != read_size) write_err(); } - totalsize += read_size; - totalpercent = (totalsize * 100.0f) / in_file->file_size; - exiso_log("%s%s%s (%u bytes) [%.1f%%]\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename, in_file->file_size, totalpercent); + if (!err) { + totalsize += read_size; + totalpercent = (totalsize * 100.0f) / in_file->file_size; + exiso_log("%s%s%s (%u bytes) [%.1f%%]\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename, in_file->file_size, totalpercent); - i += read_size; - size = min(in_file->file_size - i, READWRITE_BUFFER_SIZE); - } while (i < in_file->file_size && read_size > 0); + i += read_size; + size = min(in_file->file_size - i, READWRITE_BUFFER_SIZE); + } + } while (!err && i < in_file->file_size && read_size > 0); if (!err && i < in_file->file_size) { exiso_warn("File %s is truncated. Reported size: %u bytes, read size: %u bytes!", in_file->filename, in_file->file_size, i); in_file->file_size = i; @@ -1683,7 +1690,7 @@ int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { } -int free_dir_node_avl( void *in_dir_node_avl, void *in_context, long in_depth ) { +int free_dir_node_avl( void *in_dir_node_avl, unused void *in_context, unused int in_depth ) { dir_node_avl *avl = (dir_node_avl *) in_dir_node_avl; if ( avl->subdirectory && avl->subdirectory != EMPTY_SUBDIRECTORY ) avl_traverse_depth_first( avl->subdirectory, free_dir_node_avl, nil, k_postfix, 0 ); @@ -1695,11 +1702,10 @@ int free_dir_node_avl( void *in_dir_node_avl, void *in_context, long in_depth ) } -int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ) { - xoff_t pos; +int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { + xoff_t pos = 0, dir_start = (xoff_t)in_avl->start_sector * XISO_SECTOR_SIZE; write_tree_context context = { 0 }; - xoff_t dir_start = (xoff_t)in_avl->start_sector * XISO_SECTOR_SIZE; - int err = 0, pad; + int err = 0, pad = 0; char sector[XISO_SECTOR_SIZE]; if ( in_avl->subdirectory ) { @@ -1748,10 +1754,10 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep } -int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ) { - char *buf, *p; - uint32_t bytes, n, size = max(XISO_SECTOR_SIZE, READWRITE_BUFFER_SIZE); - int err = 0, fd = -1, i; +int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { + char *buf = nil, *p = nil; + uint32_t bytes = 0, size = max(XISO_SECTOR_SIZE, READWRITE_BUFFER_SIZE); + int err = 0, fd = -1, n, i; size_t len; if ( ! in_avl->subdirectory ) { @@ -1774,7 +1780,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep len = strlen(in_avl->filename); do { n = read(fd, buf + i, min(bytes, size - i)); - if ((signed)n < 0) { + if (n < 0) { read_err(); break; } @@ -1787,40 +1793,40 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep for (buf[n += i] = 0, p = buf; (p = boyer_moore_search(p, n - (long)(p - buf))) != nil; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; if (bytes) { i = XISO_MEDIA_ENABLE_LENGTH - 1; - if (write(in_context->xiso, buf, n - i) != (signed)n - i) { + if (write(in_context->xiso, buf, n - i) != n - i) { write_err(); break; } memcpy(buf, &buf[n - i], i); } else { - if (write(in_context->xiso, buf, n + i) != (signed)n + i) { + if (write(in_context->xiso, buf, n + i) != n + i) { write_err(); break; } } } else { - if (write(in_context->xiso, buf, n + i) != (signed)n + i) { + if (write(in_context->xiso, buf, n + i) != n + i) { write_err(); break; } } } while (bytes); - n = in_avl->file_size; + size = in_avl->file_size; in_avl->file_size -= bytes; if (!err) { - bytes = (XISO_SECTOR_SIZE - (in_avl->file_size % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE; - if (bytes) { - memset(buf, XISO_PAD_BYTE, bytes); - if (write(in_context->xiso, buf, bytes) != (signed)bytes) write_err(); + i = (XISO_SECTOR_SIZE - (in_avl->file_size % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE; + if (i) { + memset(buf, XISO_PAD_BYTE, i); + if (write(in_context->xiso, buf, i) != i) write_err(); } } exiso_log(err ? "failed" : "[OK]"); - if (!err && n != in_avl->file_size) { - exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", in_avl->filename, n, in_avl->file_size); + if (!err && size != in_avl->file_size) { + exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", in_avl->filename, size, in_avl->file_size); } if (!err) { @@ -1838,14 +1844,14 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep } -int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int in_depth ) { +int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unused int in_depth ) { xoff_t pos; uint16_t l_offset, r_offset; uint32_t file_size = in_avl->subdirectory ? n_sectors(in_avl->file_size) * XISO_SECTOR_SIZE : in_avl->file_size; uint8_t length = (uint8_t)strlen(in_avl->filename); uint8_t attributes = in_avl->subdirectory ? XISO_ATTRIBUTE_DIR : XISO_ATTRIBUTE_ARC; char sector[XISO_SECTOR_SIZE]; - int err = 0, pad; + int err = 0, pad = 0; little32( in_avl->file_size ); little32( in_avl->start_sector ); @@ -1876,7 +1882,7 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int i } -int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_current_sector, int in_depth ) { +int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_current_sector, unused int in_depth ) { wdsafp_context context = { 0 }; if ( in_avl->subdirectory ) { @@ -1899,7 +1905,7 @@ int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_current_sect } -int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io_context, int in_depth ) { +int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io_context, unused int in_depth ) { in_avl->dir_start = io_context->dir_start; if ( ! in_avl->subdirectory ) { @@ -1911,7 +1917,7 @@ int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io } -int calculate_total_files_and_bytes( dir_node_avl *in_avl, void *in_context, int in_depth ) { +int calculate_total_files_and_bytes( dir_node_avl *in_avl, unused void *in_context, unused int in_depth ) { if (in_avl->subdirectory) { if (in_avl->subdirectory != EMPTY_SUBDIRECTORY) { avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_total_files_and_bytes, nil, k_prefix, 0); @@ -1924,7 +1930,7 @@ int calculate_total_files_and_bytes( dir_node_avl *in_avl, void *in_context, int } -int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, int in_depth ) { +int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, unused int in_depth ) { if ( in_avl->subdirectory ) { if (in_avl->subdirectory != EMPTY_SUBDIRECTORY) { avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_directory_size, &in_avl->file_size, k_prefix, 0); @@ -1938,7 +1944,7 @@ int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, in } -int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, long in_depth ) { +int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, int in_depth ) { uint32_t length; if ( in_depth == 0 ) *out_size = 0; @@ -1959,11 +1965,11 @@ int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, long in_ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { - struct dirent *p; - struct stat sb; - dir_node_avl *avl; + struct dirent *p = nil; + struct stat sb = { 0 }; + dir_node_avl *avl = nil; DIR *dir = nil; - int err = 0, i, j; + int err = 0, i = 0, j = 0; bool empty_dir = true; if ( ( dir = opendir( "." ) ) == nil ) mem_err(); @@ -1993,13 +1999,13 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { if ( ! err ) err = generate_avl_tree_local( &avl->subdirectory, io_n ); if ( ! err && chdir( ".." ) == -1 ) chdir_err( ".." ); } else if ( S_ISREG( sb.st_mode ) ) { - empty_dir = false; - if ( sb.st_size > ULONG_MAX ) { + if ( sb.st_size > (int64_t)UINT32_MAX ) { log_err( __FILE__, __LINE__, "file %s is too large for xiso, skipping...", avl->filename ); free( avl->filename ); free( avl ); continue; } + empty_dir = false; s_total_bytes += avl->file_size = (uint32_t) sb.st_size; ++s_total_files; } else { @@ -2027,9 +2033,9 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { FILE_TIME *alloc_filetime_now( void ) { - FILE_TIME *ft; - double tmp; - time_t now; + FILE_TIME *ft = nil; + double tmp = 0.0f; + time_t now = 0; int err = 0; if ( ( ft = (FILE_TIME *) malloc( sizeof(struct FILE_TIME) ) ) == nil ) mem_err(); @@ -2065,9 +2071,10 @@ FILE_TIME *alloc_filetime_now( void ) { // 0x8000 to 0x8808 has been zeroed prior to entry. int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ) { - int big, err = 0, little; + uint32_t big, little; char date[] = "0000000000000000"; char spaces[ ECMA_119_VOLUME_CREATION_DATE - ECMA_119_VOLUME_SET_IDENTIFIER ]; + int err = 0; big = little = in_total_sectors; @@ -2101,14 +2108,14 @@ int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ) { void write_sector( int in_xiso, xoff_t in_start, char *in_name, char *in_extension ) { ssize_t wrote; - xoff_t curpos; + xoff_t curpos = 0; int fp = -1, err = 0; char *cwd, *sect = nil, buf[ 256 ]; if ( ( cwd = getcwd( nil, 0 ) ) == nil ) mem_err(); if ( ! err && chdir( DEBUG_DUMP_DIRECTORY ) == -1 ) chdir_err( DEBUG_DUMP_DIRECTORY ); - sprintf( buf, "%llu.%s.%s", in_start, in_name, in_extension ? in_extension : "" ); + sprintf( buf, "%" PRId64 ".%s.%s", in_start, in_name, in_extension ? in_extension : ""); if ( ! err && ( fp = open( buf, WRITEFLAGS, 0644 ) ) == -1 ) open_err( buf ); if ( ! err && ( curpos = lseek( in_xiso, 0, SEEK_CUR ) ) == -1 ) seek_err(); From 8f4bb08af597be549b22c9e432e08b1ba52b0ec4 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sat, 11 Mar 2023 16:16:35 +0100 Subject: [PATCH 15/59] Fix a bug that would cause unnecessary overlapping writes for xbe files when media patch is enabled Simplify write_file() --- extract-xiso.c | 52 ++++++++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 3d796d9..76f0338 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -1757,8 +1757,9 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { char *buf = nil, *p = nil; uint32_t bytes = 0, size = max(XISO_SECTOR_SIZE, READWRITE_BUFFER_SIZE); - int err = 0, fd = -1, n, i; + int err = 0, fd = -1, n = 0, i = 0; size_t len; + bool xbe_file; if ( ! in_avl->subdirectory ) { if ( lseek( in_context->xiso, (xoff_t) in_avl->start_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err(); @@ -1775,50 +1776,35 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int if ( ! err ) { exiso_log( "\nadding %s%s (%u bytes) ", in_context->path, in_avl->filename, in_avl->file_size ); flush(); - i = 0; bytes = in_avl->file_size; len = strlen(in_avl->filename); + xbe_file = len >= 4 && strcasecmp(&in_avl->filename[len - 4], ".xbe") == 0; do { n = read(fd, buf + i, min(bytes, size - i)); - if (n < 0) { - read_err(); - break; - } - else if (n == 0) { // End of file - if (i && write(in_context->xiso, buf, i) != i) write_err(); // Write remaining 'i' bytes - break; - } - bytes -= n; - if (s_media_enable && len >= 4 && strcasecmp(&in_avl->filename[len - 4], ".xbe") == 0) { - for (buf[n += i] = 0, p = buf; (p = boyer_moore_search(p, n - (long)(p - buf))) != nil; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; - if (bytes) { - i = XISO_MEDIA_ENABLE_LENGTH - 1; - if (write(in_context->xiso, buf, n - i) != n - i) { - write_err(); - break; - } - memcpy(buf, &buf[n - i], i); - } - else { - if (write(in_context->xiso, buf, n + i) != n + i) { - write_err(); - break; - } - } + if (n < 0) { read_err(); } + else if (n == 0) { // Unexpected end of file + if (i > 0 && write(in_context->xiso, buf, i) != i) write_err(); // Write remaining 'i' bytes } else { - if (write(in_context->xiso, buf, n + i) != n + i) { - write_err(); - break; + bytes -= n; + if (s_media_enable && xbe_file) { + n += i; + for (buf[n] = 0, p = buf; (p = boyer_moore_search(p, n - (long)(p - buf))) != nil; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; + if (bytes) { + i = XISO_MEDIA_ENABLE_LENGTH - 1; + n -= i; + } } + if (write(in_context->xiso, buf, n) != n) write_err(); + if (!err && s_media_enable && xbe_file && bytes) memcpy(buf, &buf[n], i); } - } while (bytes); + } while (!err && bytes > 0 && n > 0); size = in_avl->file_size; in_avl->file_size -= bytes; if (!err) { i = (XISO_SECTOR_SIZE - (in_avl->file_size % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE; - if (i) { + if (i > 0) { memset(buf, XISO_PAD_BYTE, i); if (write(in_context->xiso, buf, i) != i) write_err(); } @@ -1835,7 +1821,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int if (in_context->progress) (*in_context->progress)(s_total_bytes, in_context->final_bytes); } } - + if ( in_context->from == -1 && fd != -1 ) close( fd ); if ( buf ) free( buf ); } From 49e0f25eeab53e85089c333ff7b649c2ccf0a289 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 14 Mar 2023 10:15:27 +0100 Subject: [PATCH 16/59] Fix some data types, reduce unnecessarly large buffer --- extract-xiso.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 76f0338..c238676 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -468,8 +468,6 @@ #define XGD3_LSEEK_OFFSET 0x02080000ul #define XGD1_LSEEK_OFFSET 0x18300000ul -#define n_sectors( size ) ( ( size ) / XISO_SECTOR_SIZE + ( ( size ) % XISO_SECTOR_SIZE ? 1 : 0 ) ) - #define XISO_HEADER_DATA "MICROSOFT*XBOX*MEDIA" #define XISO_HEADER_DATA_LENGTH 20 #define XISO_HEADER_OFFSET 0x10000 @@ -490,7 +488,7 @@ #define XISO_DIRTABLE_SIZE 4 #define XISO_FILESIZE_SIZE 4 #define XISO_DWORD_SIZE 4 -#define XISO_FILETIME_SIZE 8 +#define XISO_FILETIME_SIZE sizeof(file_time_t) #define XISO_SECTOR_SIZE 2048 #define XISO_UNUSED_SIZE 0x7c8 @@ -514,6 +512,7 @@ #define XISO_MEDIA_ENABLE_LENGTH 8 #define XISO_MEDIA_ENABLE_BYTE_POS 7 +#define n_sectors(size) ( (size) / XISO_SECTOR_SIZE + ( (size) % XISO_SECTOR_SIZE ? 1 : 0 ) ) #define n_dword(offset) ( (offset) / XISO_DWORD_SIZE + ( (offset) % XISO_DWORD_SIZE ? 1 : 0 ) ) #define EMPTY_SUBDIRECTORY ( (dir_node_avl *) 1 ) @@ -535,7 +534,7 @@ typedef enum modes { k_generate_avl, k_extract, k_list, k_rewrite } modes; typedef enum errors { err_end_of_sector = -5001, err_iso_rewritten = -5002, err_iso_no_files = -5003 } errors; typedef enum strategies { tree_strategy, discover_strategy } strategies; -typedef void (*progress_callback)( xoff_t in_current_value, xoff_t in_final_value ); +typedef void (*progress_callback)( long long in_current_value, long long in_final_value ); typedef int (*traversal_callback)( void *in_node, void *in_context, int in_depth ); typedef struct dir_node dir_node; @@ -587,7 +586,7 @@ typedef struct write_tree_context { char *path; int from; progress_callback progress; - xoff_t final_bytes; + long long final_bytes; } write_tree_context; @@ -608,7 +607,7 @@ int boyer_moore_init( char *in_pattern, long in_pat_len, long in_alphabet_size ) int free_dir_node_avl(void* in_dir_node_avl, void* in_context, int in_depth); int extract_file( int in_xiso, dir_node *in_file, modes in_mode, char *path ); int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ); -int verify_xiso( int in_xiso, int32_t *out_root_dir_sector, int32_t *out_root_dir_size, char *in_iso_name ); +int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, char *in_iso_name ); int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ); @@ -636,12 +635,12 @@ static bool s_quiet = false; static char *s_pattern = nil; static long *s_gs_table = nil; static long *s_bc_table = nil; -static xoff_t s_total_bytes = 0; +static long long s_total_bytes = 0; static int s_total_files = 0; static char *s_copy_buffer = nil; static bool s_real_quiet = false; static bool s_media_enable = true; -static xoff_t s_total_bytes_all_isos = 0; +static long long s_total_bytes_all_isos = 0; static int s_total_files_all_isos = 0; static bool s_warned = false; @@ -661,7 +660,7 @@ int main( int argc, char **argv ) { create_list *create = nil, *p, *q, **r; int i, fd, opt_char, err = 0, isos = 0; bool extract = true, rewrite = false, x_seen = false, delete = false, optimized; - char *path = nil, *buf = nil, *new_iso_path = nil, tag[ XISO_OPTIMIZED_TAG_LENGTH * sizeof(long) ]; + char *path = nil, *buf = nil, *new_iso_path = nil, tag[XISO_OPTIMIZED_TAG_LENGTH + 1]; if ( argc < 2 ) { usage(); exit( 1 ); } @@ -837,7 +836,7 @@ int main( int argc, char **argv ) { } } - if ( ! err ) exiso_log( "\n\n%u files in %s total %lld bytes\n", s_total_files, rewrite ? new_iso_path : argv[ i ], (long long int) s_total_bytes ); + if ( ! err ) exiso_log( "\n\n%u files in %s total %lld bytes\n", s_total_files, rewrite ? new_iso_path : argv[ i ], s_total_bytes ); if ( new_iso_path ) { if ( ! err ) exiso_log( "\n%s successfully rewritten%s%s\n", argv[ i ], path ? " as " : ".", path ? new_iso_path : "" ); @@ -849,7 +848,7 @@ int main( int argc, char **argv ) { if ( err == err_iso_no_files ) err = 0; } - if ( ! err && isos > 1 ) exiso_log( "\n%u files in %u xiso's total %lld bytes\n", s_total_files_all_isos, isos, (long long int) s_total_bytes_all_isos ); + if ( ! err && isos > 1 ) exiso_log( "\n%u files in %u xiso's total %lld bytes\n", s_total_files_all_isos, isos, s_total_bytes_all_isos ); if ( s_warned ) exiso_warn( "Warning(s) were issued during execution--review stderr!\n" ); boyer_moore_done(); @@ -895,7 +894,7 @@ int log_err(unused_release const char* in_file, unused_release int in_line, cons #endif -int verify_xiso( int in_xiso, int32_t *out_root_dir_sector, int32_t *out_root_dir_size, char *in_iso_name ) { +int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, char *in_iso_name ) { int err = 0; char buffer[ XISO_HEADER_DATA_LENGTH ]; @@ -1085,7 +1084,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av if ( ! in_root ) { if ( err ) { exiso_log( "\ncould not create %s%s\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "" ); } - else exiso_log( "\nsucessfully created %s%s (%u files totalling %lld bytes added)\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "", s_total_files, (long long int) s_total_bytes ); + else exiso_log( "\nsucessfully created %s%s (%u files totalling %lld bytes added)\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "", s_total_files, s_total_bytes ); } if ( root.subdirectory != EMPTY_SUBDIRECTORY ) avl_traverse_depth_first( root.subdirectory, free_dir_node_avl, nil, k_postfix, 0 ); @@ -1112,7 +1111,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat dir_node_avl *root = nil; bool repair = false; xoff_t root_dir_start; - int32_t root_dir_sect = 0, root_dir_size = 0; + uint32_t root_dir_sect = 0, root_dir_size = 0; uint16_t root_end_offset; int xiso = 0, err = 0, len = 0, path_len = 0, add_slash = 0; char *buf = nil, *cwd = nil, *name = nil, *short_name = nil, *iso_name = nil; @@ -1639,7 +1638,7 @@ char *boyer_moore_search( char *in_text, long in_text_len ) { #endif -int extract_file( int in_xiso, dir_node *in_file, modes in_mode , char* path) { +int extract_file(int in_xiso, dir_node *in_file, modes in_mode, char* path) { int err = 0; xoff_t file_start = (xoff_t)in_file->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; uint32_t i, size, totalsize = 0; From 9c636ddffed00d710c9db0504ed1c193fa1cc0a2 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 14 Mar 2023 12:47:37 +0100 Subject: [PATCH 17/59] Fix lseek with wrapper that returns error when trying to seek past file end Simplify s_xbox_disc_lseek finding --- extract-xiso.c | 85 ++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index c238676..00d1c90 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -464,9 +464,13 @@ #endif -#define GLOBAL_LSEEK_OFFSET 0x0FD90000ul -#define XGD3_LSEEK_OFFSET 0x02080000ul -#define XGD1_LSEEK_OFFSET 0x18300000ul +#define START_LSEEK_OFFSET 0x00000000ul +#define XGD3_LSEEK_OFFSET 0x02080000ul +#define GLOBAL_LSEEK_OFFSET 0x0FD90000ul +#define XGD1_LSEEK_OFFSET 0x18300000ul +#define LSEEK_OFFSETS_LEN 4 +/* The offsets should be in ascending order, otherwise we could get a seek error before checking the correct one */ +xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_OFFSET, GLOBAL_LSEEK_OFFSET, XGD1_LSEEK_OFFSET}; #define XISO_HEADER_DATA "MICROSOFT*XBOX*MEDIA" #define XISO_HEADER_DATA_LENGTH 20 @@ -590,6 +594,7 @@ typedef struct write_tree_context { } write_tree_context; +xoff_t lseek_with_error(int fd, xoff_t offset, int whence); int log_err( const char *in_file, int in_line, const char *in_format, ... ); void avl_rotate_left( dir_node_avl **in_root ); void avl_rotate_right( dir_node_avl **in_root ); @@ -802,7 +807,7 @@ int main( int argc, char **argv ) { optimized = false; if ( ( fd = open( argv[ i ], READFLAGS, 0 ) ) == -1 ) open_err( argv[ i ] ); - if ( ! err && lseek( fd, (xoff_t) XISO_OPTIMIZED_TAG_OFFSET, SEEK_SET ) == -1 ) seek_err(); + if ( ! err && lseek_with_error( fd, (xoff_t) XISO_OPTIMIZED_TAG_OFFSET, SEEK_SET ) == -1 ) seek_err(); if ( ! err && read( fd, tag, XISO_OPTIMIZED_TAG_LENGTH ) != XISO_OPTIMIZED_TAG_LENGTH ) read_err(); if ( fd != -1 ) close( fd ); @@ -859,6 +864,19 @@ int main( int argc, char **argv ) { return err; } +/* Wrapper to avoid changing old code, since lseek will not return error if offset is beyond end of file. Use only on input. */ +xoff_t lseek_with_error(int fd, xoff_t offset, int whence) { + xoff_t pos = lseek(fd, offset, whence); // First execute the seek, to save the offset + if (pos == -1) return -1; + xoff_t end = lseek(fd, 0, SEEK_END); // Then save the end of the file + if (end == -1) return -1; + if (pos > end) { + errno = EINVAL; + return -1; + } + return lseek(fd, pos, SEEK_SET); // Finally seek again to saved offset +} + int log_err(unused_release const char* in_file, unused_release int in_line, const char* in_format, ...) { va_list ap; @@ -895,31 +913,18 @@ int log_err(unused_release const char* in_file, unused_release int in_line, cons int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, char *in_iso_name ) { - int err = 0; - char buffer[ XISO_HEADER_DATA_LENGTH ]; - - if ( lseek( in_xiso, (xoff_t) XISO_HEADER_OFFSET, SEEK_SET ) == -1 ) seek_err(); - if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err(); - if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) ) - { - if ( lseek( in_xiso, (xoff_t) XISO_HEADER_OFFSET + GLOBAL_LSEEK_OFFSET, SEEK_SET ) == -1 ) seek_err(); - if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err(); - if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) ) - { - if ( lseek( in_xiso, (xoff_t) XISO_HEADER_OFFSET + XGD3_LSEEK_OFFSET, SEEK_SET ) == -1 ) seek_err(); - if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err(); - if (!err && memcmp(buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH)) - { - if (lseek(in_xiso, (xoff_t)XISO_HEADER_OFFSET + XGD1_LSEEK_OFFSET, SEEK_SET) == -1) seek_err(); - if (!err && read(in_xiso, buffer, XISO_HEADER_DATA_LENGTH) != XISO_HEADER_DATA_LENGTH) read_err(); - if (!err && memcmp(buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH)) misc_err("%s does not appear to be a valid xbox iso image", in_iso_name) - else s_xbox_disc_lseek = XGD1_LSEEK_OFFSET; - } - else s_xbox_disc_lseek = XGD3_LSEEK_OFFSET; + int i, err = 0; + char buffer[XISO_HEADER_DATA_LENGTH]; + + for (i = 0; !err && i < LSEEK_OFFSETS_LEN; i++) { + if (lseek_with_error(in_xiso, (xoff_t)XISO_HEADER_OFFSET + lseek_offsets[i], SEEK_SET) == -1) seek_err(); + if (!err && read(in_xiso, buffer, XISO_HEADER_DATA_LENGTH) != XISO_HEADER_DATA_LENGTH) read_err(); + if (!err && !memcmp(buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH)) { + s_xbox_disc_lseek = lseek_offsets[i]; + break; // Found } - else s_xbox_disc_lseek = GLOBAL_LSEEK_OFFSET; } - else s_xbox_disc_lseek = 0; + if (!err && i == LSEEK_OFFSETS_LEN) misc_err("%s does not appear to be a valid xbox iso image", in_iso_name); // read root directory information if ( ! err && read( in_xiso, out_root_dir_sector, XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) read_err(); @@ -929,12 +934,12 @@ int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_ little32( *out_root_dir_size ); // seek to header tail and verify media tag - if ( ! err && lseek( in_xiso, (xoff_t) XISO_FILETIME_SIZE + XISO_UNUSED_SIZE, SEEK_CUR ) == -1 ) seek_err(); + if ( ! err && lseek_with_error(in_xiso, (xoff_t)XISO_FILETIME_SIZE + XISO_UNUSED_SIZE, SEEK_CUR) == -1) seek_err(); if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err(); if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) ) misc_err( "%s appears to be corrupt", in_iso_name ); // seek to root directory sector - if (!err && lseek(in_xiso, (xoff_t)*out_root_dir_sector * XISO_SECTOR_SIZE, SEEK_SET) == -1) seek_err(); + if (!err && lseek_with_error(in_xiso, (xoff_t)*out_root_dir_sector * XISO_SECTOR_SIZE, SEEK_SET) == -1) seek_err(); return err; } @@ -1043,7 +1048,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av } if ( ! err ) { if ( in_root ) { - if ( lseek( in_xiso, (xoff_t) XISO_HEADER_OFFSET + XISO_HEADER_DATA_LENGTH + XISO_SECTOR_OFFSET_SIZE + XISO_DIRTABLE_SIZE + s_xbox_disc_lseek, SEEK_SET ) == -1 ) seek_err(); + if (lseek_with_error(in_xiso, (xoff_t)XISO_HEADER_OFFSET + XISO_HEADER_DATA_LENGTH + XISO_SECTOR_OFFSET_SIZE + XISO_DIRTABLE_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); if ( ! err && read( in_xiso, buf, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) read_err(); if ( ! err && write( xiso, buf, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) write_err(); @@ -1174,7 +1179,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat root_dir_start = (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek; root_end_offset = (uint16_t)(n_sectors(root_dir_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE); - if (!err && lseek(xiso, root_dir_start, SEEK_SET) == -1) seek_err(); + if (!err && lseek_with_error(xiso, root_dir_start, SEEK_SET) == -1) seek_err(); if ( in_mode == k_rewrite ) { if (!err && root_dir_size == 0) root = EMPTY_SUBDIRECTORY; @@ -1218,7 +1223,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 if (entry_offset >= end_offset) misc_err("attempt to read node entry beyond directory end"); do { - if (!err && lseek(in_xiso, in_dir_start + (xoff_t)entry_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); + if (!err && lseek_with_error(in_xiso, in_dir_start + (xoff_t)entry_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); if (!err && read(in_xiso, &l_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); if (!err && l_offset == XISO_PAD_SHORT) { @@ -1300,13 +1305,13 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 if (strategy != discover_strategy) { // Recurse on left node if (!err && l_offset) { - if (lseek(in_xiso, in_dir_start + (xoff_t)l_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); + if (lseek_with_error(in_xiso, in_dir_start + (xoff_t)l_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); if (!err) err = traverse_xiso(in_xiso, in_dir_start, l_offset, end_offset, in_path, in_mode, &avl, strategy); } // Recurse on right node if (!err && r_offset) { - if (lseek(in_xiso, in_dir_start + (xoff_t)r_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); + if (lseek_with_error(in_xiso, in_dir_start + (xoff_t)r_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); if (!err) err = traverse_xiso(in_xiso, in_dir_start, r_offset, end_offset, in_path, in_mode, &avl, strategy); } } @@ -1322,7 +1327,7 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ if (node->attributes & XISO_ATTRIBUTE_DIR) { // Process directory - if (!err) if (lseek(in_xiso, dir_start, SEEK_SET) == -1) seek_err(); + if (!err) if (lseek_with_error(in_xiso, dir_start, SEEK_SET) == -1) seek_err(); if (!err) { if (!s_remove_systemupdate || !strstr(node->filename, s_systemupdate)) @@ -1646,7 +1651,7 @@ int extract_file(int in_xiso, dir_node *in_file, modes in_mode, char* path) { float totalpercent = 0.0f; int out = -1; - if (lseek(in_xiso, file_start, SEEK_SET) == -1) seek_err(); + if (lseek_with_error(in_xiso, file_start, SEEK_SET) == -1) seek_err(); if ( !s_remove_systemupdate || !strstr( path, s_systemupdate ) ) { if ( in_mode == k_extract ) { @@ -1768,7 +1773,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int if ( in_context->from == -1 ) { if ( ( fd = open( in_avl->filename, READFLAGS, 0 ) ) == -1 ) open_err( in_avl->filename ); } else { - if ( lseek( fd = in_context->from, (xoff_t) in_avl->old_start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET ) == -1 ) seek_err(); + if (lseek_with_error(fd = in_context->from, (xoff_t)in_avl->old_start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); } } @@ -2103,15 +2108,15 @@ void write_sector( int in_xiso, xoff_t in_start, char *in_name, char *in_extensi sprintf( buf, "%" PRId64 ".%s.%s", in_start, in_name, in_extension ? in_extension : ""); if ( ! err && ( fp = open( buf, WRITEFLAGS, 0644 ) ) == -1 ) open_err( buf ); - if ( ! err && ( curpos = lseek( in_xiso, 0, SEEK_CUR ) ) == -1 ) seek_err(); - if ( ! err && lseek( in_xiso, in_start, SEEK_SET ) == -1 ) seek_err(); + if ( ! err && ( curpos = lseek_with_error( in_xiso, 0, SEEK_CUR ) ) == -1 ) seek_err(); + if ( ! err && lseek_with_error( in_xiso, in_start, SEEK_SET ) == -1 ) seek_err(); if ( ! err && ( sect = (char *) malloc( XISO_SECTOR_SIZE ) ) == nil ) mem_err(); if ( ! err && read( in_xiso, sect, XISO_SECTOR_SIZE ) != XISO_SECTOR_SIZE ) read_err(); if ( ! err && ( wrote = write( fp, sect, XISO_SECTOR_SIZE ) ) != XISO_SECTOR_SIZE ) write_err(); - if ( ! err && lseek( in_xiso, curpos, SEEK_SET ) == -1 ) seek_err(); + if ( ! err && lseek_with_error( in_xiso, curpos, SEEK_SET ) == -1 ) seek_err(); if ( sect ) free( sect ); if ( fp != -1 ) close( fp ); From 5216be4bcf9c5987e2b894f7d00a0c9a0e93ccd9 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Wed, 15 Mar 2023 11:03:09 +0100 Subject: [PATCH 18/59] Use realpath/_fullpath to get absolute path of output dir --- extract-xiso.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 00d1c90..5b9bcb1 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -356,6 +356,7 @@ #define lseek _lseeki64 #define mkdir( a, b ) _mkdir( (a) ) #define stat _stat64 + #define realpath(a, b) _fullpath(b, a, _MAX_PATH) typedef int64_t xoff_t; #else @@ -954,38 +955,35 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av write_tree_context wt_context = { 0 }; uint32_t start_sector = 0; int i = 0, n = 0, xiso = -1, err = 0; - char *cwd = nil, *buf = nil, *iso_name = nil, *xiso_path = nil, *iso_dir = nil; + char *cwd = nil, *buf = nil, *iso_name = nil, *xiso_path = nil, *iso_dir = nil, *real_path = nil; s_total_bytes = s_total_files = 0; if ( ( cwd = getcwd( nil, 0 ) ) == nil ) mem_err(); if ( ! err ) { if ( ! in_root ) { - if ( chdir( in_root_directory ) == -1 ) chdir_err( in_root_directory ); - if ( ! err ) { - i = (int)strlen(in_root_directory) - 1; - if ( in_root_directory[i] == '/' || in_root_directory[i] == '\\' ) in_root_directory[i] = 0; - if ((iso_dir = strrchr(in_root_directory, PATH_CHAR))) iso_dir++; - else iso_dir = in_root_directory; + i = (int)strlen(in_root_directory) - 1; + if ( in_root_directory[i] == '/' || in_root_directory[i] == '\\' ) in_root_directory[i] = 0; + if ((iso_dir = strrchr(in_root_directory, PATH_CHAR))) iso_dir++; + else iso_dir = in_root_directory; - iso_name = in_name ? in_name : iso_dir; - } + iso_name = in_name ? in_name : iso_dir; } else { iso_dir = iso_name = in_root_directory; } } if ( ! err ) { if ( ! *iso_dir ) iso_dir = PATH_CHAR_STR; - if ( ! in_output_directory ) in_output_directory = cwd; - i = (int)strlen(in_output_directory) - 1; - if ( in_output_directory[i] == PATH_CHAR ) in_output_directory[i] = 0; if ( ! iso_name || ! *iso_name ) iso_name = "root"; else if ( iso_name[ 1 ] == ':' ) { iso_name[ 1 ] = iso_name[ 0 ]; ++iso_name; } -#if defined( _WIN32 ) - if ( ( asprintf( &xiso_path, "%s%c%s%s", *in_output_directory ? in_output_directory : cwd, PATH_CHAR, iso_name, in_name ? "" : ".iso" ) ) == -1 ) mem_err(); -#else - if ( ( asprintf( &xiso_path, "%s%s%s%c%s%s", *in_output_directory == PATH_CHAR ? "" : cwd, *in_output_directory == PATH_CHAR ? "" : PATH_CHAR_STR, in_output_directory, PATH_CHAR, iso_name, in_name ? "" : ".iso" ) ) == -1 ) mem_err(); -#endif + if (!err && (real_path = realpath(in_output_directory ? in_output_directory : ".", nil)) == nil) misc_err("unable to get absolute path of %s: %s", real_path, strerror(errno)); + if (!err && (asprintf(&xiso_path, "%s%c%s%s", real_path, PATH_CHAR, iso_name, in_name ? "" : ".iso")) == -1) mem_err(); + if (real_path) { + free(real_path); + real_path = nil; + } + + if (!err && !in_root && chdir(in_root_directory) == -1) chdir_err(in_root_directory); } if ( ! err ) { exiso_log( "\n%s %s%s:\n", in_root ? "rewriting" : "creating", iso_name, in_name ? "" : ".iso" ); From 9be28061beaa7f5298b09b95b6f16f4d1fb3d866 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sat, 11 Mar 2023 20:18:24 +0100 Subject: [PATCH 19/59] Fix compilation under FreeBSD, OpenBSD, MinGW and Cygwin/MSYS2, add support for NetBSD Add Linux, FreeBSD, OpenBSD and NetBSD GitHub actions Enable 64-bit builds again Update to v3 actions Set C standard to c99, not gnu99 Replace alloc_filetime_now calculation with magic numbers from Microsoft, rename it to get_filetime_now and return int64_t intead of allocating a struct Use target byte swap functions Update appveyor.yml to VS 2022 Reorder Windows-specific includes and defines Better check for endianness Check CHAR_BIT just in case Rename targets to current commercial names Simplify target-specific includes and definitions Migrate to new method for accessing big files on Linux (it shouldn't matter, since we don't support 32-bit builds on Linux anyways) --- .github/data/BSD.cmake | 21 ++++ .github/workflows/CI.yml | 250 ++++++++++++++++++++++++++++++--------- CMakeLists.txt | 5 + appveyor.yml | 4 +- extract-xiso.c | 225 +++++++++++++++++++---------------- win32/getopt.c | 6 +- 6 files changed, 352 insertions(+), 159 deletions(-) create mode 100644 .github/data/BSD.cmake diff --git a/.github/data/BSD.cmake b/.github/data/BSD.cmake new file mode 100644 index 0000000..c7bfc99 --- /dev/null +++ b/.github/data/BSD.cmake @@ -0,0 +1,21 @@ +# CMAKE_SYSTEM_NAME, TARGET and SYSROOT_PATH must be set + +set(CMAKE_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}) + +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +set(CMAKE_C_COMPILER clang) +set(CMAKE_C_COMPILER_TARGET ${TARGET}) +set(CMAKE_AR ar) +set(CMAKE_AR_TARGET ${TARGET}) +set(CMAKE_LD lld) +set(CMAKE_LD_TARGET ${TARGET}) + +set(CMAKE_SYSROOT ${SYSROOT_PATH}) + +# these variables tell CMake to avoid using any binary it finds in +# the sysroot, while picking headers and libraries exclusively from it +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 54ce97a..ac9ddf0 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -20,7 +20,7 @@ jobs: echo "BUILD_TAG=$BUILD_TAG" >> $GITHUB_ENV echo -n $BUILD_TAG > tag - name: Upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: tag path: tag @@ -43,7 +43,7 @@ jobs: platform: x64 artifact_os: Win64 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: CMake generate run: | mkdir build && cd build @@ -55,7 +55,7 @@ jobs: run: | mkdir artifacts mv -vb build\${{ matrix.configuration }}\extract-xiso.exe, LICENSE.TXT artifacts - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: extract-xiso_${{ matrix.artifact_os }}_${{ matrix.configuration }} path: artifacts @@ -64,7 +64,7 @@ jobs: runs-on: ubuntu-latest needs: Init steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: CMake generate run: | mkdir build && cd build @@ -76,7 +76,7 @@ jobs: run: | mkdir artifacts mv -v build/extract-xiso LICENSE.TXT artifacts - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: extract-xiso_${{ runner.os }} path: artifacts @@ -85,7 +85,7 @@ jobs: runs-on: macos-latest needs: Init steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: CMake generate run: | mkdir build && cd build @@ -97,20 +97,116 @@ jobs: run: | mkdir artifacts mv -v build/extract-xiso LICENSE.TXT artifacts - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: extract-xiso_${{ runner.os }} path: artifacts + build-freebsd: + runs-on: ubuntu-latest + needs: Init + env: + SYSROOT_PATH: /opt/cross-freebsd-13 + steps: + - uses: actions/checkout@v3 + - name: FreeBSD toolchain setup + run: | + sudo apt-get -qq install clang lld && cd /tmp && \ + wget -nv http://ftp.plusline.de/FreeBSD/releases/amd64/13.1-RELEASE/base.txz && \ + mkdir -p $SYSROOT_PATH && cd $SYSROOT_PATH && \ + tar -xf /tmp/base.txz ./lib/ ./usr/lib/ ./usr/include/ && \ + cd $SYSROOT_PATH/usr/lib && \ + find . -xtype l | xargs ls -l | grep ' /lib/' | awk -v sysroot="$SYSROOT_PATH" '{print "ln -sf " sysroot $11 " " $9}' | /bin/sh && \ + rm -f /tmp/base.txz + - name: CMake generate + run: | + mkdir build && cd build + cmake -DCMAKE_TOOLCHAIN_FILE=../.github/data/BSD.cmake -DCMAKE_SYSTEM_NAME=FreeBSD -DTARGET=x86_64-pc-freebsd -DSYSROOT_PATH=$SYSROOT_PATH .. + - name: Build + working-directory: build + run: cmake --build . -j $(nproc --all) + - name: Prepare artifacts + run: | + mkdir artifacts + mv -v build/extract-xiso LICENSE.TXT artifacts + - uses: actions/upload-artifact@v3 + with: + name: extract-xiso_freebsd + path: artifacts + + build-openbsd: + runs-on: ubuntu-latest + needs: Init + env: + SYSROOT_PATH: /opt/cross-openbsd-7 + steps: + - uses: actions/checkout@v3 + - name: OpenBSD toolchain setup + run: | + sudo apt-get -qq install clang lld && cd /tmp && \ + wget -nv https://cdn.openbsd.org/pub/OpenBSD/7.2/amd64/base72.tgz \ + https://cdn.openbsd.org/pub/OpenBSD/7.2/amd64/comp72.tgz && \ + mkdir -p $SYSROOT_PATH && cd $SYSROOT_PATH && \ + tar -xf /tmp/base72.tgz ./usr/lib/ ./usr/include/ && \ + tar -xf /tmp/comp72.tgz ./usr/lib/ ./usr/include/ && \ + rm -f /tmp/base72.tgz /tmp/comp72.tgz + - name: CMake generate + run: | + mkdir build && cd build + cmake -DCMAKE_TOOLCHAIN_FILE=../.github/data/BSD.cmake -DCMAKE_SYSTEM_NAME=OpenBSD -DTARGET=x86_64-pc-openbsd -DSYSROOT_PATH=$SYSROOT_PATH .. + - name: Build + working-directory: build + run: cmake --build . -j $(nproc --all) + - name: Prepare artifacts + run: | + mkdir artifacts + mv -v build/extract-xiso LICENSE.TXT artifacts + - uses: actions/upload-artifact@v3 + with: + name: extract-xiso_openbsd + path: artifacts + + build-netbsd: + runs-on: ubuntu-latest + needs: Init + env: + SYSROOT_PATH: /opt/cross-netbsd-9 + steps: + - uses: actions/checkout@v3 + - name: NetBSD toolchain setup + run: | + sudo apt-get -qq install clang lld && cd /tmp && \ + wget -nv https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.3/amd64/binary/sets/base.tar.xz \ + https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.3/amd64/binary/sets/comp.tar.xz && \ + mkdir -p $SYSROOT_PATH && cd $SYSROOT_PATH && \ + tar -xf /tmp/base.tar.xz ./usr/lib/ ./usr/include/ && \ + tar -xf /tmp/comp.tar.xz ./usr/lib/ ./usr/include/ && \ + rm -f /tmp/base.tar.xz /tmp/comp.tar.xz + - name: CMake generate + run: | + mkdir build && cd build + cmake -DCMAKE_TOOLCHAIN_FILE=../.github/data/BSD.cmake -DCMAKE_SYSTEM_NAME=NetBSD -DTARGET=x86_64-pc-netbsd -DSYSROOT_PATH=$SYSROOT_PATH .. + - name: Build + working-directory: build + run: cmake --build . -j $(nproc --all) + - name: Prepare artifacts + run: | + mkdir artifacts + mv -v build/extract-xiso LICENSE.TXT artifacts + - uses: actions/upload-artifact@v3 + with: + name: extract-xiso_netbsd + path: artifacts + Release: if: github.event_name == 'push' && github.ref == 'refs/heads/master' runs-on: ubuntu-latest - needs: [build-windows, build-linux, build-macos] + needs: [build-windows, build-linux, build-macos, build-freebsd, build-openbsd, build-netbsd] env: BUILD_TAG: steps: - name: Download artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: path: dist - name: Create archives @@ -121,18 +217,27 @@ jobs: pushd dist/extract-xiso_Win32_Debug zip -r ../extract-xiso-win32-debug.zip * popd - ### - # Comment out 64 bit builds as they are currently broken - ### - # pushd dist/extract-xiso_Win64_Release - # zip -r ../extract-xiso-win64-release.zip * - # popd - # pushd dist/extract-xiso_Win64_Debug - # zip -r ../extract-xiso-win64-debug.zip * - # popd - # pushd dist/extract-xiso_macOS - # zip -r ../extract-xiso-macos.zip * - # popd + pushd dist/extract-xiso_Win64_Release + zip -r ../extract-xiso-win64-release.zip * + popd + pushd dist/extract-xiso_Win64_Debug + zip -r ../extract-xiso-win64-debug.zip * + popd + pushd dist/extract-xiso_linux + zip -r ../extract-xiso-linux.zip * + popd + pushd dist/extract-xiso_macOS + zip -r ../extract-xiso-macos.zip * + popd + pushd dist/extract-xiso_freebsd + zip -r ../extract-xiso-freebsd.zip * + popd + pushd dist/extract-xiso_openbsd + zip -r ../extract-xiso-openbsd.zip * + popd + pushd dist/extract-xiso_netbsd + zip -r ../extract-xiso-netbsd.zip * + popd - name: Get package info run: | echo "BUILD_TAG=$(cat dist/tag/tag)" >> $GITHUB_ENV @@ -166,36 +271,73 @@ jobs: asset_name: extract-xiso-win32-debug.zip asset_path: dist/extract-xiso-win32-debug.zip asset_content_type: application/zip - ### - # Comment out 64 bit builds as they are currently broken - ### - # - name: Upload release assets (Win64 build) - # id: upload-release-assets-win64-release - # uses: actions/upload-release-asset@v1.0.1 - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # with: - # upload_url: ${{ steps.create_release.outputs.upload_url }} - # asset_name: extract-xiso-win64-release.zip - # asset_path: dist/extract-xiso-win64-release.zip - # asset_content_type: application/zip - # - name: Upload release assets (Win64 debug build) - # id: upload-release-assets-win64-debug - # uses: actions/upload-release-asset@v1.0.1 - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # with: - # upload_url: ${{ steps.create_release.outputs.upload_url }} - # asset_name: extract-xiso-win64-debug.zip - # asset_path: dist/extract-xiso-win64-debug.zip - # asset_content_type: application/zip - # - name: Upload release assets (macOS build) - # id: upload-release-assets-macos-release - # uses: actions/upload-release-asset@v1.0.1 - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # with: - # upload_url: ${{ steps.create_release.outputs.upload_url }} - # asset_name: extract-xiso-macos.zip - # asset_path: dist/extract-xiso-macos.zip - # asset_content_type: application/zip + - name: Upload release assets (Win64 build) + id: upload-release-assets-win64-release + uses: actions/upload-release-asset@v1.0.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: extract-xiso-win64-release.zip + asset_path: dist/extract-xiso-win64-release.zip + asset_content_type: application/zip + - name: Upload release assets (Win64 debug build) + id: upload-release-assets-win64-debug + uses: actions/upload-release-asset@v1.0.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: extract-xiso-win64-debug.zip + asset_path: dist/extract-xiso-win64-debug.zip + asset_content_type: application/zip + - name: Upload release assets (Linux build) + id: upload-release-assets-linux-release + uses: actions/upload-release-asset@v1.0.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: extract-xiso-linux.zip + asset_path: dist/extract-xiso-linux.zip + asset_content_type: application/zip + - name: Upload release assets (macOS build) + id: upload-release-assets-macos-release + uses: actions/upload-release-asset@v1.0.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: extract-xiso-macos.zip + asset_path: dist/extract-xiso-macos.zip + asset_content_type: application/zip + - name: Upload release assets (FreeBSD build) + id: upload-release-assets-freebsd-release + uses: actions/upload-release-asset@v1.0.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: extract-xiso-freebsd.zip + asset_path: dist/extract-xiso-freebsd.zip + asset_content_type: application/zip + - name: Upload release assets (OpenBSD build) + id: upload-release-assets-openbsd-release + uses: actions/upload-release-asset@v1.0.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: extract-xiso-openbsd.zip + asset_path: dist/extract-xiso-openbsd.zip + asset_content_type: application/zip + - name: Upload release assets (NetBSD build) + id: upload-release-assets-netbsd-release + uses: actions/upload-release-asset@v1.0.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: extract-xiso-netbsd.zip + asset_path: dist/extract-xiso-netbsd.zip + asset_content_type: application/zip diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b54f64..c92b150 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,5 +23,10 @@ else() endif() add_executable(extract-xiso ${SOURCE_FILES}) target_compile_definitions(extract-xiso PRIVATE ${TARGET_OS}) +if(CMAKE_C_BYTE_ORDER MATCHES "^$") + set(CMAKE_C_BYTE_ORDER UNK_ENDIAN) +endif() +target_compile_definitions(extract-xiso PRIVATE CMAKE_ENDIANNESS=${CMAKE_C_BYTE_ORDER}) set_property(TARGET extract-xiso PROPERTY C_STANDARD 99) +set_property(TARGET extract-xiso PROPERTY C_EXTENSIONS OFF) install(TARGETS extract-xiso RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/appveyor.yml b/appveyor.yml index 4874b89..95f84d0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,12 +1,12 @@ image: -- Visual Studio 2017 +- Visual Studio 2022 configuration: - Release before_build: - cmd: |- mkdir build cd build - cmake .. -G "Visual Studio 15 2017" + cmake .. -G "Visual Studio 17 2022" build: project: c:\projects\extract-xiso\build\extract-xiso.sln after_build: diff --git a/extract-xiso.c b/extract-xiso.c index 5b9bcb1..aba6b1c 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -234,11 +234,13 @@ in */ -#if defined( __LINUX__ ) - #define _LARGEFILE64_SOURCE +#if defined(__linux__) + #define _LARGEFILE_SOURCE + #define _FILE_OFFSET_BITS 64 + #define _TIME_BITS 64 #endif -#if defined( __GNUC__ ) +#if defined(__GNUC__) #define _GNU_SOURCE #define unused __attribute__((__unused__)) #elif defined(_MSC_VER) @@ -271,13 +273,14 @@ #include #include -#if defined( __FREEBSD__ ) || defined( __OPENBSD__ ) - #include +#if defined(__FreeBSD__) || defined(__OpenBSD__) + #include #endif -#if defined( _WIN32 ) +#if defined(_WIN32) #include #include "win32/dirent.c" + #include "win32/getopt.c" #else #include #include @@ -285,98 +288,135 @@ #endif #if defined(_MSC_VER) + #include "win32/asprintf.c" #include - typedef SSIZE_T ssize_t; - #define strcasecmp _stricmp - #define strncasecmp _strnicmp #else #include #endif +#if defined(__APPLE__) && defined(__MACH__) + #define exiso_target "macOS" + + #include + #define bswap_16(x) OSSwapInt16(x) + #define bswap_32(x) OSSwapInt32(x) + #define bswap_64(x) OSSwapInt64(x) +#elif defined(__FreeBSD__) + #define exiso_target "FreeBSD" + + #include + #define bswap_16(x) bswap16(x) + #define bswap_32(x) bswap32(x) + #define bswap_64(x) bswap64(x) +#elif defined(__OpenBSD__) + #define exiso_target "OpenBSD" + + #include + #define bswap_16(x) swap16(x) + #define bswap_32(x) swap32(x) + #define bswap_64(x) swap64(x) +#elif defined(__NetBSD__) + #define exiso_target "NetBSD" + + #include + #include + #if defined(__BSWAP_RENAME) && !defined(__bswap_16) + #define bswap_16(x) bswap16(x) + #define bswap_32(x) bswap32(x) + #define bswap_64(x) bswap64(x) + #endif +#elif defined(__linux__) + #define exiso_target "Linux" + + #include +#elif defined(_WIN32) || defined(__CYGWIN__) + #define exiso_target "Windows" + + #if defined(_MSC_VER) + #define S_ISDIR(x) ((x) & _S_IFDIR) + #define S_ISREG(x) ((x) & _S_IFREG) + + typedef SSIZE_T ssize_t; + #define strcasecmp _stricmp + #define strncasecmp _strnicmp + #endif + + #if defined(__CYGWIN__) + #include + #else + #include + + #define lseek _lseeki64 + #define mkdir(a, b) _mkdir(a) + #define stat _stat64 + #define realpath(a, b) _fullpath(b, a, _MAX_PATH) + + #define bswap_16(x) _byteswap_ushort(x) + #define bswap_32(x) _byteswap_ulong(x) + #define bswap_64(x) _byteswap_uint64(x) + #endif +#else + #error unknown target, cannot compile! +#endif -#if defined( __DARWIN__ ) - #define exiso_target "macos-x" - - #define PATH_CHAR '/' - #define PATH_CHAR_STR "/" - - #define FORCE_ASCII 1 - #define READFLAGS O_RDONLY - #define WRITEFLAGS O_WRONLY | O_CREAT | O_TRUNC - #define READWRITEFLAGS O_RDWR +#if defined(_WIN32) || defined(__CYGWIN__) + #define PATH_CHAR '\\' + #define PATH_CHAR_STR "\\" - typedef off_t xoff_t; -#elif defined( __FREEBSD__ ) - #define exiso_target "freebsd" + #define READFLAGS O_RDONLY | O_BINARY + #define WRITEFLAGS O_WRONLY | O_CREAT | O_TRUNC | O_BINARY + #define READWRITEFLAGS O_RDWR | O_BINARY + typedef int64_t xoff_t; +#else #define PATH_CHAR '/' #define PATH_CHAR_STR "/" - #define FORCE_ASCII 1 #define READFLAGS O_RDONLY #define WRITEFLAGS O_WRONLY | O_CREAT | O_TRUNC #define READWRITEFLAGS O_RDWR typedef off_t xoff_t; -#elif defined( __LINUX__ ) - #define exiso_target "linux" - - #define PATH_CHAR '/' - #define PATH_CHAR_STR "/" - - #define FORCE_ASCII 0 - #define READFLAGS O_RDONLY | O_LARGEFILE - #define WRITEFLAGS O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE - #define READWRITEFLAGS O_RDWR | O_LARGEFILE - - #define lseek lseek64 - #define stat stat64 - - typedef off64_t xoff_t; -#elif defined( __OPENBSD__ ) - #define exiso_target "openbsd" -#elif defined( _WIN32 ) - #define exiso_target "win32" - - #define PATH_CHAR '\\' - #define PATH_CHAR_STR "\\" - - #define FORCE_ASCII 0 - #define READFLAGS O_RDONLY | O_BINARY - #define WRITEFLAGS O_WRONLY | O_CREAT | O_TRUNC | O_BINARY - #define READWRITEFLAGS O_RDWR | O_BINARY - - #define S_ISDIR( x ) ( ( x ) & _S_IFDIR ) - #define S_ISREG( x ) ( ( x ) & _S_IFREG ) - - #include "win32/getopt.c" -#if defined(_MSC_VER) - #include "win32/asprintf.c" #endif - #define lseek _lseeki64 - #define mkdir( a, b ) _mkdir( (a) ) - #define stat _stat64 - #define realpath(a, b) _fullpath(b, a, _MAX_PATH) - typedef int64_t xoff_t; +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) /* All BSD systems, but this macro is unused anyways */ + #define FORCE_ASCII 1 #else - #error unknown target, cannot compile! + #define FORCE_ASCII 0 #endif +#if CHAR_BIT != 8 + #error unsupported char size, cannot compile! +#endif -#define swap16( n ) ( ( n ) = ( n ) << 8 | ( n ) >> 8 ) -#define swap32( n ) ( ( n ) = ( n ) << 24 | ( ( ( n ) << 8 ) & 0xff0000 ) | ( ( ( n ) >> 8 ) & 0xff00 ) | ( n ) >> 24 ) +#if !defined(BIG_ENDIAN) + #define BIG_ENDIAN 1 + #define LITTLE_ENDIAN 0 +#endif +#define UNK_ENDIAN -1 + +#if defined(CMAKE_ENDIANNESS) + #if CMAKE_ENDIANNESS == BIG_ENDIAN + #define USE_BIG_ENDIAN + #elif CMAKE_ENDIANNESS != LITTLE_ENDIAN + #error unknown endianness, cannot compile! + #endif +#endif -#ifdef USE_BIG_ENDIAN - #define big16( n ) - #define big32( n ) - #define little16( n ) swap16( n ) - #define little32( n ) swap32( n ) +#if defined(USE_BIG_ENDIAN) + #define big16(n) + #define big32(n) + #define big64(n) + #define little16(n) ( (n) = bswap_16(n) ) + #define little32(n) ( (n) = bswap_32(n) ) + #define little64(n) ( (n) = bswap_64(n) ) #else - #define big16( n ) swap16( n ) - #define big32( n ) swap32( n ) - #define little16( n ) - #define little32( n ) + #define big16(n) ( (n) = bswap_16(n) ) + #define big32(n) ( (n) = bswap_32(n) ) + #define big64(n) ( (n) = bswap_64(n) ) + #define little16(n) + #define little32(n) + #define little64(n) #endif @@ -390,6 +430,7 @@ enum { false, true }; #endif +typedef int64_t file_time_t; #ifndef nil #define nil 0 @@ -576,11 +617,6 @@ struct create_list { create_list *next; }; -typedef struct FILE_TIME { - uint32_t l; - uint32_t h; -} FILE_TIME; - typedef struct wdsafp_context { xoff_t dir_start; uint32_t *current_sector; @@ -618,7 +654,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ); -FILE_TIME *alloc_filetime_now( void ); +int get_filetime_now( file_time_t *ft ); int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ); int generate_avl_tree_remote( dir_node_avl **out_root, int *io_n ); int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int in_depth ); @@ -951,7 +987,7 @@ int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ) { xoff_t pos = 0; dir_node_avl root = { 0 }; - FILE_TIME *ft = nil; + file_time_t ft = 0; write_tree_context wt_context = { 0 }; uint32_t start_sector = 0; int i = 0, n = 0, xiso = -1, err = 0; @@ -1052,8 +1088,8 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av memset( buf, 0, XISO_FILETIME_SIZE ); } else { - if ( ( ft = alloc_filetime_now() ) == nil ) mem_err(); - if ( ! err && write( xiso, ft, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) write_err(); + if ( ( err = get_filetime_now(&ft) ) ) misc_err("cannot get current time"); + if ( ! err && write( xiso, &ft, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) write_err(); } } if ( ! err && write( xiso, buf, XISO_UNUSED_SIZE ) != XISO_UNUSED_SIZE ) write_err(); @@ -1099,7 +1135,6 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av if ( root.filename ) free( root.filename ); if ( buf ) free( buf ); - if ( ft ) free( ft ); if ( cwd ) { if ( chdir( cwd ) == -1 ) chdir_err( cwd ); @@ -2020,28 +2055,18 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { } -FILE_TIME *alloc_filetime_now( void ) { - FILE_TIME *ft = nil; - double tmp = 0.0f; +int get_filetime_now(file_time_t *ft) { time_t now = 0; int err = 0; - if ( ( ft = (FILE_TIME *) malloc( sizeof(struct FILE_TIME) ) ) == nil ) mem_err(); - if ( ! err && ( now = time( nil ) ) == -1 ) unknown_err(); + if (ft == nil) return 1; + if ( ( now = time( nil ) ) == -1 ) unknown_err(); if ( ! err ) { - tmp = ( (double) now + ( 369.0 * 365.25 * 24 * 60 * 60 - ( 3.0 * 24 * 60 * 60 + 6.0 * 60 * 60 ) ) ) * 1.0e7; - - ft->h = (uint32_t) ( tmp * ( 1.0 / ( 4.0 * (double) ( 1 << 30 ) ) ) ); - ft->l = (uint32_t) ( tmp - ( (double) ft->h ) * 4.0 * (double) ( 1 << 30 ) ); - - little32( ft->h ); // convert to little endian here because this is a PC only struct and we won't read it anyway - little32( ft->l ); - } else if ( ft ) { - free( ft ); - ft = nil; + *ft = (now * 10000000LL) + 116444736000000000LL; // Magic numbers directly from Microsoft + little64(*ft); // convert to little endian here because this is a PC only struct and we won't read it anyway } - return ft; + return err; } // Found the CD-ROM layout in ECMA-119. Now burning software should correctly diff --git a/win32/getopt.c b/win32/getopt.c index 9cf84c5..e09dba3 100644 --- a/win32/getopt.c +++ b/win32/getopt.c @@ -56,7 +56,7 @@ * University of Illinois, Urbana-Champaign. */ -#ifdef WIN32 +#ifdef _WIN32 #include #include @@ -77,8 +77,8 @@ static int optiserr(int argc, char * const *argv, int oint, const char *optstr, int optchr, int err) { - argc; - optstr; + (void)argc; + (void)optstr; if(opterr) { From a029894eca58aef49b458127b54868ce436ea4c2 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Fri, 17 Mar 2023 16:20:57 +0100 Subject: [PATCH 20/59] Swallow the semicolon in function-like macros --- extract-xiso.c | 52 +++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index aba6b1c..c9c3528 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -480,24 +480,24 @@ typedef int64_t file_time_t; -v Print version information and exit.\n\ ", banner, argv[ 0 ], argv[ 0 ] ); -#define exiso_log(...) if ( ! s_quiet ) { printf(__VA_ARGS__); } -#define exiso_warn(...) if ( ! s_quiet ) { printf("\nWARNING: " __VA_ARGS__); s_warned = true; } -#define flush() if ( ! s_quiet ) { fflush( stdout ); } - -#define mem_err() { log_err( __FILE__, __LINE__, "out of memory error" ); err = 1; } -#define read_err() { log_err( __FILE__, __LINE__, "read error: %s", strerror( errno ) ); err = 1; } -#define seek_err() { log_err( __FILE__, __LINE__, "seek error: %s", strerror( errno ) ); err = 1; } -#define write_err() { log_err( __FILE__, __LINE__, "write error: %s", strerror( errno ) ); err = 1; } -#define rread_err() { log_err( __FILE__, __LINE__, "unable to read remote file" ); err = 1; } -#define rwrite_err() { log_err( __FILE__, __LINE__, "unable to write to remote file" ); err = 1; } -#define unknown_err() { log_err( __FILE__, __LINE__, "an unrecoverable error has occurred" ); err = 1; } -#define open_err( in_file ) { log_err( __FILE__, __LINE__, "open error: %s %s", ( in_file ), strerror( errno ) ); err = 1; } -#define chdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to change to directory %s: %s", ( in_dir ), strerror( errno ) ); err = 1; } -#define mkdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to create directory %s: %s", ( in_dir ), strerror( errno ) ); err = 1; } -#define ropen_err( in_file ) { log_err( __FILE__, __LINE__, "unable to open remote file %s", ( in_file ) ); err = 1; } -#define rchdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to change to remote directory %s", ( in_dir ) ); err = 1; } -#define rmkdir_err( in_dir ) { log_err( __FILE__, __LINE__, "unable to create remote directory %s", ( in_dir ) ); err = 1; } -#define misc_err( ... ) { log_err( __FILE__, __LINE__, __VA_ARGS__ ); err = 1; } +#define exiso_log(...) do{ if ( ! s_quiet ) { printf(__VA_ARGS__); } } while(0) +#define exiso_warn(...) do{ if ( ! s_quiet ) { printf("\nWARNING: " __VA_ARGS__); s_warned = true; } } while(0) +#define flush() do{ if ( ! s_quiet ) { fflush( stdout ); } } while(0) + +#define mem_err() do{ log_err( __FILE__, __LINE__, "out of memory error" ); err = 1; } while(0) +#define read_err() do{ log_err( __FILE__, __LINE__, "read error: %s", strerror( errno ) ); err = 1; } while(0) +#define seek_err() do{ log_err( __FILE__, __LINE__, "seek error: %s", strerror( errno ) ); err = 1; } while(0) +#define write_err() do{ log_err( __FILE__, __LINE__, "write error: %s", strerror( errno ) ); err = 1; } while(0) +#define rread_err() do{ log_err( __FILE__, __LINE__, "unable to read remote file" ); err = 1; } while(0) +#define rwrite_err() do{ log_err( __FILE__, __LINE__, "unable to write to remote file" ); err = 1; } while(0) +#define unknown_err() do{ log_err( __FILE__, __LINE__, "an unrecoverable error has occurred" ); err = 1; } while(0) +#define open_err( in_file ) do{ log_err( __FILE__, __LINE__, "open error: %s %s", ( in_file ), strerror( errno ) ); err = 1; } while(0) +#define chdir_err( in_dir ) do{ log_err( __FILE__, __LINE__, "unable to change to directory %s: %s", ( in_dir ), strerror( errno ) ); err = 1; } while(0) +#define mkdir_err( in_dir ) do{ log_err( __FILE__, __LINE__, "unable to create directory %s: %s", ( in_dir ), strerror( errno ) ); err = 1; } while(0) +#define ropen_err( in_file ) do{ log_err( __FILE__, __LINE__, "unable to open remote file %s", ( in_file ) ); err = 1; } while(0) +#define rchdir_err( in_dir ) do{ log_err( __FILE__, __LINE__, "unable to change to remote directory %s", ( in_dir ) ); err = 1; } while(0) +#define rmkdir_err( in_dir ) do{ log_err( __FILE__, __LINE__, "unable to create remote directory %s", ( in_dir ) ); err = 1; } while(0) +#define misc_err( ... ) do{ log_err( __FILE__, __LINE__, __VA_ARGS__ ); err = 1; } while(0) #ifndef min @@ -1122,7 +1122,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av if ( ! err && write( xiso, XISO_OPTIMIZED_TAG, XISO_OPTIMIZED_TAG_LENGTH ) != XISO_OPTIMIZED_TAG_LENGTH ) write_err(); if ( ! in_root ) { - if ( err ) { exiso_log( "\ncould not create %s%s\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "" ); } + if ( err ) exiso_log( "\ncould not create %s%s\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "" ); else exiso_log( "\nsucessfully created %s%s (%u files totalling %lld bytes added)\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "", s_total_files, s_total_bytes ); } @@ -1207,7 +1207,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat } if (!err) { - if (asprintf(&buf, "%s%s%s%c", in_path ? in_path : "", add_slash && (!in_path) ? PATH_CHAR_STR : "", in_mode != k_list && (!in_path) ? iso_name : "", PATH_CHAR) == -1) mem_err() + if (asprintf(&buf, "%s%s%s%c", in_path ? in_path : "", add_slash && (!in_path) ? PATH_CHAR_STR : "", in_mode != k_list && (!in_path) ? iso_name : "", PATH_CHAR) == -1) mem_err(); root_dir_start = (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek; root_end_offset = (uint16_t)(n_sectors(root_dir_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE); @@ -1693,15 +1693,13 @@ int extract_file(int in_xiso, dir_node *in_file, modes in_mode, char* path) { if ( ! err ) { exiso_log("\n"); - if (in_file->file_size == 0) { - exiso_log("%s%s%s (0 bytes) [100%%]\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename); - } + if (in_file->file_size == 0) exiso_log("%s%s%s (0 bytes) [100%%]\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename); else { i = 0; size = min(in_file->file_size, READWRITE_BUFFER_SIZE); do { read_size = read(in_xiso, s_copy_buffer, size); - if (read_size < 0) { read_err(); } + if (read_size < 0) read_err(); else if (in_mode == k_extract && read_size != 0) { if (write(out, s_copy_buffer, read_size) != read_size) write_err(); } @@ -1818,7 +1816,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int xbe_file = len >= 4 && strcasecmp(&in_avl->filename[len - 4], ".xbe") == 0; do { n = read(fd, buf + i, min(bytes, size - i)); - if (n < 0) { read_err(); } + if (n < 0) read_err(); else if (n == 0) { // Unexpected end of file if (i > 0 && write(in_context->xiso, buf, i) != i) write_err(); // Write remaining 'i' bytes } @@ -1848,9 +1846,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int } exiso_log(err ? "failed" : "[OK]"); - if (!err && size != in_avl->file_size) { - exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", in_avl->filename, size, in_avl->file_size); - } + if (!err && size != in_avl->file_size) exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", in_avl->filename, size, in_avl->file_size); if (!err) { ++s_total_files; From 80e7d5da85b483f830a3f1b9088e67f2da6721f1 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Fri, 17 Mar 2023 14:39:27 +0100 Subject: [PATCH 21/59] Simplify free_dir_node_avl --- extract-xiso.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index c9c3528..1da4f60 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -646,7 +646,7 @@ void boyer_moore_done(); char *boyer_moore_search( char *in_text, long in_text_len ); int boyer_moore_init( char *in_pattern, long in_pat_len, long in_alphabet_size ); -int free_dir_node_avl(void* in_dir_node_avl, void* in_context, int in_depth); +int free_dir_node_avl(dir_node_avl* in_dir_node_avl, void* in_context, int in_depth); int extract_file( int in_xiso, dir_node *in_file, modes in_mode, char *path ); int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ); int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, char *in_iso_name ); @@ -1126,7 +1126,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av else exiso_log( "\nsucessfully created %s%s (%u files totalling %lld bytes added)\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "", s_total_files, s_total_bytes ); } - if ( root.subdirectory != EMPTY_SUBDIRECTORY ) avl_traverse_depth_first( root.subdirectory, free_dir_node_avl, nil, k_postfix, 0 ); + if ( root.subdirectory != EMPTY_SUBDIRECTORY ) avl_traverse_depth_first( root.subdirectory, (traversal_callback) free_dir_node_avl, nil, k_postfix, 0 ); if ( xiso != -1 ) { close( xiso ); @@ -1725,13 +1725,11 @@ int extract_file(int in_xiso, dir_node *in_file, modes in_mode, char* path) { } -int free_dir_node_avl( void *in_dir_node_avl, unused void *in_context, unused int in_depth ) { - dir_node_avl *avl = (dir_node_avl *) in_dir_node_avl; - - if ( avl->subdirectory && avl->subdirectory != EMPTY_SUBDIRECTORY ) avl_traverse_depth_first( avl->subdirectory, free_dir_node_avl, nil, k_postfix, 0 ); +int free_dir_node_avl( dir_node_avl *in_dir_node_avl, unused void *in_context, unused int in_depth ) { + if (in_dir_node_avl->subdirectory && in_dir_node_avl->subdirectory != EMPTY_SUBDIRECTORY) avl_traverse_depth_first(in_dir_node_avl->subdirectory, (traversal_callback)free_dir_node_avl, nil, k_postfix, 0); - free( avl->filename ); - free( avl ); + free(in_dir_node_avl->filename); + free(in_dir_node_avl); return 0; } From 6928e892bcbad4e93464ac841122092df00c9e8f Mon Sep 17 00:00:00 2001 From: rapperskull Date: Fri, 17 Mar 2023 18:23:18 +0100 Subject: [PATCH 22/59] Rewrite usage macro to include exit and print to stdout when using -h flag (this way the help can be piped to more or less) Move usage to a function, potentially reducing binary size --- extract-xiso.c | 125 +++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 67 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 1da4f60..12bd413 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -442,43 +442,7 @@ typedef int64_t file_time_t; #define banner "extract-xiso v" exiso_version " for " exiso_target " - written by in \n" -#define usage() fprintf( stderr, \ -"%s\n\ - Usage:\n\ -\n\ - %s [options] [-[lrx]] [file2.xiso] ...\n\ - %s [options] -c [name] [-c [name]] ...\n\ -\n\ - Mutually exclusive modes:\n\ -\n\ - -c [name] Create xiso from file(s) starting in . If the\n\ - [name] parameter is specified, the xiso will be\n\ - created with the (path and) name given, otherwise\n\ - the xiso will be created in the current directory\n\ - with the name .iso. The -c option may be\n\ - specified multiple times to create multiple xiso\n\ - images.\n\ - -l List files in xiso(s).\n\ - -r Rewrite xiso(s) as optimized xiso(s).\n\ - -x Extract xiso(s) (the default mode if none is given).\n\ - If no directory is specified with -d, a directory\n\ - with the name of the xiso (minus the .iso portion)\n\ - will be created in the current directory and the\n\ - xiso will be expanded there.\n\ -\n\ - Options:\n\ -\n\ - -d In extract mode, expand xiso in .\n\ - In rewrite mode, rewrite xiso in .\n\ - -D In rewrite mode, delete old xiso after processing.\n\ - -h Print this help text and exit.\n\ - -m In create or rewrite mode, disable automatic .xbe\n\ - media enable patching (not recommended).\n\ - -q Run quiet (suppress all non-error output).\n\ - -Q Run silent (suppress all output).\n\ - -s Skip $SystemUpdate folder.\n\ - -v Print version information and exit.\n\ -", banner, argv[ 0 ], argv[ 0 ] ); +#define usage_and_exit(n) print_usage_and_exit(n, argv[0]) #define exiso_log(...) do{ if ( ! s_quiet ) { printf(__VA_ARGS__); } } while(0) #define exiso_warn(...) do{ if ( ! s_quiet ) { printf("\nWARNING: " __VA_ARGS__); s_warned = true; } } while(0) @@ -631,6 +595,7 @@ typedef struct write_tree_context { } write_tree_context; +void print_usage_and_exit(int ret, char* name); xoff_t lseek_with_error(int fd, xoff_t offset, int whence); int log_err( const char *in_file, int in_line, const char *in_format, ... ); void avl_rotate_left( dir_node_avl **in_root ); @@ -704,15 +669,12 @@ int main( int argc, char **argv ) { bool extract = true, rewrite = false, x_seen = false, delete = false, optimized; char *path = nil, *buf = nil, *new_iso_path = nil, tag[XISO_OPTIMIZED_TAG_LENGTH + 1]; - if ( argc < 2 ) { usage(); exit( 1 ); } + if (argc < 2) usage_and_exit(1); while ( ! err && ( opt_char = getopt( argc, argv, GETOPT_STRING ) ) != -1 ) { switch ( opt_char ) { case 'c': { - if ( x_seen || rewrite || ! extract ) { - usage(); - exit( 1 ); - } + if (x_seen || rewrite || !extract) usage_and_exit(1); for ( r = &create; *r != nil; r = &(*r)->next ) ; @@ -736,23 +698,16 @@ int main( int argc, char **argv ) { } break; case 'h': { - usage(); - exit( 0 ); + usage_and_exit(0); } break; case 'l': { - if ( x_seen || rewrite || create ) { - usage(); - exit( 1 ); - } + if ( x_seen || rewrite || create ) usage_and_exit(1); extract = false; } break; case 'm': { - if ( x_seen || ! extract ) { - usage(); - exit( 1 ); - } + if ( x_seen || ! extract ) usage_and_exit(1); s_media_enable = false; } break; @@ -765,10 +720,7 @@ int main( int argc, char **argv ) { } break; case 'r': { - if ( x_seen || ! extract || create ) { - usage(); - exit( 1 ); - } + if ( x_seen || ! extract || create ) usage_and_exit(1); rewrite = true; } break; @@ -777,31 +729,29 @@ int main( int argc, char **argv ) { } break; case 'v': { - printf( "%s", banner ); - exit( 0 ); + printf(banner); + exit(0); } break; case 'x': { - if ( ! extract || rewrite || create ) { - usage(); - exit( 1 ); - } + if ( ! extract || rewrite || create ) usage_and_exit(1); x_seen = true; } break; default: { - usage(); - exit( 1 ); + usage_and_exit(1); } break; } } if ( ! err ) { - if ( create ) { if ( optind < argc ) { usage(); exit( 1 ); } } - else if ( optind >= argc ) { usage(); exit( 1 ); } + if (create) { + if (optind < argc) usage_and_exit(1); + } + else if (optind >= argc) usage_and_exit(1); - exiso_log( "%s", banner ); + exiso_log(banner); if ( ( extract ) && ( s_copy_buffer = (char *) malloc( READWRITE_BUFFER_SIZE ) ) == nil ) mem_err(); } @@ -901,6 +851,47 @@ int main( int argc, char **argv ) { return err; } +void print_usage_and_exit(int ret, char* name) { + fprintf(ret ? stderr : stdout, banner "\n\ + Usage:\n\ +\n\ + %s [options] [-[lrx]] [file2.xiso] ...\n\ + %s [options] -c [name] [-c [name]] ...\n\ +\n\ + Mutually exclusive modes:\n\ +\n\ + -c [name] Create xiso from file(s) starting in . If the\n\ + [name] parameter is specified, the xiso will be\n\ + created with the (path and) name given, otherwise\n\ + the xiso will be created in the current directory\n\ + with the name .iso. The -c option may be\n\ + specified multiple times to create multiple xiso\n\ + images.\n\ + -l List files in xiso(s).\n\ + -r Rewrite xiso(s) as optimized xiso(s).\n\ + -x Extract xiso(s) (the default mode if none is given).\n\ + If no directory is specified with -d, a directory\n\ + with the name of the xiso (minus the .iso portion)\n\ + will be created in the current directory and the\n\ + xiso will be expanded there.\n\ +\n\ + Options:\n\ +\n\ + -d In extract mode, expand xiso in .\n\ + In rewrite mode, rewrite xiso in .\n\ + -D In rewrite mode, delete old xiso after processing.\n\ + -h Print this help text and exit.\n\ + -m In create or rewrite mode, disable automatic .xbe\n\ + media enable patching (not recommended).\n\ + -q Run quiet (suppress all non-error output).\n\ + -Q Run silent (suppress all output).\n\ + -s Skip $SystemUpdate folder.\n\ + -v Print version information and exit.\n\ +", name, name); + fflush(ret ? stderr : stdout); + exit(ret); +} + /* Wrapper to avoid changing old code, since lseek will not return error if offset is beyond end of file. Use only on input. */ xoff_t lseek_with_error(int fd, xoff_t offset, int whence) { xoff_t pos = lseek(fd, offset, whence); // First execute the seek, to save the offset From 3dd329763bcc5af63b98779c27132164cbc230f3 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sat, 18 Mar 2023 17:53:49 +0100 Subject: [PATCH 23/59] Fix calculation of total size and files number across isos --- extract-xiso.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 12bd413..4a350a7 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -828,7 +828,11 @@ int main( int argc, char **argv ) { } } - if ( ! err ) exiso_log( "\n\n%u files in %s total %lld bytes\n", s_total_files, rewrite ? new_iso_path : argv[ i ], s_total_bytes ); + if (!err) { + exiso_log("\n\n%u files in %s total %lld bytes\n", s_total_files, rewrite ? new_iso_path : argv[i], s_total_bytes); + s_total_files_all_isos += s_total_files; + s_total_bytes_all_isos += s_total_bytes; + } if ( new_iso_path ) { if ( ! err ) exiso_log( "\n%s successfully rewritten%s%s\n", argv[ i ], path ? " as " : ".", path ? new_iso_path : "" ); @@ -1397,9 +1401,7 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ } ++s_total_files; - ++s_total_files_all_isos; s_total_bytes += node->file_size; - s_total_bytes_all_isos += node->file_size; } } } From c9dacc328557dad87a1ddd1ae23808e6324c5d38 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sun, 19 Mar 2023 21:43:32 +0100 Subject: [PATCH 24/59] Fix typo and spacing, use tabulation to align output Print root in listing and extracting mode Simplify path generation in decode_xiso Better check for iso name and path in decode_xiso Ignore destination path in listing mode --- extract-xiso.c | 126 ++++++++++++++++++++++--------------------------- 1 file changed, 57 insertions(+), 69 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 4a350a7..696c4bb 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -823,7 +823,7 @@ int main( int argc, char **argv ) { if ( buf ) free( buf ); } else { // the order of the mutually exclusive options here is important, the extract ? k_extract : k_list test *must* be the final comparison - if ( ! err ) err = decode_xiso( argv[ i ], path, extract ? k_extract : k_list, nil ); + if ( ! err ) err = decode_xiso( argv[ i ], extract ? path : nil, extract ? k_extract : k_list, nil ); } } } @@ -1019,7 +1019,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av if ( ! err ) { exiso_log( "\n%s %s%s:\n", in_root ? "rewriting" : "creating", iso_name, in_name ? "" : ".iso" ); - root.start_sector = XISO_ROOT_DIRECTORY_SECTOR; + root.start_sector = XISO_ROOT_DIRECTORY_SECTOR; s_total_bytes = s_total_files = 0; @@ -1118,9 +1118,9 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av if ( ! in_root ) { if ( err ) exiso_log( "\ncould not create %s%s\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "" ); - else exiso_log( "\nsucessfully created %s%s (%u files totalling %lld bytes added)\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "", s_total_files, s_total_bytes ); + else exiso_log( "\n\nsuccessfully created %s%s (%u files totalling %lld bytes added)\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "", s_total_files, s_total_bytes ); } - + if ( root.subdirectory != EMPTY_SUBDIRECTORY ) avl_traverse_depth_first( root.subdirectory, (traversal_callback) free_dir_node_avl, nil, k_postfix, 0 ); if ( xiso != -1 ) { @@ -1142,87 +1142,75 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ) { dir_node_avl *root = nil; - bool repair = false; xoff_t root_dir_start; uint32_t root_dir_sect = 0, root_dir_size = 0; uint16_t root_end_offset; - int xiso = 0, err = 0, len = 0, path_len = 0, add_slash = 0; - char *buf = nil, *cwd = nil, *name = nil, *short_name = nil, *iso_name = nil; + size_t len; + int xiso = 0, err = 0; + char *path = nil, *cwd = nil, *name = nil, *short_name = nil, *iso_name = nil; - if ( ( xiso = open( in_xiso, READFLAGS, 0 ) ) == -1 ) open_err( in_xiso ); + if ((xiso = open(in_xiso, READFLAGS, 0)) == -1) open_err(in_xiso); - if ( ! err ) { - len = (int) strlen( in_xiso ); - - if ( in_mode == k_rewrite ) { - in_xiso[ len -= 4 ] = 0; - repair = true; - } - + if (in_mode == k_rewrite) in_xiso[strlen(in_xiso) - 4] = '\0'; + + if (!err) { if ((name = strrchr(in_xiso, PATH_CHAR))) name++; else name = in_xiso; - - len = (int) strlen( name ); - + // create a directory of the same name as the file we are working on, minus the ".iso" portion - if (len > 4 && strcasecmp(&name[len - 4], ".iso") == 0) { - name[ len -= 4 ] = 0; - if ( ( short_name = strdup( name ) ) == nil ) mem_err(); - name[ len ] = '.'; + if ((len = strlen(name)) >= 4 && strcasecmp(&name[len - 4], ".iso") == 0) { + name[len - 4] = '\0'; + if ((short_name = strdup(name)) == nil) mem_err(); + name[len - 4] = '.'; } + + iso_name = short_name ? short_name : name; } - if ( ! err && ! len ) misc_err( "invalid xiso image name: %s", in_xiso ); + if (!err && in_path && (len = strlen(in_path)) > 0) { + if (in_path[len - 1] == '/' || in_path[len - 1] == '\\') in_path[len - 1] = '\0'; + } - if ( ! err && in_mode == k_extract && in_path ) { - if ( ( cwd = getcwd( nil, 0 ) ) == nil ) mem_err(); - if ( ! err && mkdir( in_path, 0755 ) == -1 ) mkdir_err( in_path ); - if ( ! err && chdir( in_path ) == -1 ) chdir_err( in_path ); + if (!err && in_mode == k_extract) { + if (in_path) { + if (strlen(in_path) == 0) misc_err("empty destination path"); + if (!err && (cwd = getcwd(nil, 0)) == nil) mem_err(); + if (!err && mkdir(in_path, 0755) == -1) mkdir_err(in_path); + if (!err && chdir(in_path) == -1) chdir_err(in_path); + } + else { + if (strlen(iso_name) == 0) misc_err("invalid xiso image name: %s", in_xiso); + if (!err && mkdir(iso_name, 0755) == -1) mkdir_err(iso_name); + if (!err && chdir(iso_name) == -1) chdir_err(iso_name); + } } - if ( ! err ) err = verify_xiso( xiso, &root_dir_sect, &root_dir_size, name ); + if (!err) err = verify_xiso(xiso, &root_dir_sect, &root_dir_size, name); - iso_name = short_name ? short_name : name; + if (!err && in_mode != k_rewrite) exiso_log("\n%s %s:\n", in_mode == k_extract ? "extracting" : "listing", name); - if ( ! err && in_mode != k_rewrite ) { - exiso_log( "\n%s %s:\n", in_mode == k_extract ? "extracting" : "listing", name ); + if (!err) { + if (asprintf(&path, "%s%c", in_path ? in_path : (in_mode != k_list ? iso_name : ""), PATH_CHAR) == -1) mem_err(); - if ( in_mode == k_extract ) { - if ( ! in_path ) { - if ( ( err = mkdir( iso_name, 0755 ) ) ) mkdir_err( iso_name ); - if ( ! err && ( err = chdir( iso_name ) ) ) chdir_err( iso_name ); - } - } - } + root_dir_start = (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek; + root_end_offset = (uint16_t)(n_sectors(root_dir_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE); - if ( ! err ) { - if ( in_path ) { - path_len = (int) strlen( in_path ); - if ( in_path[ path_len - 1 ] != PATH_CHAR ) ++add_slash; - } + if (!err && lseek_with_error(xiso, root_dir_start, SEEK_SET) == -1) seek_err(); - if (!err) { - if (asprintf(&buf, "%s%s%s%c", in_path ? in_path : "", add_slash && (!in_path) ? PATH_CHAR_STR : "", in_mode != k_list && (!in_path) ? iso_name : "", PATH_CHAR) == -1) mem_err(); - - root_dir_start = (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek; - root_end_offset = (uint16_t)(n_sectors(root_dir_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE); - - if (!err && lseek_with_error(xiso, root_dir_start, SEEK_SET) == -1) seek_err(); - - if ( in_mode == k_rewrite ) { - if (!err && root_dir_size == 0) root = EMPTY_SUBDIRECTORY; - else { - if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, k_generate_avl, &root, tree_strategy); - if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, k_generate_avl, &root, discover_strategy); - } - if (!err) err = create_xiso(iso_name, in_path, root, xiso, out_iso_path, nil, nil); - } + if (in_mode == k_rewrite) { + if (!err && root_dir_size == 0) root = EMPTY_SUBDIRECTORY; else { - if (!err && root_dir_size != 0) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, buf, in_mode, nil, discover_strategy); + if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, k_generate_avl, &root, tree_strategy); + if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, k_generate_avl, &root, discover_strategy); } - - if(buf) free(buf); + if (!err) err = create_xiso(iso_name, in_path, root, xiso, out_iso_path, nil, nil); + } + else { + exiso_log("\n%s%s (0 bytes)%s", in_mode == k_extract ? "creating\t" : "", path, in_mode == k_extract ? " [OK]" : ""); flush(); + if (!err && root_dir_size != 0) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, in_mode, nil, discover_strategy); } + + if(path) free(path); } if ( err == err_iso_rewritten ) err = 0; @@ -1236,7 +1224,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat free( cwd ); } - if ( repair ) in_xiso[ strlen( in_xiso ) ] = '.'; + if (in_mode == k_rewrite) in_xiso[strlen(in_xiso)] = '.'; return err; } @@ -1365,7 +1353,7 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ if (!err && (err = chdir(node->filename))) chdir_err(node->filename); } if (!err && in_mode != k_generate_avl) { - exiso_log("\n%s%s%s%s (0 bytes)%s", in_mode == k_extract ? "creating " : "", in_path, node->filename, PATH_CHAR_STR, in_mode == k_extract ? " [OK]" : ""); flush(); + exiso_log("\n%s%s%s%s (0 bytes)%s", in_mode == k_extract ? "creating\t" : "", in_path, node->filename, PATH_CHAR_STR, in_mode == k_extract ? " [OK]" : ""); flush(); } } } @@ -1686,7 +1674,7 @@ int extract_file(int in_xiso, dir_node *in_file, modes in_mode, char* path) { if ( ! err ) { exiso_log("\n"); - if (in_file->file_size == 0) exiso_log("%s%s%s (0 bytes) [100%%]\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename); + if (in_file->file_size == 0) exiso_log("%s%s%s (0 bytes) [100%%]\r", in_mode == k_extract ? "extracting\t" : "", path, in_file->filename); else { i = 0; size = min(in_file->file_size, READWRITE_BUFFER_SIZE); @@ -1699,7 +1687,7 @@ int extract_file(int in_xiso, dir_node *in_file, modes in_mode, char* path) { if (!err) { totalsize += read_size; totalpercent = (totalsize * 100.0f) / in_file->file_size; - exiso_log("%s%s%s (%u bytes) [%.1f%%]\r", in_mode == k_extract ? "extracting " : "", path, in_file->filename, in_file->file_size, totalpercent); + exiso_log("%s%s%s (%u bytes) [%.1f%%]\r", in_mode == k_extract ? "extracting\t" : "", path, in_file->filename, in_file->file_size, totalpercent); i += read_size; size = min(in_file->file_size - i, READWRITE_BUFFER_SIZE); @@ -1739,7 +1727,7 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int else { if ( asprintf( &context.path, "%c", PATH_CHAR ) == -1 ) mem_err(); } if ( ! err ) { - exiso_log( "\nadding %s (0 bytes) [OK]", context.path ); + exiso_log( "\nadding\t%s (0 bytes) [OK]", context.path ); if ( in_avl->subdirectory != EMPTY_SUBDIRECTORY ) { context.xiso = in_context->xiso; @@ -1800,7 +1788,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int } if ( ! err ) { - exiso_log( "\nadding %s%s (%u bytes) ", in_context->path, in_avl->filename, in_avl->file_size ); flush(); + exiso_log( "\nadding\t%s%s (%u bytes) ", in_context->path, in_avl->filename, in_avl->file_size ); flush(); bytes = in_avl->file_size; len = strlen(in_avl->filename); From c76c66a541028af09b84eab62b64700643047ea0 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Mon, 20 Mar 2023 23:16:08 +0100 Subject: [PATCH 25/59] Add const qualifiers where possible --- extract-xiso.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 696c4bb..9d48204 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -595,29 +595,29 @@ typedef struct write_tree_context { } write_tree_context; -void print_usage_and_exit(int ret, char* name); +void print_usage_and_exit(int ret, const char* name); xoff_t lseek_with_error(int fd, xoff_t offset, int whence); int log_err( const char *in_file, int in_line, const char *in_format, ... ); void avl_rotate_left( dir_node_avl **in_root ); void avl_rotate_right( dir_node_avl **in_root ); -int avl_compare_key( char *in_lhs, char *in_rhs ); +int avl_compare_key( const char *in_lhs, const char *in_rhs ); avl_result avl_left_grown( dir_node_avl **in_root ); avl_result avl_right_grown( dir_node_avl **in_root ); -dir_node_avl *avl_fetch( dir_node_avl *in_root, char *in_filename ); +dir_node_avl *avl_fetch( dir_node_avl *in_root, const char *in_filename ); avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ); int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, int in_depth ); void boyer_moore_done(); char *boyer_moore_search( char *in_text, long in_text_len ); -int boyer_moore_init( char *in_pattern, long in_pat_len, long in_alphabet_size ); +int boyer_moore_init( const char *in_pattern, long in_pat_len, long in_alphabet_size ); int free_dir_node_avl(dir_node_avl* in_dir_node_avl, void* in_context, int in_depth); -int extract_file( int in_xiso, dir_node *in_file, modes in_mode, char *path ); +int extract_file( int in_xiso, dir_node *in_file, modes in_mode, const char *path ); int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ); -int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, char *in_iso_name ); -int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); -int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); -int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ); +int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, const char *in_iso_name ); +int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); +int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); +int create_xiso( char *in_root_directory, const char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ); int get_filetime_now( file_time_t *ft ); int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ); @@ -633,13 +633,13 @@ int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ); #if DEBUG -void write_sector( int in_xiso, xoff_t in_start, char *in_name, char *in_extension ); +void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char *in_extension ); #endif static long s_pat_len; static bool s_quiet = false; -static char *s_pattern = nil; +static const char *s_pattern = nil; static long *s_gs_table = nil; static long *s_bc_table = nil; static long long s_total_bytes = 0; @@ -855,7 +855,7 @@ int main( int argc, char **argv ) { return err; } -void print_usage_and_exit(int ret, char* name) { +void print_usage_and_exit(int ret, const char* name) { fprintf(ret ? stderr : stdout, banner "\n\ Usage:\n\ \n\ @@ -944,7 +944,7 @@ int log_err(unused_release const char* in_file, unused_release int in_line, cons #endif -int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, char *in_iso_name ) { +int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, const char *in_iso_name ) { int i, err = 0; char buffer[XISO_HEADER_DATA_LENGTH]; @@ -979,7 +979,7 @@ int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_ -int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ) { +int create_xiso( char *in_root_directory, const char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ) { xoff_t pos = 0; dir_node_avl root = { 0 }; file_time_t ft = 0; @@ -1230,7 +1230,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat } -int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { +int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { dir_node_avl *avl = nil; dir_node *node = nil; uint16_t l_offset = 0, r_offset = 0; @@ -1335,7 +1335,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 return err; } -int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { +int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { char *path = nil; int err = 0; xoff_t dir_start = (xoff_t)node->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; @@ -1403,7 +1403,7 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_ #endif -dir_node_avl *avl_fetch( dir_node_avl *in_root, char *in_filename ) { +dir_node_avl *avl_fetch( dir_node_avl *in_root, const char *in_filename ) { int result; for ( ;; ) { @@ -1531,7 +1531,7 @@ void avl_rotate_right( dir_node_avl **in_root ) { } -int avl_compare_key( char *in_lhs, char *in_rhs ) { +int avl_compare_key( const char *in_lhs, const char *in_rhs ) { char a, b; for ( ;; ) { @@ -1587,7 +1587,7 @@ int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callb #endif -int boyer_moore_init( char *in_pattern, long in_pat_len, long in_alphabet_size ) { +int boyer_moore_init( const char *in_pattern, long in_pat_len, long in_alphabet_size ) { long i, j, k, *backup, err = 0; s_pattern = in_pattern; @@ -1657,7 +1657,7 @@ char *boyer_moore_search( char *in_text, long in_text_len ) { #endif -int extract_file(int in_xiso, dir_node *in_file, modes in_mode, char* path) { +int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const char* path) { int err = 0; xoff_t file_start = (xoff_t)in_file->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; uint32_t i, size, totalsize = 0; @@ -2094,7 +2094,7 @@ int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ) { #if DEBUG -void write_sector( int in_xiso, xoff_t in_start, char *in_name, char *in_extension ) { +void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char *in_extension ) { ssize_t wrote; xoff_t curpos = 0; int fp = -1, err = 0; From 481ab8d91aaf83027025987a5f42b3a3636bf2bd Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 21 Mar 2023 01:00:46 +0100 Subject: [PATCH 26/59] Simplify main a bit --- extract-xiso.c | 106 ++++++++++++++++++++++++------------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 9d48204..68d7fe9 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -664,10 +664,12 @@ static xoff_t s_xbox_disc_lseek = 0; int main( int argc, char **argv ) { struct stat sb; - create_list *create = nil, *p, *q, **r; + create_list *create = nil, *p, *q; int i, fd, opt_char, err = 0, isos = 0; bool extract = true, rewrite = false, x_seen = false, delete = false, optimized; - char *path = nil, *buf = nil, *new_iso_path = nil, tag[XISO_OPTIMIZED_TAG_LENGTH + 1]; + ptrdiff_t diff; + char *path = nil, *buf = nil, *new_iso_path = nil; + char tag[XISO_OPTIMIZED_TAG_LENGTH + 1]; if (argc < 2) usage_and_exit(1); @@ -675,17 +677,17 @@ int main( int argc, char **argv ) { switch ( opt_char ) { case 'c': { if (x_seen || rewrite || !extract) usage_and_exit(1); - - for ( r = &create; *r != nil; r = &(*r)->next ) ; - if ( ( *r = (create_list *) malloc( sizeof(create_list) ) ) == nil ) mem_err(); - if ( ! err ) { - (*r)->name = nil; - (*r)->next = nil; - - if ( ( (*r)->path = strdup( optarg ) ) == nil ) mem_err(); + if (create == nil) { + if ((p = create = (create_list*)calloc(1, sizeof(create_list))) == nil) mem_err(); } - if ( ! err && argv[ optind ] && *argv[ optind ] != '-' && *argv[ optind ] && ( (*r)->name = strdup( argv[ optind++ ] ) ) == nil ) mem_err(); + else { + p = create; + while (p != nil && p->next != nil) p = p->next; + if ((p = p->next = (create_list*)calloc(1, sizeof(create_list))) == nil) mem_err(); + } + if (!err && (p->path = strdup(optarg)) == nil) mem_err(); + if (!err && argv[optind] && *argv[optind] != '-' && *argv[optind] && (p->name = strdup(argv[optind++])) == nil) mem_err(); } break; case 'd': { @@ -759,28 +761,27 @@ int main( int argc, char **argv ) { if ( ! err && ( create || rewrite ) ) err = boyer_moore_init( XISO_MEDIA_ENABLE, XISO_MEDIA_ENABLE_LENGTH, k_default_alphabet_size ); if ( ! err && create ) { - for ( p = create; ! err && p != nil; ) { - char* tmp = nil; - ptrdiff_t diff = 0; - - if ( p->name && (tmp = strrchr(p->name, PATH_CHAR)) ) { - diff = tmp - p->name; - if ( ( tmp = (char *) malloc( diff + 1 ) ) == nil ) mem_err(); + p = create; + while (!err && p != nil) { + diff = 0; + if ( p->name && (buf = strrchr(p->name, PATH_CHAR)) ) { + diff = buf - p->name; + if ( ( buf = (char *) malloc( diff + 1 ) ) == nil ) mem_err(); if ( ! err ) { - strncpy( tmp, p->name, diff ); - tmp[ diff ] = 0; + strncpy( buf, p->name, diff ); + buf[ diff ] = 0; } diff += 1; } - if ( ! err ) err = create_xiso( p->path, tmp, nil, -1, nil, p->name ? p->name + diff : nil, nil ); + if ( ! err ) err = create_xiso( p->path, buf, nil, -1, nil, p->name ? p->name + diff : nil, nil ); - if ( tmp ) free( tmp ); + if (buf) { free(buf); buf = nil; } q = p->next; if ( p->name ) free( p->name ); - free( p->path ); + if ( p->path ) free( p->path ); free( p ); p = q; @@ -788,43 +789,42 @@ int main( int argc, char **argv ) { } else for ( i = optind; ! err && i < argc; ++i ) { ++isos; s_total_bytes = s_total_files = 0; + optimized = false; - - if ( ! err ) { - optimized = false; - - if ( ( fd = open( argv[ i ], READFLAGS, 0 ) ) == -1 ) open_err( argv[ i ] ); - if ( ! err && lseek_with_error( fd, (xoff_t) XISO_OPTIMIZED_TAG_OFFSET, SEEK_SET ) == -1 ) seek_err(); - if ( ! err && read( fd, tag, XISO_OPTIMIZED_TAG_LENGTH ) != XISO_OPTIMIZED_TAG_LENGTH ) read_err(); + if ( ( fd = open( argv[ i ], READFLAGS, 0 ) ) == -1 ) open_err( argv[ i ] ); + if ( ! err && lseek_with_error( fd, (xoff_t) XISO_OPTIMIZED_TAG_OFFSET, SEEK_SET ) == -1 ) seek_err(); + if ( ! err && read( fd, tag, XISO_OPTIMIZED_TAG_LENGTH ) != XISO_OPTIMIZED_TAG_LENGTH ) read_err(); - if ( fd != -1 ) close( fd ); + if ( fd != -1 ) close( fd ); - if ( ! err ) { - tag[ XISO_OPTIMIZED_TAG_LENGTH ] = 0; + if ( ! err ) { + tag[ XISO_OPTIMIZED_TAG_LENGTH ] = 0; - if ( ! strncmp( tag, XISO_OPTIMIZED_TAG, XISO_OPTIMIZED_TAG_LENGTH_MIN ) ) optimized = true; + if ( ! strncmp( tag, XISO_OPTIMIZED_TAG, XISO_OPTIMIZED_TAG_LENGTH_MIN ) ) optimized = true; - if ( rewrite ) { - if ( optimized ) { - exiso_log( "\n%s is already optimized, skipping...\n", argv[ i ] ); - continue; - } + if ( rewrite ) { + if ( optimized ) { + exiso_log( "\n%s is already optimized, skipping...\n", argv[ i ] ); + continue; + } - if ( ! err ) { - if (asprintf(&buf, "%s.old", argv[i]) == -1) mem_err(); - if ( ! err && stat( buf, &sb ) != -1 ) misc_err( "%s already exists, cannot rewrite %s", buf, argv[ i ] ); - if ( ! err && rename( argv[ i ], buf ) == -1 ) misc_err( "cannot rename %s to %s", argv[ i ], buf ); - - if ( err ) { err = 0; if ( buf ) free( buf ); continue; } - } - if ( ! err ) err = decode_xiso( buf, path, k_rewrite, &new_iso_path ); - if ( ! err && delete && unlink( buf ) == -1 ) log_err( __FILE__, __LINE__, "unable to delete %s", buf ); - - if ( buf ) free( buf ); - } else { - // the order of the mutually exclusive options here is important, the extract ? k_extract : k_list test *must* be the final comparison - if ( ! err ) err = decode_xiso( argv[ i ], extract ? path : nil, extract ? k_extract : k_list, nil ); + if (asprintf(&buf, "%s.old", argv[i]) == -1) mem_err(); + if ( ! err && stat( buf, &sb ) != -1 ) misc_err( "%s already exists, cannot rewrite %s", buf, argv[ i ] ); + if ( ! err && rename( argv[ i ], buf ) == -1 ) misc_err( "cannot rename %s to %s", argv[ i ], buf ); + + if (err) { + err = 0; + if (buf) { free(buf); buf = nil; } + continue; } + + err = decode_xiso(buf, path, k_rewrite, &new_iso_path); + if (!err && delete && unlink(buf) == -1) log_err(__FILE__, __LINE__, "unable to delete %s", buf); + + if (buf) { free(buf); buf = nil; } + } else { + // the order of the mutually exclusive options here is important, the extract ? k_extract : k_list test *must* be the final comparison + err = decode_xiso( argv[ i ], extract ? path : nil, extract ? k_extract : k_list, nil ); } } From 13e88af307784822a330fe66b1e8d31693ca595d Mon Sep 17 00:00:00 2001 From: rapperskull Date: Mon, 27 Mar 2023 10:44:56 +0200 Subject: [PATCH 27/59] Add alternative XGD2 offset Found in 'Xbox 360 Trial Disk' (http://redump.org/disc/58095/) --- extract-xiso.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 68d7fe9..2365a19 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -472,11 +472,12 @@ typedef int64_t file_time_t; #define START_LSEEK_OFFSET 0x00000000ul #define XGD3_LSEEK_OFFSET 0x02080000ul -#define GLOBAL_LSEEK_OFFSET 0x0FD90000ul +#define XGD2_LSEEK_OFFSET 0x0FD90000ul #define XGD1_LSEEK_OFFSET 0x18300000ul -#define LSEEK_OFFSETS_LEN 4 +#define XGD2_ALT_LSEEK_OFFSET 0x89D80000ul +#define LSEEK_OFFSETS_LEN 5 /* The offsets should be in ascending order, otherwise we could get a seek error before checking the correct one */ -xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_OFFSET, GLOBAL_LSEEK_OFFSET, XGD1_LSEEK_OFFSET}; +xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_OFFSET, XGD2_LSEEK_OFFSET, XGD1_LSEEK_OFFSET, XGD2_ALT_LSEEK_OFFSET}; #define XISO_HEADER_DATA "MICROSOFT*XBOX*MEDIA" #define XISO_HEADER_DATA_LENGTH 20 From 64e7003106b3e5fa5a762689563e84070f8418b7 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Mon, 27 Mar 2023 20:21:04 +0200 Subject: [PATCH 28/59] Add support for Unicode characters Unicode characters outside the Windows-1252 charset are replaced with spaces, while Windows-1252 characters not in ASCII charset are correctly handled on all systems --- CMakeLists.txt | 2 +- cp1252/cp1252.c | 274 ++++++++++++++++++++++++++++++++++++++++++++++++ extract-xiso.c | 78 +++++++------- 3 files changed, 318 insertions(+), 36 deletions(-) create mode 100644 cp1252/cp1252.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c92b150..618a7e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ set(SOURCE_FILES if(MSVC) set(CMAKE_C_FLAGS_RELEASE_INIT "/O2") - add_compile_options(/W4) + add_compile_options(/W4 /utf-8) add_compile_options("$<$:/DDEBUG=1>") add_definitions(-D_CRT_NONSTDC_NO_WARNINGS) # POSIX function names add_definitions(-D_CRT_SECURE_NO_WARNINGS) # Unsafe CRT Library functions diff --git a/cp1252/cp1252.c b/cp1252/cp1252.c new file mode 100644 index 0000000..9451c99 --- /dev/null +++ b/cp1252/cp1252.c @@ -0,0 +1,274 @@ +#ifndef CP1252_INCLUDED +#define CP1252_INCLUDED + +#include +#include +#include + +uint32_t getUnicodeFromCP1252(char input); +char getCP1252FromUnicode(uint32_t input); +int getUTF8CodePointSize(uint32_t input); +char* getUTF8Sequence(uint32_t input, char* buf); +size_t strcplen(const char* buf); +const char* getCodePointFromUTF8Sequence(const char* buf, uint32_t* out); +char* getUTF8String(const char* input); +char* getCP1252String(const char* input); + +uint32_t getUnicodeFromCP1252(char input) { + switch ((unsigned char)input) { + case 0x80u: + return 0x20ACu; // EURO SIGN + case 0x82u: + return 0x201Au; // SINGLE LOW-9 QUOTATION MARK + case 0x83u: + return 0x0192u; // LATIN SMALL LETTER F WITH HOOK + case 0x84u: + return 0x201Eu; // DOUBLE LOW-9 QUOTATION MARK + case 0x85u: + return 0x2026u; // HORIZONTAL ELLIPSIS + case 0x86u: + return 0x2020u; // DAGGER + case 0x87u: + return 0x2021u; // DOUBLE DAGGER + case 0x88u: + return 0x02C6u; // MODIFIER LETTER CIRCUMFLEX ACCENT + case 0x89u: + return 0x2030u; // PER MILLE SIGN + case 0x8Au: + return 0x0160u; // LATIN CAPITAL LETTER S WITH CARON + case 0x8Bu: + return 0x2039u; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK + case 0x8Cu: + return 0x0152u; // LATIN CAPITAL LIGATURE OE + case 0x8Eu: + return 0x017Du; // LATIN CAPITAL LETTER Z WITH CARON + case 0x91u: + return 0x2018u; // LEFT SINGLE QUOTATION MARK + case 0x92u: + return 0x2019u; // RIGHT SINGLE QUOTATION MARK + case 0x93u: + return 0x201Cu; // LEFT DOUBLE QUOTATION MARK + case 0x94u: + return 0x201Du; // RIGHT DOUBLE QUOTATION MARK + case 0x95u: + return 0x2022u; // BULLET + case 0x96u: + return 0x2013u; // EN DASH + case 0x97u: + return 0x2014u; // EM DASH + case 0x98u: + return 0x02DCu; // SMALL TILDE + case 0x99u: + return 0x2122u; // TRADE MARK SIGN + case 0x9Au: + return 0x0161u; // LATIN SMALL LETTER S WITH CARON + case 0x9Bu: + return 0x203Au; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + case 0x9Cu: + return 0x0153u; // LATIN SMALL LIGATURE OE + case 0x9Eu: + return 0x017Eu; // LATIN SMALL LETTER Z WITH CARON + case 0x9Fu: + return 0x0178u; // LATIN CAPITAL LETTER Y WITH DIAERESIS + default: + return (unsigned char)input; + } +} + +char getCP1252FromUnicode(uint32_t input) { + switch (input) { + case 0x20ACu: + return '\x80'; // EURO SIGN + case 0x201Au: + return '\x82'; // SINGLE LOW-9 QUOTATION MARK + case 0x0192u: + return '\x83'; // LATIN SMALL LETTER F WITH HOOK + case 0x201Eu: + return '\x84'; // DOUBLE LOW-9 QUOTATION MARK + case 0x2026u: + return '\x85'; // HORIZONTAL ELLIPSIS + case 0x2020u: + return '\x86'; // DAGGER + case 0x2021u: + return '\x87'; // DOUBLE DAGGER + case 0x02C6u: + return '\x88'; // MODIFIER LETTER CIRCUMFLEX ACCENT + case 0x2030u: + return '\x89'; // PER MILLE SIGN + case 0x0160u: + return '\x8A'; // LATIN CAPITAL LETTER S WITH CARON + case 0x2039u: + return '\x8B'; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK + case 0x0152u: + return '\x8C'; // LATIN CAPITAL LIGATURE OE + case 0x017Du: + return '\x8E'; // LATIN CAPITAL LETTER Z WITH CARON + case 0x2018u: + return '\x91'; // LEFT SINGLE QUOTATION MARK + case 0x2019u: + return '\x92'; // RIGHT SINGLE QUOTATION MARK + case 0x201Cu: + return '\x93'; // LEFT DOUBLE QUOTATION MARK + case 0x201Du: + return '\x94'; // RIGHT DOUBLE QUOTATION MARK + case 0x2022u: + return '\x95'; // BULLET + case 0x2013u: + return '\x96'; // EN DASH + case 0x2014u: + return '\x97'; // EM DASH + case 0x02DCu: + return '\x98'; // SMALL TILDE + case 0x2122u: + return '\x99'; // TRADE MARK SIGN + case 0x0161u: + return '\x9A'; // LATIN SMALL LETTER S WITH CARON + case 0x203Au: + return '\x9B'; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + case 0x0153u: + return '\x9C'; // LATIN SMALL LIGATURE OE + case 0x017Eu: + return '\x9E'; // LATIN SMALL LETTER Z WITH CARON + case 0x0178u: + return '\x9F'; // LATIN CAPITAL LETTER Y WITH DIAERESIS + case 0x0081u: + case 0x008Du: + case 0x008Fu: + case 0x0090u: + case 0x009Du: + return (char)input; + default: + if (input <= 0x007Fu || (input >= 0x00A0u && input <= 0x00FFu)) { + return (char)input; + } + else { + return '\x20'; // SPACE + } + } +} + +int getUTF8CodePointSize(uint32_t input) { + if (input < 0x80u) { + return 1; + } + else if (input < 0x800u) { + return 2; + } + else if (input < 0x10000u) { + return 3; + } + else if (input < 0x110000u) { + return 4; + } + else { + return 0; + } +} + +char* getUTF8Sequence(uint32_t input, char* buf) { + if (input < 0x80u) { + *buf++ = input & (0xFF >> 1); + } + else if (input < 0x800u) { + *buf++ = 0xC0 | ((input >> 6) & (0xFF >> 3)); + *buf++ = 0x80 | (input & 0x3F); + } + else if (input < 0x10000u) { + *buf++ = 0xE0 | ((input >> 12) & (0xFF >> 4)); + *buf++ = 0x80 | ((input >> 6) & 0x3F); + *buf++ = 0x80 | (input & 0x3F); + } + else if (input < 0x110000u) { + *buf++ = 0xF0 | ((input >> 18) & (0xFF >> 5)); + *buf++ = 0x80 | ((input >> 12) & 0x3F); + *buf++ = 0x80 | ((input >> 6) & 0x3F); + *buf++ = 0x80 | (input & 0x3F); + } + + return buf; +} + +size_t strcplen(const char* buf) { + unsigned char c; + size_t count = 0; + while (buf[0] != '\0') { + c = (unsigned char)buf[0]; + count += 1; + if ((c >> 7) == 0x00u) { + buf += 1; + } + else if ((c >> 5) == 0x06u) { + buf += 2; + } + else if ((c >> 4) == 0x0Eu) { + buf += 3; + } + else if ((c >> 3) == 0x1Eu) { + buf += 4; + } + else { + buf += 1; // Skip invalid char and don't count it + count -= 1; + } + } + return count; +} + +const char* getCodePointFromUTF8Sequence(const char* buf, uint32_t* out) { + unsigned char c = (unsigned char)buf[0]; + if ((c >> 7) == 0x00) { + if (out) *out = buf[0] & 0x7F; + buf += 1; + } + else if ((c >> 5) == 0x06) { + if (out) *out = ((buf[0] & 0x1F) << 6) | (buf[1] & 0x3F); + buf += 2; + } + else if ((c >> 4) == 0x0E) { + if (out) *out = ((buf[0] & 0xF) << 12) | ((buf[1] & 0x3F) << 6) | (buf[2] & 0x3F); + buf += 3; + } + else if ((c >> 3) == 0x1E) { + if (out) *out = ((buf[0] & 0x7) << 18) | ((buf[1] & 0x3F) << 12) | ((buf[2] & 0x3F) << 6) | (buf[3] & 0x3F); + buf += 4; + } + else { + if (out) *out = '\0'; + buf += 1; // Skip invalid char + } + + return buf; +} + +char* getUTF8String(const char* input) { + const char* p = input; + char *ret = NULL, *q; + size_t len = 0; + while (*p != '\0') { + len += getUTF8CodePointSize(getUnicodeFromCP1252(*p++)); + } + ret = (char*)malloc(len + 1); + if (!ret) return NULL; + q = ret; + while (*input != '\0') { + q = getUTF8Sequence(getUnicodeFromCP1252(*input++), q); + } + *q = '\0'; + return ret; +} + +char* getCP1252String(const char* input) { + size_t len = strcplen(input); + char* ret = malloc(len + 1); + if (!ret) return NULL; + char* p = ret; + uint32_t cp; + while (*input != '\0') { + input = getCodePointFromUTF8Sequence(input, &cp); + if (cp != '\0') *p++ = getCP1252FromUnicode(cp); + } + *p = '\0'; + return ret; +} + +#endif //CP1252_INCLUDED diff --git a/extract-xiso.c b/extract-xiso.c index 2365a19..2bc215a 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -270,8 +270,10 @@ #include #include #include +#include #include #include +#include "cp1252/cp1252.c" #if defined(__FreeBSD__) || defined(__OpenBSD__) #include @@ -557,23 +559,24 @@ struct dir_node { uint32_t start_sector; uint8_t attributes; uint8_t filename_length; - char* filename; + char* filename; // UTF-8 encoded }; struct dir_node_avl { uint32_t offset; xoff_t dir_start; - char *filename; + char* filename; // Windows-1252 encoded + char* filename_utf8; // UTF-8 encoded uint32_t file_size; uint32_t start_sector; - dir_node_avl *subdirectory; + dir_node_avl* subdirectory; uint32_t old_start_sector; avl_skew skew; - dir_node_avl *left; - dir_node_avl *right; + dir_node_avl* left; + dir_node_avl* right; }; struct create_list { @@ -757,6 +760,8 @@ int main( int argc, char **argv ) { exiso_log(banner); if ( ( extract ) && ( s_copy_buffer = (char *) malloc( READWRITE_BUFFER_SIZE ) ) == nil ) mem_err(); + + setlocale(LC_ALL, ".utf8"); } if ( ! err && ( create || rewrite ) ) err = boyer_moore_init( XISO_MEDIA_ENABLE, XISO_MEDIA_ENABLE_LENGTH, k_default_alphabet_size ); @@ -1094,7 +1099,8 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if ( ! err && ! in_root ) { if ( chdir( ".." ) == -1 ) chdir_err( ".." ); } - if ( ! err && ( root.filename = strdup( iso_dir ) ) == nil ) mem_err(); + if (!err && (root.filename_utf8 = strdup(iso_dir)) == nil) mem_err(); + if (!err && (root.filename = getCP1252String(iso_dir)) == nil) mem_err(); if ( ! err && lseek( xiso, (xoff_t) root.start_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err(); if ( ! err ) { @@ -1129,8 +1135,9 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if (err && xiso_path) unlink(xiso_path); } - if ( root.filename ) free( root.filename ); - if ( buf ) free( buf ); + if (root.filename_utf8) free(root.filename_utf8); + if (root.filename) free(root.filename); + if (buf) free(buf); if ( cwd ) { if ( chdir( cwd ) == -1 ) chdir_err( cwd ); @@ -1236,6 +1243,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 dir_node *node = nil; uint16_t l_offset = 0, r_offset = 0; int err = 0; + char buf[XISO_FILENAME_MAX_CHARS + 1]; if (entry_offset >= end_offset) misc_err("attempt to read node entry beyond directory end"); @@ -1273,19 +1281,17 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 little32(node->file_size); little32(node->start_sector); - if ((node->filename = (char*)malloc((size_t)node->filename_length + 1)) == nil) mem_err(); - } - - if (!err) { - if (read(in_xiso, node->filename, node->filename_length) != node->filename_length) read_err(); + if (read(in_xiso, &buf, node->filename_length) != node->filename_length) read_err(); if (!err) { - node->filename[node->filename_length] = 0; + buf[node->filename_length] = '\0'; // security patch (Chris Bainbridge), modified by in to support "...", etc. 02.14.06 (in) - if (!strcmp(node->filename, ".") || !strcmp(node->filename, "..") || strchr(node->filename, '/') || strchr(node->filename, '\\')) { - log_err(__FILE__, __LINE__, "filename '%s' contains invalid character(s), aborting.", node->filename); + if (!strcmp(buf, ".") || !strcmp(buf, "..") || strchr(buf, '/') || strchr(buf, '\\')) { + log_err(__FILE__, __LINE__, "filename '%s' contains invalid character(s), aborting.", buf); exit(1); } + + if ((node->filename = getUTF8String(buf)) == nil) mem_err(); } } @@ -1293,7 +1299,8 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 if (!err) { if (in_mode == k_generate_avl) { if ((avl = (dir_node_avl*)calloc(1, sizeof(dir_node_avl))) == nil) mem_err(); - if (!err) if ((avl->filename = strdup(node->filename)) == nil) mem_err(); + if (!err) if ((avl->filename_utf8 = getUTF8String(buf)) == nil) mem_err(); + if (!err) if ((avl->filename = strdup(buf)) == nil) mem_err(); if (!err) { avl->file_size = node->file_size; avl->old_start_sector = node->start_sector; @@ -1710,6 +1717,7 @@ int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const char* path int free_dir_node_avl( dir_node_avl *in_dir_node_avl, unused void *in_context, unused int in_depth ) { if (in_dir_node_avl->subdirectory && in_dir_node_avl->subdirectory != EMPTY_SUBDIRECTORY) avl_traverse_depth_first(in_dir_node_avl->subdirectory, (traversal_callback)free_dir_node_avl, nil, k_postfix, 0); + free(in_dir_node_avl->filename_utf8); free(in_dir_node_avl->filename); free(in_dir_node_avl); @@ -1724,8 +1732,7 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int char sector[XISO_SECTOR_SIZE]; if ( in_avl->subdirectory ) { - if ( in_context->path ) { if ( asprintf( &context.path, "%s%s%c", in_context->path, in_avl->filename, PATH_CHAR ) == -1 ) mem_err(); } - else { if ( asprintf( &context.path, "%c", PATH_CHAR ) == -1 ) mem_err(); } + if (asprintf(&context.path, "%s%s%c", in_context->path ? in_context->path : "", in_context->path ? in_avl->filename_utf8 : "", PATH_CHAR) == -1) mem_err(); if ( ! err ) { exiso_log( "\nadding\t%s (0 bytes) [OK]", context.path ); @@ -1737,7 +1744,7 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int context.final_bytes = in_context->final_bytes; if ( in_context->from == -1 ) { - if ( chdir( in_avl->filename ) == -1 ) chdir_err( in_avl->filename ); + if ( chdir(in_avl->filename_utf8) == -1 ) chdir_err(in_avl->filename_utf8); } if ( ! err ) err = avl_traverse_depth_first( in_avl->subdirectory, (traversal_callback) write_file, &context, k_prefix, 0 ); @@ -1760,9 +1767,9 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int if ((pos = lseek(in_context->xiso, dir_start, SEEK_SET)) == -1) seek_err(); if (!err && write(in_context->xiso, sector, XISO_SECTOR_SIZE) != XISO_SECTOR_SIZE) write_err(); } - - if (context.path) free(context.path); } + + if (context.path) free(context.path); } return err; @@ -1782,17 +1789,17 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int if ( ! err && ( buf = (char *) malloc( (size_t)size + 1 ) ) == nil ) mem_err(); if ( ! err ) { if ( in_context->from == -1 ) { - if ( ( fd = open( in_avl->filename, READFLAGS, 0 ) ) == -1 ) open_err( in_avl->filename ); + if ( ( fd = open( in_avl->filename_utf8, READFLAGS, 0 ) ) == -1 ) open_err(in_avl->filename_utf8); } else { if (lseek_with_error(fd = in_context->from, (xoff_t)in_avl->old_start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); } } if ( ! err ) { - exiso_log( "\nadding\t%s%s (%u bytes) ", in_context->path, in_avl->filename, in_avl->file_size ); flush(); + exiso_log( "\nadding\t%s%s (%u bytes) ", in_context->path, in_avl->filename_utf8, in_avl->file_size ); flush(); bytes = in_avl->file_size; - len = strlen(in_avl->filename); + len = strlen(in_avl->filename); // Use Windows-1252 name here xbe_file = len >= 4 && strcasecmp(&in_avl->filename[len - 4], ".xbe") == 0; do { n = read(fd, buf + i, min(bytes, size - i)); @@ -1826,7 +1833,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int } exiso_log(err ? "failed" : "[OK]"); - if (!err && size != in_avl->file_size) exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", in_avl->filename, size, in_avl->file_size); + if (!err && size != in_avl->file_size) exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", in_avl->filename_utf8, size, in_avl->file_size); if (!err) { ++s_total_files; @@ -1978,28 +1985,27 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { for ( i = *io_n; i; --i ) exiso_log( "\b" ); exiso_log( "%s", p->d_name ); - for ( j = i = (int) strlen( p->d_name ); j < *io_n; ++j ) exiso_log( " " ); + for ( j = i = (int) strcplen( p->d_name ); j < *io_n; ++j ) exiso_log( " " ); for ( j = i; j < *io_n; ++j ) exiso_log( "\b" ); *io_n = i; flush(); - if ( ( avl = (dir_node_avl *) malloc( sizeof(dir_node_avl) ) ) == nil ) mem_err(); - if ( ! err ) { - memset( avl, 0, sizeof(dir_node_avl) ); - if ( ( avl->filename = strdup( p->d_name ) ) == nil ) mem_err(); - } - if ( ! err && stat( avl->filename, &sb ) == -1 ) read_err(); + if ( ( avl = (dir_node_avl *) calloc( 1, sizeof(dir_node_avl) ) ) == nil ) mem_err(); + if (!err && (avl->filename_utf8 = strdup(p->d_name)) == nil) mem_err(); + if ( ! err && ( avl->filename = getCP1252String( p->d_name ) ) == nil ) mem_err(); + if ( ! err && stat( p->d_name, &sb ) == -1 ) read_err(); if ( ! err ) { if ( S_ISDIR( sb.st_mode ) ) { empty_dir = false; - if ( chdir( avl->filename ) == -1 ) chdir_err( avl->filename ); + if ( chdir(p->d_name) == -1 ) chdir_err(p->d_name); if ( ! err ) err = generate_avl_tree_local( &avl->subdirectory, io_n ); if ( ! err && chdir( ".." ) == -1 ) chdir_err( ".." ); } else if ( S_ISREG( sb.st_mode ) ) { if ( sb.st_size > (int64_t)UINT32_MAX ) { - log_err( __FILE__, __LINE__, "file %s is too large for xiso, skipping...", avl->filename ); + log_err( __FILE__, __LINE__, "file %s is too large for xiso, skipping...", p->d_name); + free(avl->filename_utf8); free( avl->filename ); free( avl ); continue; @@ -2008,6 +2014,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { s_total_bytes += avl->file_size = (uint32_t) sb.st_size; ++s_total_files; } else { + free(avl->filename_utf8); free( avl->filename ); free( avl ); continue; @@ -2017,6 +2024,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { if ( avl_insert( out_root, avl ) == k_avl_error ) misc_err( "error inserting file %s into tree (duplicate filename?)", avl->filename ); } else { if ( avl ) { + if (avl->filename_utf8) free(avl->filename_utf8); if ( avl->filename ) free( avl->filename ); free( avl ); } From 37fa5e72054833c3b4dd725c8b017bed27f255f1 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 28 Mar 2023 13:23:59 +0200 Subject: [PATCH 29/59] Fix rewrite mode skipping some files Don't skew tree when unnecessary This produces the same trees of retail ISOs (not sure if avl_compare_key always produces the same order as retail) --- extract-xiso.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 2bc215a..8dc6cb2 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -1330,13 +1330,13 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 // Recurse on left node if (!err && l_offset) { if (lseek_with_error(in_xiso, in_dir_start + (xoff_t)l_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); - if (!err) err = traverse_xiso(in_xiso, in_dir_start, l_offset, end_offset, in_path, in_mode, &avl, strategy); + if (!err) err = traverse_xiso(in_xiso, in_dir_start, l_offset, end_offset, in_path, in_mode, in_root, strategy); } // Recurse on right node if (!err && r_offset) { if (lseek_with_error(in_xiso, in_dir_start + (xoff_t)r_offset * XISO_DWORD_SIZE, SEEK_SET) == -1) seek_err(); - if (!err) err = traverse_xiso(in_xiso, in_dir_start, r_offset, end_offset, in_path, in_mode, &avl, strategy); + if (!err) err = traverse_xiso(in_xiso, in_dir_start, r_offset, end_offset, in_path, in_mode, in_root, strategy); } } @@ -1443,7 +1443,7 @@ avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ) { avl_result avl_left_grown( dir_node_avl **in_root ) { switch ( (*in_root)->skew ) { - case k_left_skew: { + case k_left_skew: if ( (*in_root)->left->skew == k_left_skew ) { (*in_root)->skew = (*in_root)->left->skew = k_no_skew; avl_rotate_right( in_root ); @@ -1468,26 +1468,21 @@ avl_result avl_left_grown( dir_node_avl **in_root ) { avl_rotate_left( &(*in_root)->left ); avl_rotate_right( in_root ); } - } return no_err; + return no_err; - case k_right_skew: { + case k_right_skew: (*in_root)->skew = k_no_skew; - } return no_err; + return no_err; - default: { - (*in_root)->skew = k_left_skew; - } return k_avl_balanced; + default: + return k_avl_balanced; } } avl_result avl_right_grown( dir_node_avl **in_root ) { switch ( (*in_root)->skew ) { - case k_left_skew: { - (*in_root)->skew = k_no_skew; - } return no_err; - - case k_right_skew: { + case k_right_skew: if ( (*in_root)->right->skew == k_right_skew ) { (*in_root)->skew = (*in_root)->right->skew = k_no_skew; avl_rotate_left( in_root ); @@ -1512,11 +1507,14 @@ avl_result avl_right_grown( dir_node_avl **in_root ) { avl_rotate_right( &(*in_root)->right ); avl_rotate_left( in_root ); } - } return no_err; + return no_err; + + case k_left_skew: + (*in_root)->skew = k_no_skew; + return no_err; - default: { - (*in_root)->skew = k_right_skew; - } return k_avl_balanced; + default: + return k_avl_balanced; } } From ae06b0c87e924cd99b0edaad62f5394f83b82bf6 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 28 Mar 2023 14:11:20 +0200 Subject: [PATCH 30/59] Compare as unsigned in avl_compare_key --- extract-xiso.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 8dc6cb2..8c1cf79 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -1538,11 +1538,11 @@ void avl_rotate_right( dir_node_avl **in_root ) { int avl_compare_key( const char *in_lhs, const char *in_rhs ) { - char a, b; + unsigned char a, b; for ( ;; ) { - a = *in_lhs++; - b = *in_rhs++; + a = (unsigned char)*in_lhs++; + b = (unsigned char)*in_rhs++; if ( a >= 'a' && a <= 'z' ) a -= 32; // uppercase(a); if ( b >= 'a' && b <= 'z' ) b -= 32; // uppercase(b); From 53fe37a62c4312f110186541132324e198695bad Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 28 Mar 2023 17:07:16 +0200 Subject: [PATCH 31/59] Preserve file attributes when rewriting Store files from disk with attribute NORMAL instead of ARCHIVE --- extract-xiso.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 8c1cf79..00409f3 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -528,8 +528,6 @@ xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_OFFSET #define n_sectors(size) ( (size) / XISO_SECTOR_SIZE + ( (size) % XISO_SECTOR_SIZE ? 1 : 0 ) ) #define n_dword(offset) ( (offset) / XISO_DWORD_SIZE + ( (offset) % XISO_DWORD_SIZE ? 1 : 0 ) ) -#define EMPTY_SUBDIRECTORY ( (dir_node_avl *) 1 ) - #define READWRITE_BUFFER_SIZE 0x00200000 #define DEBUG_DUMP_DIRECTORY "/Volumes/c/xbox/iso/exiso" @@ -570,6 +568,7 @@ struct dir_node_avl { char* filename_utf8; // UTF-8 encoded uint32_t file_size; uint32_t start_sector; + uint8_t attributes; dir_node_avl* subdirectory; uint32_t old_start_sector; @@ -1026,6 +1025,7 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n exiso_log( "\n%s %s%s:\n", in_root ? "rewriting" : "creating", iso_name, in_name ? "" : ".iso" ); root.start_sector = XISO_ROOT_DIRECTORY_SECTOR; + root.attributes = XISO_ATTRIBUTE_DIR; s_total_bytes = s_total_files = 0; @@ -1128,7 +1128,7 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n else exiso_log( "\n\nsuccessfully created %s%s (%u files totalling %lld bytes added)\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "", s_total_files, s_total_bytes ); } - if ( root.subdirectory != EMPTY_SUBDIRECTORY ) avl_traverse_depth_first( root.subdirectory, (traversal_callback) free_dir_node_avl, nil, k_postfix, 0 ); + if ( root.subdirectory ) avl_traverse_depth_first( root.subdirectory, (traversal_callback) free_dir_node_avl, nil, k_postfix, 0 ); if ( xiso != -1 ) { close( xiso ); @@ -1206,7 +1206,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if (!err && lseek_with_error(xiso, root_dir_start, SEEK_SET) == -1) seek_err(); if (in_mode == k_rewrite) { - if (!err && root_dir_size == 0) root = EMPTY_SUBDIRECTORY; + if (!err && root_dir_size == 0) root = nil; else { if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, k_generate_avl, &root, tree_strategy); if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, k_generate_avl, &root, discover_strategy); @@ -1253,7 +1253,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 if (!err && read(in_xiso, &l_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); if (!err && l_offset == XISO_PAD_SHORT) { if (entry_offset == 0) { // Empty directories have padding starting at the beginning - if (in_mode == k_generate_avl) *in_root = EMPTY_SUBDIRECTORY; + if (in_mode == k_generate_avl) *in_root = nil; return err; // Done } else if (strategy != discover_strategy) { // When discovering, the padding means end of sector @@ -1304,6 +1304,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 if (!err) { avl->file_size = node->file_size; avl->old_start_sector = node->start_sector; + avl->attributes = node->attributes; if (avl_insert(in_root, avl) == k_avl_error) { // Insert node in tree // If we're discovering files outside trees, we don't care about avl_insert errors, // since they represent nodes already discovered before, and we don't want to process them again @@ -1369,7 +1370,7 @@ int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode if (!err) { // Recurse on subdirectory if (node->file_size == 0) { - if (in_mode == k_generate_avl) *in_root = EMPTY_SUBDIRECTORY; + if (in_mode == k_generate_avl) *in_root = nil; } else { if (in_path && asprintf(&path, "%s%s%c", in_path, node->filename, PATH_CHAR) == -1) mem_err(); @@ -1713,7 +1714,7 @@ int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const char* path int free_dir_node_avl( dir_node_avl *in_dir_node_avl, unused void *in_context, unused int in_depth ) { - if (in_dir_node_avl->subdirectory && in_dir_node_avl->subdirectory != EMPTY_SUBDIRECTORY) avl_traverse_depth_first(in_dir_node_avl->subdirectory, (traversal_callback)free_dir_node_avl, nil, k_postfix, 0); + if ((in_dir_node_avl->attributes & XISO_ATTRIBUTE_DIR) && in_dir_node_avl->subdirectory) avl_traverse_depth_first(in_dir_node_avl->subdirectory, (traversal_callback)free_dir_node_avl, nil, k_postfix, 0); free(in_dir_node_avl->filename_utf8); free(in_dir_node_avl->filename); @@ -1729,13 +1730,13 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int int err = 0, pad = 0; char sector[XISO_SECTOR_SIZE]; - if ( in_avl->subdirectory ) { + if (in_avl->attributes & XISO_ATTRIBUTE_DIR) { if (asprintf(&context.path, "%s%s%c", in_context->path ? in_context->path : "", in_context->path ? in_avl->filename_utf8 : "", PATH_CHAR) == -1) mem_err(); if ( ! err ) { exiso_log( "\nadding\t%s (0 bytes) [OK]", context.path ); - if ( in_avl->subdirectory != EMPTY_SUBDIRECTORY ) { + if (in_avl->subdirectory) { context.xiso = in_context->xiso; context.from = in_context->from; context.progress = in_context->progress; @@ -1781,7 +1782,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int size_t len; bool xbe_file; - if ( ! in_avl->subdirectory ) { + if (!(in_avl->attributes & XISO_ATTRIBUTE_DIR)) { if ( lseek( in_context->xiso, (xoff_t) in_avl->start_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err(); if ( ! err && ( buf = (char *) malloc( (size_t)size + 1 ) ) == nil ) mem_err(); @@ -1851,9 +1852,8 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unused int in_depth ) { xoff_t pos; uint16_t l_offset, r_offset; - uint32_t file_size = in_avl->subdirectory ? n_sectors(in_avl->file_size) * XISO_SECTOR_SIZE : in_avl->file_size; + uint32_t file_size = (in_avl->attributes & XISO_ATTRIBUTE_DIR) ? n_sectors(in_avl->file_size) * XISO_SECTOR_SIZE : in_avl->file_size; uint8_t length = (uint8_t)strlen(in_avl->filename); - uint8_t attributes = in_avl->subdirectory ? XISO_ATTRIBUTE_DIR : XISO_ATTRIBUTE_ARC; char sector[XISO_SECTOR_SIZE]; int err = 0, pad = 0; @@ -1875,7 +1875,7 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unuse if ( ! err && write( in_context->xiso, &r_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err(); if ( ! err && write( in_context->xiso, &in_avl->start_sector, XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) write_err(); if ( ! err && write( in_context->xiso, &file_size, XISO_FILESIZE_SIZE ) != XISO_FILESIZE_SIZE ) write_err(); - if ( ! err && write( in_context->xiso, &attributes, XISO_ATTRIBUTES_SIZE ) != XISO_ATTRIBUTES_SIZE ) write_err(); + if ( ! err && write( in_context->xiso, &in_avl->attributes, XISO_ATTRIBUTES_SIZE ) != XISO_ATTRIBUTES_SIZE ) write_err(); if ( ! err && write( in_context->xiso, &length, XISO_FILENAME_LENGTH_SIZE ) != XISO_FILENAME_LENGTH_SIZE ) write_err(); if ( ! err && write( in_context->xiso, in_avl->filename, length ) != length ) write_err(); @@ -1889,8 +1889,8 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unuse int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_current_sector, unused int in_depth ) { wdsafp_context context = { 0 }; - if ( in_avl->subdirectory ) { - if (in_avl->subdirectory == EMPTY_SUBDIRECTORY) { + if ( in_avl->attributes & XISO_ATTRIBUTE_DIR ) { + if (!in_avl->subdirectory) { in_avl->start_sector = *io_current_sector; *io_current_sector += 1; } @@ -1912,9 +1912,9 @@ int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_current_sect int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io_context, unused int in_depth ) { in_avl->dir_start = io_context->dir_start; - if ( ! in_avl->subdirectory ) { + if (!(in_avl->attributes & XISO_ATTRIBUTE_DIR)) { in_avl->start_sector = *io_context->current_sector; - *io_context->current_sector += n_sectors( in_avl->file_size ); + *io_context->current_sector += n_sectors(in_avl->file_size); } return 0; @@ -1922,8 +1922,8 @@ int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io int calculate_total_files_and_bytes( dir_node_avl *in_avl, unused void *in_context, unused int in_depth ) { - if (in_avl->subdirectory) { - if (in_avl->subdirectory != EMPTY_SUBDIRECTORY) { + if (in_avl->attributes & XISO_ATTRIBUTE_DIR) { + if (in_avl->subdirectory) { avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_total_files_and_bytes, nil, k_prefix, 0); } } else { @@ -1935,8 +1935,8 @@ int calculate_total_files_and_bytes( dir_node_avl *in_avl, unused void *in_conte int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, unused int in_depth ) { - if ( in_avl->subdirectory ) { - if (in_avl->subdirectory != EMPTY_SUBDIRECTORY) { + if (in_avl->attributes & XISO_ATTRIBUTE_DIR) { + if (in_avl->subdirectory) { avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_directory_size, &in_avl->file_size, k_prefix, 0); avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_directory_requirements, in_context, k_prefix, 0); } else { @@ -1995,6 +1995,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { if ( ! err ) { if ( S_ISDIR( sb.st_mode ) ) { empty_dir = false; + avl->attributes = XISO_ATTRIBUTE_DIR; if ( chdir(p->d_name) == -1 ) chdir_err(p->d_name); @@ -2009,6 +2010,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { continue; } empty_dir = false; + avl->attributes = XISO_ATTRIBUTE_NOR; s_total_bytes += avl->file_size = (uint32_t) sb.st_size; ++s_total_files; } else { @@ -2029,7 +2031,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { } } - if ( empty_dir ) *out_root = EMPTY_SUBDIRECTORY; + if ( empty_dir ) *out_root = nil; if ( dir ) closedir( dir ); From fe885c620854dae7375a39023153d93e0080c090 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 28 Mar 2023 17:51:10 +0200 Subject: [PATCH 32/59] Use less memory when reading the file names --- extract-xiso.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 00409f3..3285ce0 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -1243,7 +1243,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 dir_node *node = nil; uint16_t l_offset = 0, r_offset = 0; int err = 0; - char buf[XISO_FILENAME_MAX_CHARS + 1]; + char *filename = nil; if (entry_offset >= end_offset) misc_err("attempt to read node entry beyond directory end"); @@ -1280,18 +1280,22 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 little16(r_offset); little32(node->file_size); little32(node->start_sector); - - if (read(in_xiso, &buf, node->filename_length) != node->filename_length) read_err(); + if ((filename = malloc((size_t)node->filename_length + 1)) == nil) mem_err(); + if (!err && read(in_xiso, filename, node->filename_length) != node->filename_length) read_err(); if (!err) { - buf[node->filename_length] = '\0'; + filename[node->filename_length] = '\0'; // security patch (Chris Bainbridge), modified by in to support "...", etc. 02.14.06 (in) - if (!strcmp(buf, ".") || !strcmp(buf, "..") || strchr(buf, '/') || strchr(buf, '\\')) { - log_err(__FILE__, __LINE__, "filename '%s' contains invalid character(s), aborting.", buf); + if (!strcmp(filename, ".") || !strcmp(filename, "..") || strchr(filename, '/') || strchr(filename, '\\')) { + log_err(__FILE__, __LINE__, "filename '%s' contains invalid character(s), aborting.", filename); exit(1); } - if ((node->filename = getUTF8String(buf)) == nil) mem_err(); + if ((node->filename = getUTF8String(filename)) == nil) mem_err(); + } + if (filename && in_mode != k_generate_avl) { // If 'in_mode' is 'k_generate_avl', we copy filename to avl->filename + free(filename); + filename = nil; } } @@ -1299,9 +1303,9 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 if (!err) { if (in_mode == k_generate_avl) { if ((avl = (dir_node_avl*)calloc(1, sizeof(dir_node_avl))) == nil) mem_err(); - if (!err) if ((avl->filename_utf8 = getUTF8String(buf)) == nil) mem_err(); - if (!err) if ((avl->filename = strdup(buf)) == nil) mem_err(); if (!err) { + avl->filename_utf8 = node->filename; // Remember to not free node->filename yet + avl->filename = filename; avl->file_size = node->file_size; avl->old_start_sector = node->start_sector; avl->attributes = node->attributes; @@ -1321,7 +1325,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 // Free memory before recurring or iterating if (node) { - if (node->filename) free(node->filename); + if (node->filename && in_mode != k_generate_avl) free(node->filename); // We copied node->filename in avl->filename_utf8 if 'in_mode' was 'k_generate_avl' free(node); } @@ -2021,7 +2025,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { } } if ( ! err ) { - if ( avl_insert( out_root, avl ) == k_avl_error ) misc_err( "error inserting file %s into tree (duplicate filename?)", avl->filename ); + if ( avl_insert( out_root, avl ) == k_avl_error ) misc_err( "error inserting file %s into tree (duplicate filename?)", avl->filename_utf8 ); } else { if ( avl ) { if (avl->filename_utf8) free(avl->filename_utf8); From 2debfbb108e916b4f307edc40dc658302bdce752 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 28 Mar 2023 18:06:25 +0200 Subject: [PATCH 33/59] Fix potential memory leak --- extract-xiso.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 3285ce0..4965f89 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -1309,12 +1309,18 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 avl->file_size = node->file_size; avl->old_start_sector = node->start_sector; avl->attributes = node->attributes; - if (avl_insert(in_root, avl) == k_avl_error) { // Insert node in tree - // If we're discovering files outside trees, we don't care about avl_insert errors, - // since they represent nodes already discovered before, and we don't want to process them again - if (strategy != discover_strategy) misc_err("this iso appears to be corrupt"); + if (avl_insert(in_root, avl) != k_avl_error) { // Insert node in tree + err = process_node(in_xiso, node, in_path, in_mode, &avl->subdirectory, strategy); + } else if (strategy == discover_strategy) { + // If we're discovering files outside trees, we don't care about avl_insert errors, since + // they represent nodes already discovered before, and we don't want to process them again. + // We just free some memory previously allocated + free(avl->filename_utf8); + free(avl->filename); + node->filename = nil; + free(avl); } - else err = process_node(in_xiso, node, in_path, in_mode, &avl->subdirectory, strategy); + else misc_err("this iso appears to be corrupt"); // When not discovering, a duplicate node is an error } } else err = process_node(in_xiso, node, in_path, in_mode, nil, strategy); From fd97a472251d8d76a4a90d59121ea6b5dc305ed3 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 28 Mar 2023 23:49:51 +0200 Subject: [PATCH 34/59] Improve speed and memory usage when rewriting or creating by using a buffer instead of calling malloc/free every time --- extract-xiso.c | 58 ++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 4965f89..fe7ad13 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -528,7 +528,7 @@ xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_OFFSET #define n_sectors(size) ( (size) / XISO_SECTOR_SIZE + ( (size) % XISO_SECTOR_SIZE ? 1 : 0 ) ) #define n_dword(offset) ( (offset) / XISO_DWORD_SIZE + ( (offset) % XISO_DWORD_SIZE ? 1 : 0 ) ) -#define READWRITE_BUFFER_SIZE 0x00200000 +#define READWRITE_BUFFER_SIZE 0x00200000ul // Must be at least XISO_HEADER_OFFSET #define DEBUG_DUMP_DIRECTORY "/Volumes/c/xbox/iso/exiso" @@ -758,7 +758,7 @@ int main( int argc, char **argv ) { exiso_log(banner); - if ( ( extract ) && ( s_copy_buffer = (char *) malloc( READWRITE_BUFFER_SIZE ) ) == nil ) mem_err(); + if ((extract || rewrite || create) && (s_copy_buffer = (char*)malloc(READWRITE_BUFFER_SIZE)) == nil) mem_err(); setlocale(LC_ALL, ".utf8"); } @@ -991,7 +991,7 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n write_tree_context wt_context = { 0 }; uint32_t start_sector = 0; int i = 0, n = 0, xiso = -1, err = 0; - char *cwd = nil, *buf = nil, *iso_name = nil, *xiso_path = nil, *iso_dir = nil, *real_path = nil; + char *cwd = nil, *iso_name = nil, *xiso_path = nil, *iso_dir = nil, *real_path = nil; s_total_bytes = s_total_files = 0; @@ -1057,7 +1057,6 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n avl_traverse_depth_first( &root, (traversal_callback) calculate_directory_requirements, nil, k_prefix, 0 ); avl_traverse_depth_first( &root, (traversal_callback) calculate_directory_offsets, &start_sector, k_prefix, 0 ); } - if ( ! err && ( buf = (char *) malloc( n = max( READWRITE_BUFFER_SIZE, XISO_HEADER_OFFSET ) ) ) == nil ) mem_err(); if ( ! err ) { if ( ( xiso = open( xiso_path, WRITEFLAGS, 0644 ) ) == -1 ) open_err( xiso_path ); if (out_iso_path) *out_iso_path = xiso_path; @@ -1067,8 +1066,8 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n } } if ( ! err ) { - memset( buf, 0, n ); - if ( write( xiso, buf, XISO_HEADER_OFFSET ) != XISO_HEADER_OFFSET ) write_err(); + memset(s_copy_buffer, 0, XISO_HEADER_OFFSET); + if ( write( xiso, s_copy_buffer, XISO_HEADER_OFFSET ) != XISO_HEADER_OFFSET ) write_err(); } if ( ! err && write( xiso, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) write_err(); if ( ! err ) { @@ -1084,16 +1083,15 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if ( ! err ) { if ( in_root ) { if (lseek_with_error(in_xiso, (xoff_t)XISO_HEADER_OFFSET + XISO_HEADER_DATA_LENGTH + XISO_SECTOR_OFFSET_SIZE + XISO_DIRTABLE_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); - if ( ! err && read( in_xiso, buf, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) read_err(); - if ( ! err && write( xiso, buf, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) write_err(); - - memset( buf, 0, XISO_FILETIME_SIZE ); + if ( ! err && read( in_xiso, s_copy_buffer, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) read_err(); + if ( ! err && write( xiso, s_copy_buffer, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) write_err(); } else { if ( ( err = get_filetime_now(&ft) ) ) misc_err("cannot get current time"); if ( ! err && write( xiso, &ft, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) write_err(); } } - if ( ! err && write( xiso, buf, XISO_UNUSED_SIZE ) != XISO_UNUSED_SIZE ) write_err(); + memset(s_copy_buffer, 0, XISO_UNUSED_SIZE); + if ( ! err && write( xiso, s_copy_buffer, XISO_UNUSED_SIZE ) != XISO_UNUSED_SIZE ) write_err(); if ( ! err && write( xiso, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) write_err(); if ( ! err && ! in_root ) { @@ -1115,7 +1113,8 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if ( ! err && ( pos = lseek( xiso, (xoff_t) 0, SEEK_END ) ) == -1 ) seek_err(); if (!err) { i = (int)((XISO_FILE_MODULUS - pos % XISO_FILE_MODULUS) % XISO_FILE_MODULUS); - if (write(xiso, buf, i) != i) write_err(); + memset(s_copy_buffer, 0, i); + if (write(xiso, s_copy_buffer, i) != i) write_err(); } if ( ! err ) err = write_volume_descriptors( xiso, (uint32_t)((pos + (xoff_t)i) / XISO_SECTOR_SIZE) ); @@ -1137,7 +1136,6 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if (root.filename_utf8) free(root.filename_utf8); if (root.filename) free(root.filename); - if (buf) free(buf); if ( cwd ) { if ( chdir( cwd ) == -1 ) chdir_err( cwd ); @@ -1738,7 +1736,6 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int xoff_t pos = 0, dir_start = (xoff_t)in_avl->start_sector * XISO_SECTOR_SIZE; write_tree_context context = { 0 }; int err = 0, pad = 0; - char sector[XISO_SECTOR_SIZE]; if (in_avl->attributes & XISO_ATTRIBUTE_DIR) { if (asprintf(&context.path, "%s%s%c", in_context->path ? in_context->path : "", in_context->path ? in_avl->filename_utf8 : "", PATH_CHAR) == -1) mem_err(); @@ -1764,17 +1761,17 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int if (!err && (pos = lseek(in_context->xiso, 0, SEEK_CUR)) == -1) seek_err(); if (!err) { pad = (int)((XISO_SECTOR_SIZE - (pos % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE); - memset(sector, XISO_PAD_BYTE, pad); - if (write(in_context->xiso, sector, pad) != pad) write_err(); + memset(s_copy_buffer, XISO_PAD_BYTE, pad); + if (write(in_context->xiso, s_copy_buffer, pad) != pad) write_err(); } if ( ! err && in_context->from == -1 ) { if ( chdir( ".." ) == -1 ) chdir_err( ".." ); } } else { - memset(sector, XISO_PAD_BYTE, XISO_SECTOR_SIZE); + memset(s_copy_buffer, XISO_PAD_BYTE, XISO_SECTOR_SIZE); if ((pos = lseek(in_context->xiso, dir_start, SEEK_SET)) == -1) seek_err(); - if (!err && write(in_context->xiso, sector, XISO_SECTOR_SIZE) != XISO_SECTOR_SIZE) write_err(); + if (!err && write(in_context->xiso, s_copy_buffer, XISO_SECTOR_SIZE) != XISO_SECTOR_SIZE) write_err(); } } @@ -1786,8 +1783,8 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { - char *buf = nil, *p = nil; - uint32_t bytes = 0, size = max(XISO_SECTOR_SIZE, READWRITE_BUFFER_SIZE); + char *p = nil; + uint32_t bytes = 0, size = 0; int err = 0, fd = -1, n = 0, i = 0; size_t len; bool xbe_file; @@ -1795,7 +1792,6 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int if (!(in_avl->attributes & XISO_ATTRIBUTE_DIR)) { if ( lseek( in_context->xiso, (xoff_t) in_avl->start_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err(); - if ( ! err && ( buf = (char *) malloc( (size_t)size + 1 ) ) == nil ) mem_err(); if ( ! err ) { if ( in_context->from == -1 ) { if ( ( fd = open( in_avl->filename_utf8, READFLAGS, 0 ) ) == -1 ) open_err(in_avl->filename_utf8); @@ -1811,23 +1807,23 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int len = strlen(in_avl->filename); // Use Windows-1252 name here xbe_file = len >= 4 && strcasecmp(&in_avl->filename[len - 4], ".xbe") == 0; do { - n = read(fd, buf + i, min(bytes, size - i)); + n = read(fd, s_copy_buffer + i, min(bytes, READWRITE_BUFFER_SIZE - i)); if (n < 0) read_err(); else if (n == 0) { // Unexpected end of file - if (i > 0 && write(in_context->xiso, buf, i) != i) write_err(); // Write remaining 'i' bytes + if (i > 0 && write(in_context->xiso, s_copy_buffer, i) != i) write_err(); // Write remaining 'i' bytes } else { bytes -= n; if (s_media_enable && xbe_file) { n += i; - for (buf[n] = 0, p = buf; (p = boyer_moore_search(p, n - (long)(p - buf))) != nil; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; + for (p = s_copy_buffer; (p = boyer_moore_search(p, n - (long)(p - s_copy_buffer))) != nil; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; if (bytes) { i = XISO_MEDIA_ENABLE_LENGTH - 1; n -= i; } } - if (write(in_context->xiso, buf, n) != n) write_err(); - if (!err && s_media_enable && xbe_file && bytes) memcpy(buf, &buf[n], i); + if (write(in_context->xiso, s_copy_buffer, n) != n) write_err(); + if (!err && s_media_enable && xbe_file && bytes) memcpy(s_copy_buffer, &s_copy_buffer[n], i); } } while (!err && bytes > 0 && n > 0); size = in_avl->file_size; @@ -1836,8 +1832,8 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int if (!err) { i = (XISO_SECTOR_SIZE - (in_avl->file_size % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE; if (i > 0) { - memset(buf, XISO_PAD_BYTE, i); - if (write(in_context->xiso, buf, i) != i) write_err(); + memset(s_copy_buffer, XISO_PAD_BYTE, i); + if (write(in_context->xiso, s_copy_buffer, i) != i) write_err(); } } exiso_log(err ? "failed" : "[OK]"); @@ -1852,7 +1848,6 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int } if ( in_context->from == -1 && fd != -1 ) close( fd ); - if ( buf ) free( buf ); } return err; @@ -1864,7 +1859,6 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unuse uint16_t l_offset, r_offset; uint32_t file_size = (in_avl->attributes & XISO_ATTRIBUTE_DIR) ? n_sectors(in_avl->file_size) * XISO_SECTOR_SIZE : in_avl->file_size; uint8_t length = (uint8_t)strlen(in_avl->filename); - char sector[XISO_SECTOR_SIZE]; int err = 0, pad = 0; little32( in_avl->file_size ); @@ -1876,11 +1870,11 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unuse little16( l_offset ); little16( r_offset ); - memset( sector, XISO_PAD_BYTE, XISO_SECTOR_SIZE ); + memset(s_copy_buffer, XISO_PAD_BYTE, XISO_SECTOR_SIZE); if ( ( pos = lseek( in_context->xiso, 0, SEEK_CUR ) ) == -1 ) seek_err(); if ( ! err ) pad = (int)((xoff_t)in_avl->offset + in_avl->dir_start - pos); - if ( ! err && write( in_context->xiso, sector, pad ) != pad ) write_err(); + if ( ! err && write( in_context->xiso, s_copy_buffer, pad ) != pad ) write_err(); if ( ! err && write( in_context->xiso, &l_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err(); if ( ! err && write( in_context->xiso, &r_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err(); if ( ! err && write( in_context->xiso, &in_avl->start_sector, XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) write_err(); From f03952e124dc9c10e7f6be8f08c00cbd03ffd129 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Wed, 29 Mar 2023 16:21:08 +0200 Subject: [PATCH 35/59] Use stdbool.h, since we're compiling under C99 anyways --- extract-xiso.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index fe7ad13..5a30a72 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -268,6 +268,7 @@ #include #include #include +#include #include #include #include @@ -426,12 +427,6 @@ #define DEBUG_OPTIMIZE_XISO 0 #define DEBUG_TRAVERSE_XISO_DIR 0 - -#if ! defined( __cplusplus ) && ! defined( bool ) - typedef int bool; - enum { false, true }; -#endif - typedef int64_t file_time_t; #ifndef nil From 7cae2b406b2b63fcf86cb0987c9e58c3507f02c4 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Wed, 29 Mar 2023 16:19:41 +0200 Subject: [PATCH 36/59] Use Windows-1252 locale if available on the system and avoid UTF-8 entirely --- cp1252/cp1252.c | 9 ++- extract-xiso.c | 147 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 106 insertions(+), 50 deletions(-) diff --git a/cp1252/cp1252.c b/cp1252/cp1252.c index 9451c99..a6d8659 100644 --- a/cp1252/cp1252.c +++ b/cp1252/cp1252.c @@ -4,12 +4,14 @@ #include #include #include +#include +#include uint32_t getUnicodeFromCP1252(char input); char getCP1252FromUnicode(uint32_t input); int getUTF8CodePointSize(uint32_t input); char* getUTF8Sequence(uint32_t input, char* buf); -size_t strcplen(const char* buf); +size_t strcplen(const char* buf, bool utf8); const char* getCodePointFromUTF8Sequence(const char* buf, uint32_t* out); char* getUTF8String(const char* input); char* getCP1252String(const char* input); @@ -188,9 +190,10 @@ char* getUTF8Sequence(uint32_t input, char* buf) { return buf; } -size_t strcplen(const char* buf) { +size_t strcplen(const char* buf, bool utf8) { unsigned char c; size_t count = 0; + if (!utf8) return strlen(buf); while (buf[0] != '\0') { c = (unsigned char)buf[0]; count += 1; @@ -258,7 +261,7 @@ char* getUTF8String(const char* input) { } char* getCP1252String(const char* input) { - size_t len = strcplen(input); + size_t len = strcplen(input, true); char* ret = malloc(len + 1); if (!ret) return NULL; char* p = ret; diff --git a/extract-xiso.c b/extract-xiso.c index 5a30a72..0133b9b 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -529,6 +529,9 @@ xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_OFFSET #define GETOPT_STRING "c:d:Dhlmp:qQrsvx" +char* cp1252_locales[] = { ".1252" /* Windows */, "C.CP1252", "en_US.CP1252", "de_DE.CP1252", nil }; +char* utf8_locales[] = { ".UTF-8" /* Windows */, "C.UTF-8", "en_US.UTF-8", nil }; + typedef enum avl_skew { k_no_skew , k_left_skew , k_right_skew } avl_skew; typedef enum avl_result { no_err, k_avl_error, k_avl_balanced } avl_result; @@ -552,15 +555,16 @@ struct dir_node { uint32_t start_sector; uint8_t attributes; uint8_t filename_length; - char* filename; // UTF-8 encoded + char* filename; // User encoded }; struct dir_node_avl { uint32_t offset; xoff_t dir_start; - char* filename; // Windows-1252 encoded - char* filename_utf8; // UTF-8 encoded + /* filename_cp1252 is always present. If filename is also present, then the encoding differs from filename_cp1252 */ + char* filename_cp1252; // Windows-1252 encoded + char* filename; // User encoded uint32_t file_size; uint32_t start_sector; uint8_t attributes; @@ -648,6 +652,7 @@ static bool s_media_enable = true; static long long s_total_bytes_all_isos = 0; static int s_total_files_all_isos = 0; static bool s_warned = false; +static bool s_cp1252 = false; static bool s_remove_systemupdate = false; static char *s_systemupdate = "$SystemUpdate"; @@ -666,7 +671,7 @@ int main( int argc, char **argv ) { int i, fd, opt_char, err = 0, isos = 0; bool extract = true, rewrite = false, x_seen = false, delete = false, optimized; ptrdiff_t diff; - char *path = nil, *buf = nil, *new_iso_path = nil; + char *path = nil, *buf = nil, *new_iso_path = nil, *locale = nil, **locale_arr = nil; char tag[XISO_OPTIMIZED_TAG_LENGTH + 1]; if (argc < 2) usage_and_exit(1); @@ -755,7 +760,23 @@ int main( int argc, char **argv ) { if ((extract || rewrite || create) && (s_copy_buffer = (char*)malloc(READWRITE_BUFFER_SIZE)) == nil) mem_err(); - setlocale(LC_ALL, ".utf8"); + locale_arr = cp1252_locales; + while (*locale_arr) { + locale = setlocale(LC_ALL, *locale_arr); + if (locale) break; + locale_arr++; + } + if (locale) s_cp1252 = true; + else { + locale_arr = utf8_locales; + while (*locale_arr) { + locale = setlocale(LC_ALL, *locale_arr); + if (locale) break; + locale_arr++; + } + if (!locale) exiso_warn("Using %s locale. Non-ASCII characters will probably not be represented correctly.", setlocale(LC_ALL, NULL)); + } + } if ( ! err && ( create || rewrite ) ) err = boyer_moore_init( XISO_MEDIA_ENABLE, XISO_MEDIA_ENABLE_LENGTH, k_default_alphabet_size ); @@ -1092,8 +1113,14 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if ( ! err && ! in_root ) { if ( chdir( ".." ) == -1 ) chdir_err( ".." ); } - if (!err && (root.filename_utf8 = strdup(iso_dir)) == nil) mem_err(); - if (!err && (root.filename = getCP1252String(iso_dir)) == nil) mem_err(); + if (!err && (root.filename = strdup(iso_dir)) == nil) mem_err(); + if (!err) { + if (s_cp1252) { + root.filename_cp1252 = root.filename; + root.filename = nil; + } + else if ((root.filename_cp1252 = getCP1252String(iso_dir)) == nil) mem_err(); + } if ( ! err && lseek( xiso, (xoff_t) root.start_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err(); if ( ! err ) { @@ -1129,8 +1156,8 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if (err && xiso_path) unlink(xiso_path); } - if (root.filename_utf8) free(root.filename_utf8); if (root.filename) free(root.filename); + if (root.filename_cp1252) free(root.filename_cp1252); if ( cwd ) { if ( chdir( cwd ) == -1 ) chdir_err( cwd ); @@ -1284,12 +1311,13 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 exit(1); } - if ((node->filename = getUTF8String(filename)) == nil) mem_err(); - } - if (filename && in_mode != k_generate_avl) { // If 'in_mode' is 'k_generate_avl', we copy filename to avl->filename - free(filename); - filename = nil; + if (s_cp1252) { + node->filename = filename; + filename = nil; + } + else if ((node->filename = getUTF8String(filename)) == nil) mem_err(); } + } // Process the node according to the mode @@ -1297,8 +1325,15 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 if (in_mode == k_generate_avl) { if ((avl = (dir_node_avl*)calloc(1, sizeof(dir_node_avl))) == nil) mem_err(); if (!err) { - avl->filename_utf8 = node->filename; // Remember to not free node->filename yet - avl->filename = filename; + if (s_cp1252) { + avl->filename = nil; + avl->filename_cp1252 = node->filename; // Don't set node->filename to nil yet + } + else { + avl->filename = node->filename; // Don't set node->filename to nil yet + avl->filename_cp1252 = filename; + filename = nil; + } avl->file_size = node->file_size; avl->old_start_sector = node->start_sector; avl->attributes = node->attributes; @@ -1308,24 +1343,35 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 // If we're discovering files outside trees, we don't care about avl_insert errors, since // they represent nodes already discovered before, and we don't want to process them again. // We just free some memory previously allocated - free(avl->filename_utf8); - free(avl->filename); - node->filename = nil; + if (avl->filename) free(avl->filename); + if (avl->filename_cp1252) free(avl->filename_cp1252); free(avl); } else misc_err("this iso appears to be corrupt"); // When not discovering, a duplicate node is an error + node->filename = nil; + } + } + else { + if (filename) { + free(filename); + filename = nil; } + err = process_node(in_xiso, node, in_path, in_mode, nil, strategy); } - else err = process_node(in_xiso, node, in_path, in_mode, nil, strategy); } // Save next offset for discovery if (!err) entry_offset = n_dword(entry_offset * XISO_DWORD_SIZE + XISO_FILENAME_OFFSET + node->filename_length); // Free memory before recurring or iterating + if (filename) { + free(filename); + filename = nil; + } if (node) { - if (node->filename && in_mode != k_generate_avl) free(node->filename); // We copied node->filename in avl->filename_utf8 if 'in_mode' was 'k_generate_avl' + if (node->filename) free(node->filename); free(node); + node = nil; } } while (!err && entry_offset < end_offset && strategy == discover_strategy); // Iterate only if using discover_strategy @@ -1421,7 +1467,7 @@ dir_node_avl *avl_fetch( dir_node_avl *in_root, const char *in_filename ) { for ( ;; ) { if ( in_root == nil ) return nil; - result = avl_compare_key( in_filename, in_root->filename ); + result = avl_compare_key( in_filename, in_root->filename_cp1252); if ( result < 0 ) in_root = in_root->left; else if ( result > 0 ) in_root = in_root->right; @@ -1436,7 +1482,7 @@ avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ) { if ( *in_root == nil ) { *in_root = in_node; return k_avl_balanced; } - result = avl_compare_key( in_node->filename, (*in_root)->filename ); + result = avl_compare_key( in_node->filename_cp1252, (*in_root)->filename_cp1252); if ( result < 0 ) return ( tmp = avl_insert( &(*in_root)->left, in_node ) ) == k_avl_balanced ? avl_left_grown( in_root ) : tmp; if ( result > 0 ) return ( tmp = avl_insert( &(*in_root)->right, in_node ) ) == k_avl_balanced ? avl_right_grown( in_root ) : tmp; @@ -1719,8 +1765,8 @@ int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const char* path int free_dir_node_avl( dir_node_avl *in_dir_node_avl, unused void *in_context, unused int in_depth ) { if ((in_dir_node_avl->attributes & XISO_ATTRIBUTE_DIR) && in_dir_node_avl->subdirectory) avl_traverse_depth_first(in_dir_node_avl->subdirectory, (traversal_callback)free_dir_node_avl, nil, k_postfix, 0); - free(in_dir_node_avl->filename_utf8); - free(in_dir_node_avl->filename); + if (in_dir_node_avl->filename) free(in_dir_node_avl->filename); + free(in_dir_node_avl->filename_cp1252); free(in_dir_node_avl); return 0; @@ -1730,10 +1776,11 @@ int free_dir_node_avl( dir_node_avl *in_dir_node_avl, unused void *in_context, u int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { xoff_t pos = 0, dir_start = (xoff_t)in_avl->start_sector * XISO_SECTOR_SIZE; write_tree_context context = { 0 }; + char* filename = in_avl->filename ? in_avl->filename : in_avl->filename_cp1252; int err = 0, pad = 0; if (in_avl->attributes & XISO_ATTRIBUTE_DIR) { - if (asprintf(&context.path, "%s%s%c", in_context->path ? in_context->path : "", in_context->path ? in_avl->filename_utf8 : "", PATH_CHAR) == -1) mem_err(); + if (asprintf(&context.path, "%s%s%c", in_context->path ? in_context->path : "", in_context->path ? filename : "", PATH_CHAR) == -1) mem_err(); if ( ! err ) { exiso_log( "\nadding\t%s (0 bytes) [OK]", context.path ); @@ -1745,7 +1792,7 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int context.final_bytes = in_context->final_bytes; if ( in_context->from == -1 ) { - if ( chdir(in_avl->filename_utf8) == -1 ) chdir_err(in_avl->filename_utf8); + if ( chdir(filename) == -1 ) chdir_err(filename); } if ( ! err ) err = avl_traverse_depth_first( in_avl->subdirectory, (traversal_callback) write_file, &context, k_prefix, 0 ); @@ -1783,24 +1830,25 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int int err = 0, fd = -1, n = 0, i = 0; size_t len; bool xbe_file; + char* filename = in_avl->filename ? in_avl->filename : in_avl->filename_cp1252; if (!(in_avl->attributes & XISO_ATTRIBUTE_DIR)) { if ( lseek( in_context->xiso, (xoff_t) in_avl->start_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err(); if ( ! err ) { if ( in_context->from == -1 ) { - if ( ( fd = open( in_avl->filename_utf8, READFLAGS, 0 ) ) == -1 ) open_err(in_avl->filename_utf8); + if ( ( fd = open( filename, READFLAGS, 0 ) ) == -1 ) open_err(filename); } else { if (lseek_with_error(fd = in_context->from, (xoff_t)in_avl->old_start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); } } if ( ! err ) { - exiso_log( "\nadding\t%s%s (%u bytes) ", in_context->path, in_avl->filename_utf8, in_avl->file_size ); flush(); + exiso_log( "\nadding\t%s%s (%u bytes) ", in_context->path, filename, in_avl->file_size ); flush(); bytes = in_avl->file_size; - len = strlen(in_avl->filename); // Use Windows-1252 name here - xbe_file = len >= 4 && strcasecmp(&in_avl->filename[len - 4], ".xbe") == 0; + len = strlen(in_avl->filename_cp1252); + xbe_file = len >= 4 && strcasecmp(&in_avl->filename_cp1252[len - 4], ".xbe") == 0; do { n = read(fd, s_copy_buffer + i, min(bytes, READWRITE_BUFFER_SIZE - i)); if (n < 0) read_err(); @@ -1833,7 +1881,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int } exiso_log(err ? "failed" : "[OK]"); - if (!err && size != in_avl->file_size) exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", in_avl->filename_utf8, size, in_avl->file_size); + if (!err && size != in_avl->file_size) exiso_warn("File %s is truncated. Reported size: %u bytes, wrote size: %u bytes!", filename, size, in_avl->file_size); if (!err) { ++s_total_files; @@ -1853,7 +1901,7 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unuse xoff_t pos; uint16_t l_offset, r_offset; uint32_t file_size = (in_avl->attributes & XISO_ATTRIBUTE_DIR) ? n_sectors(in_avl->file_size) * XISO_SECTOR_SIZE : in_avl->file_size; - uint8_t length = (uint8_t)strlen(in_avl->filename); + uint8_t length = (uint8_t)strlen(in_avl->filename_cp1252); int err = 0, pad = 0; little32( in_avl->file_size ); @@ -1876,7 +1924,7 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unuse if ( ! err && write( in_context->xiso, &file_size, XISO_FILESIZE_SIZE ) != XISO_FILESIZE_SIZE ) write_err(); if ( ! err && write( in_context->xiso, &in_avl->attributes, XISO_ATTRIBUTES_SIZE ) != XISO_ATTRIBUTES_SIZE ) write_err(); if ( ! err && write( in_context->xiso, &length, XISO_FILENAME_LENGTH_SIZE ) != XISO_FILENAME_LENGTH_SIZE ) write_err(); - if ( ! err && write( in_context->xiso, in_avl->filename, length ) != length ) write_err(); + if ( ! err && write( in_context->xiso, in_avl->filename_cp1252, length ) != length ) write_err(); little32( in_avl->start_sector ); little32( in_avl->file_size ); @@ -1952,7 +2000,7 @@ int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, int in_d if ( in_depth == 0 ) *out_size = 0; - length = XISO_FILENAME_OFFSET + (uint32_t)strlen( in_avl->filename ); + length = XISO_FILENAME_OFFSET + (uint32_t)strlen(in_avl->filename_cp1252); length += ( XISO_DWORD_SIZE - ( length % XISO_DWORD_SIZE ) ) % XISO_DWORD_SIZE; if ( n_sectors( *out_size + length ) > n_sectors( *out_size ) ) { @@ -1982,14 +2030,19 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { for ( i = *io_n; i; --i ) exiso_log( "\b" ); exiso_log( "%s", p->d_name ); - for ( j = i = (int) strcplen( p->d_name ); j < *io_n; ++j ) exiso_log( " " ); + for ( j = i = (int) strcplen( p->d_name, !s_cp1252 ); j < *io_n; ++j ) exiso_log( " " ); for ( j = i; j < *io_n; ++j ) exiso_log( "\b" ); *io_n = i; flush(); if ( ( avl = (dir_node_avl *) calloc( 1, sizeof(dir_node_avl) ) ) == nil ) mem_err(); - if (!err && (avl->filename_utf8 = strdup(p->d_name)) == nil) mem_err(); - if ( ! err && ( avl->filename = getCP1252String( p->d_name ) ) == nil ) mem_err(); + if (!err && (avl->filename = strdup(p->d_name)) == nil) mem_err(); + if (!err) { + if (s_cp1252) { + avl->filename_cp1252 = avl->filename; + avl->filename = nil; + } else if ((avl->filename_cp1252 = getCP1252String(p->d_name)) == nil) mem_err(); + } if ( ! err && stat( p->d_name, &sb ) == -1 ) read_err(); if ( ! err ) { if ( S_ISDIR( sb.st_mode ) ) { @@ -2003,9 +2056,9 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { } else if ( S_ISREG( sb.st_mode ) ) { if ( sb.st_size > (int64_t)UINT32_MAX ) { log_err( __FILE__, __LINE__, "file %s is too large for xiso, skipping...", p->d_name); - free(avl->filename_utf8); - free( avl->filename ); - free( avl ); + if (avl->filename) free(avl->filename); + free(avl->filename_cp1252); + free(avl); continue; } empty_dir = false; @@ -2013,19 +2066,19 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { s_total_bytes += avl->file_size = (uint32_t) sb.st_size; ++s_total_files; } else { - free(avl->filename_utf8); - free( avl->filename ); - free( avl ); + if (avl->filename) free(avl->filename); + free(avl->filename_cp1252); + free(avl); continue; } } if ( ! err ) { - if ( avl_insert( out_root, avl ) == k_avl_error ) misc_err( "error inserting file %s into tree (duplicate filename?)", avl->filename_utf8 ); + if ( avl_insert( out_root, avl ) == k_avl_error ) misc_err( "error inserting file %s into tree (duplicate filename?)", avl->filename); } else { if ( avl ) { - if (avl->filename_utf8) free(avl->filename_utf8); - if ( avl->filename ) free( avl->filename ); - free( avl ); + if (avl->filename) free(avl->filename); + free(avl->filename_cp1252); + free(avl); } } } From c9f5b4bbfd97e319df17ddd6a0ff907b541f61d7 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Wed, 29 Mar 2023 23:35:35 +0200 Subject: [PATCH 37/59] Replace nil with standard NULL, remove unused defines --- extract-xiso.c | 205 +++++++++++++++++++++++-------------------------- 1 file changed, 94 insertions(+), 111 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 0133b9b..ed9b538 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -382,11 +382,7 @@ typedef off_t xoff_t; #endif -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) /* All BSD systems, but this macro is unused anyways */ - #define FORCE_ASCII 1 -#else - #define FORCE_ASCII 0 -#endif +typedef int64_t file_time_t; #if CHAR_BIT != 8 #error unsupported char size, cannot compile! @@ -422,18 +418,11 @@ #define little64(n) #endif - -#define DEBUG_VERIFY_XISO 0 -#define DEBUG_OPTIMIZE_XISO 0 -#define DEBUG_TRAVERSE_XISO_DIR 0 - -typedef int64_t file_time_t; - -#ifndef nil - #define nil 0 +#ifndef min + #define min(a, b) ( (a) < (b) ? (a) : (b) ) + #define max(a, b) ( (a) > (b) ? (a) : (b) ) #endif - #define exiso_version "2.7.1 (01.11.14)" #define VERSION_LENGTH 16 @@ -461,12 +450,6 @@ typedef int64_t file_time_t; #define misc_err( ... ) do{ log_err( __FILE__, __LINE__, __VA_ARGS__ ); err = 1; } while(0) -#ifndef min - #define min( a , b ) ( ( a ) < ( b ) ? ( a ) : ( b ) ) - #define max( a , b ) ( ( a ) > ( b ) ? ( a ) : ( b ) ) -#endif - - #define START_LSEEK_OFFSET 0x00000000ul #define XGD3_LSEEK_OFFSET 0x02080000ul #define XGD2_LSEEK_OFFSET 0x0FD90000ul @@ -529,8 +512,8 @@ xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_OFFSET #define GETOPT_STRING "c:d:Dhlmp:qQrsvx" -char* cp1252_locales[] = { ".1252" /* Windows */, "C.CP1252", "en_US.CP1252", "de_DE.CP1252", nil }; -char* utf8_locales[] = { ".UTF-8" /* Windows */, "C.UTF-8", "en_US.UTF-8", nil }; +char* cp1252_locales[] = { ".1252" /* Windows */, "C.CP1252", "en_US.CP1252", "de_DE.CP1252", NULL }; +char* utf8_locales[] = { ".UTF-8" /* Windows */, "C.UTF-8", "en_US.UTF-8", NULL }; typedef enum avl_skew { k_no_skew , k_left_skew , k_right_skew } avl_skew; @@ -641,12 +624,12 @@ void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char static long s_pat_len; static bool s_quiet = false; -static const char *s_pattern = nil; -static long *s_gs_table = nil; -static long *s_bc_table = nil; +static const char *s_pattern = NULL; +static long *s_gs_table = NULL; +static long *s_bc_table = NULL; static long long s_total_bytes = 0; static int s_total_files = 0; -static char *s_copy_buffer = nil; +static char *s_copy_buffer = NULL; static bool s_real_quiet = false; static bool s_media_enable = true; static long long s_total_bytes_all_isos = 0; @@ -667,11 +650,11 @@ static xoff_t s_xbox_disc_lseek = 0; int main( int argc, char **argv ) { struct stat sb; - create_list *create = nil, *p, *q; + create_list *create = NULL, *p, *q; int i, fd, opt_char, err = 0, isos = 0; bool extract = true, rewrite = false, x_seen = false, delete = false, optimized; ptrdiff_t diff; - char *path = nil, *buf = nil, *new_iso_path = nil, *locale = nil, **locale_arr = nil; + char *path = NULL, *buf = NULL, *new_iso_path = NULL, *locale = NULL, **locale_arr = NULL; char tag[XISO_OPTIMIZED_TAG_LENGTH + 1]; if (argc < 2) usage_and_exit(1); @@ -681,21 +664,21 @@ int main( int argc, char **argv ) { case 'c': { if (x_seen || rewrite || !extract) usage_and_exit(1); - if (create == nil) { - if ((p = create = (create_list*)calloc(1, sizeof(create_list))) == nil) mem_err(); + if (create == NULL) { + if ((p = create = (create_list*)calloc(1, sizeof(create_list))) == NULL) mem_err(); } else { p = create; - while (p != nil && p->next != nil) p = p->next; - if ((p = p->next = (create_list*)calloc(1, sizeof(create_list))) == nil) mem_err(); + while (p != NULL && p->next != NULL) p = p->next; + if ((p = p->next = (create_list*)calloc(1, sizeof(create_list))) == NULL) mem_err(); } - if (!err && (p->path = strdup(optarg)) == nil) mem_err(); - if (!err && argv[optind] && *argv[optind] != '-' && *argv[optind] && (p->name = strdup(argv[optind++])) == nil) mem_err(); + if (!err && (p->path = strdup(optarg)) == NULL) mem_err(); + if (!err && argv[optind] && *argv[optind] != '-' && *argv[optind] && (p->name = strdup(argv[optind++])) == NULL) mem_err(); } break; case 'd': { if ( path ) free( path ); - if ( ( path = strdup( optarg ) ) == nil ) mem_err(); + if ( ( path = strdup( optarg ) ) == NULL ) mem_err(); } break; case 'D': { @@ -758,7 +741,7 @@ int main( int argc, char **argv ) { exiso_log(banner); - if ((extract || rewrite || create) && (s_copy_buffer = (char*)malloc(READWRITE_BUFFER_SIZE)) == nil) mem_err(); + if ((extract || rewrite || create) && (s_copy_buffer = (char*)malloc(READWRITE_BUFFER_SIZE)) == NULL) mem_err(); locale_arr = cp1252_locales; while (*locale_arr) { @@ -783,11 +766,11 @@ int main( int argc, char **argv ) { if ( ! err && create ) { p = create; - while (!err && p != nil) { + while (!err && p != NULL) { diff = 0; if ( p->name && (buf = strrchr(p->name, PATH_CHAR)) ) { diff = buf - p->name; - if ( ( buf = (char *) malloc( diff + 1 ) ) == nil ) mem_err(); + if ( ( buf = (char *) malloc( diff + 1 ) ) == NULL ) mem_err(); if ( ! err ) { strncpy( buf, p->name, diff ); buf[ diff ] = 0; @@ -795,9 +778,9 @@ int main( int argc, char **argv ) { diff += 1; } - if ( ! err ) err = create_xiso( p->path, buf, nil, -1, nil, p->name ? p->name + diff : nil, nil ); + if ( ! err ) err = create_xiso( p->path, buf, NULL, -1, NULL, p->name ? p->name + diff : NULL, NULL ); - if (buf) { free(buf); buf = nil; } + if (buf) { free(buf); buf = NULL; } q = p->next; @@ -835,17 +818,17 @@ int main( int argc, char **argv ) { if (err) { err = 0; - if (buf) { free(buf); buf = nil; } + if (buf) { free(buf); buf = NULL; } continue; } err = decode_xiso(buf, path, k_rewrite, &new_iso_path); if (!err && delete && unlink(buf) == -1) log_err(__FILE__, __LINE__, "unable to delete %s", buf); - if (buf) { free(buf); buf = nil; } + if (buf) { free(buf); buf = NULL; } } else { // the order of the mutually exclusive options here is important, the extract ? k_extract : k_list test *must* be the final comparison - err = decode_xiso( argv[ i ], extract ? path : nil, extract ? k_extract : k_list, nil ); + err = decode_xiso( argv[ i ], extract ? path : NULL, extract ? k_extract : k_list, NULL ); } } @@ -859,7 +842,7 @@ int main( int argc, char **argv ) { if ( ! err ) exiso_log( "\n%s successfully rewritten%s%s\n", argv[ i ], path ? " as " : ".", path ? new_iso_path : "" ); free( new_iso_path ); - new_iso_path = nil; + new_iso_path = NULL; } if ( err == err_iso_no_files ) err = 0; @@ -1007,11 +990,11 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n write_tree_context wt_context = { 0 }; uint32_t start_sector = 0; int i = 0, n = 0, xiso = -1, err = 0; - char *cwd = nil, *iso_name = nil, *xiso_path = nil, *iso_dir = nil, *real_path = nil; + char *cwd = NULL, *iso_name = NULL, *xiso_path = NULL, *iso_dir = NULL, *real_path = NULL; s_total_bytes = s_total_files = 0; - if ( ( cwd = getcwd( nil, 0 ) ) == nil ) mem_err(); + if ( ( cwd = getcwd( NULL, 0 ) ) == NULL ) mem_err(); if ( ! err ) { if ( ! in_root ) { i = (int)strlen(in_root_directory) - 1; @@ -1028,11 +1011,11 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if ( ! *iso_dir ) iso_dir = PATH_CHAR_STR; if ( ! iso_name || ! *iso_name ) iso_name = "root"; else if ( iso_name[ 1 ] == ':' ) { iso_name[ 1 ] = iso_name[ 0 ]; ++iso_name; } - if (!err && (real_path = realpath(in_output_directory ? in_output_directory : ".", nil)) == nil) misc_err("unable to get absolute path of %s: %s", real_path, strerror(errno)); + if (!err && (real_path = realpath(in_output_directory ? in_output_directory : ".", NULL)) == NULL) misc_err("unable to get absolute path of %s: %s", real_path, strerror(errno)); if (!err && (asprintf(&xiso_path, "%s%c%s%s", real_path, PATH_CHAR, iso_name, in_name ? "" : ".iso")) == -1) mem_err(); if (real_path) { free(real_path); - real_path = nil; + real_path = NULL; } if (!err && !in_root && chdir(in_root_directory) == -1) chdir_err(in_root_directory); @@ -1047,7 +1030,7 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if ( in_root ) { root.subdirectory = in_root; - avl_traverse_depth_first( &root, (traversal_callback) calculate_total_files_and_bytes, nil, k_prefix, 0 ); + avl_traverse_depth_first( &root, (traversal_callback) calculate_total_files_and_bytes, NULL, k_prefix, 0 ); } else { n = 0; @@ -1070,7 +1053,7 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n start_sector = root.start_sector; - avl_traverse_depth_first( &root, (traversal_callback) calculate_directory_requirements, nil, k_prefix, 0 ); + avl_traverse_depth_first( &root, (traversal_callback) calculate_directory_requirements, NULL, k_prefix, 0 ); avl_traverse_depth_first( &root, (traversal_callback) calculate_directory_offsets, &start_sector, k_prefix, 0 ); } if ( ! err ) { @@ -1078,7 +1061,7 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if (out_iso_path) *out_iso_path = xiso_path; else { free(xiso_path); - xiso_path = nil; + xiso_path = NULL; } } if ( ! err ) { @@ -1113,18 +1096,18 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if ( ! err && ! in_root ) { if ( chdir( ".." ) == -1 ) chdir_err( ".." ); } - if (!err && (root.filename = strdup(iso_dir)) == nil) mem_err(); + if (!err && (root.filename = strdup(iso_dir)) == NULL) mem_err(); if (!err) { if (s_cp1252) { root.filename_cp1252 = root.filename; - root.filename = nil; + root.filename = NULL; } - else if ((root.filename_cp1252 = getCP1252String(iso_dir)) == nil) mem_err(); + else if ((root.filename_cp1252 = getCP1252String(iso_dir)) == NULL) mem_err(); } if ( ! err && lseek( xiso, (xoff_t) root.start_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err(); if ( ! err ) { - wt_context.path = nil; + wt_context.path = NULL; wt_context.xiso = xiso; wt_context.from = in_root ? in_xiso : -1; wt_context.progress = in_progress_callback; @@ -1149,7 +1132,7 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n else exiso_log( "\n\nsuccessfully created %s%s (%u files totalling %lld bytes added)\n", iso_name ? iso_name : "xiso", iso_name && ! in_name ? ".iso" : "", s_total_files, s_total_bytes ); } - if ( root.subdirectory ) avl_traverse_depth_first( root.subdirectory, (traversal_callback) free_dir_node_avl, nil, k_postfix, 0 ); + if ( root.subdirectory ) avl_traverse_depth_first( root.subdirectory, (traversal_callback) free_dir_node_avl, NULL, k_postfix, 0 ); if ( xiso != -1 ) { close( xiso ); @@ -1169,13 +1152,13 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ) { - dir_node_avl *root = nil; + dir_node_avl *root = NULL; xoff_t root_dir_start; uint32_t root_dir_sect = 0, root_dir_size = 0; uint16_t root_end_offset; size_t len; int xiso = 0, err = 0; - char *path = nil, *cwd = nil, *name = nil, *short_name = nil, *iso_name = nil; + char *path = NULL, *cwd = NULL, *name = NULL, *short_name = NULL, *iso_name = NULL; if ((xiso = open(in_xiso, READFLAGS, 0)) == -1) open_err(in_xiso); @@ -1188,7 +1171,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat // create a directory of the same name as the file we are working on, minus the ".iso" portion if ((len = strlen(name)) >= 4 && strcasecmp(&name[len - 4], ".iso") == 0) { name[len - 4] = '\0'; - if ((short_name = strdup(name)) == nil) mem_err(); + if ((short_name = strdup(name)) == NULL) mem_err(); name[len - 4] = '.'; } @@ -1202,7 +1185,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if (!err && in_mode == k_extract) { if (in_path) { if (strlen(in_path) == 0) misc_err("empty destination path"); - if (!err && (cwd = getcwd(nil, 0)) == nil) mem_err(); + if (!err && (cwd = getcwd(NULL, 0)) == NULL) mem_err(); if (!err && mkdir(in_path, 0755) == -1) mkdir_err(in_path); if (!err && chdir(in_path) == -1) chdir_err(in_path); } @@ -1226,16 +1209,16 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat if (!err && lseek_with_error(xiso, root_dir_start, SEEK_SET) == -1) seek_err(); if (in_mode == k_rewrite) { - if (!err && root_dir_size == 0) root = nil; + if (!err && root_dir_size == 0) root = NULL; else { if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, k_generate_avl, &root, tree_strategy); if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, k_generate_avl, &root, discover_strategy); } - if (!err) err = create_xiso(iso_name, in_path, root, xiso, out_iso_path, nil, nil); + if (!err) err = create_xiso(iso_name, in_path, root, xiso, out_iso_path, NULL, NULL); } else { exiso_log("\n%s%s (0 bytes)%s", in_mode == k_extract ? "creating\t" : "", path, in_mode == k_extract ? " [OK]" : ""); flush(); - if (!err && root_dir_size != 0) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, in_mode, nil, discover_strategy); + if (!err && root_dir_size != 0) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, in_mode, NULL, discover_strategy); } if(path) free(path); @@ -1259,11 +1242,11 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { - dir_node_avl *avl = nil; - dir_node *node = nil; + dir_node_avl *avl = NULL; + dir_node *node = NULL; uint16_t l_offset = 0, r_offset = 0; int err = 0; - char *filename = nil; + char *filename = NULL; if (entry_offset >= end_offset) misc_err("attempt to read node entry beyond directory end"); @@ -1273,7 +1256,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 if (!err && read(in_xiso, &l_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); if (!err && l_offset == XISO_PAD_SHORT) { if (entry_offset == 0) { // Empty directories have padding starting at the beginning - if (in_mode == k_generate_avl) *in_root = nil; + if (in_mode == k_generate_avl) *in_root = NULL; return err; // Done } else if (strategy != discover_strategy) { // When discovering, the padding means end of sector @@ -1286,7 +1269,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 } // Read node - if (!err) if ((node = calloc(1, sizeof(dir_node))) == nil) mem_err(); + if (!err) if ((node = calloc(1, sizeof(dir_node))) == NULL) mem_err(); if (!err && read(in_xiso, &r_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); if (!err && read(in_xiso, &node->start_sector, XISO_SECTOR_OFFSET_SIZE) != XISO_SECTOR_OFFSET_SIZE) read_err(); if (!err && read(in_xiso, &node->file_size, XISO_FILESIZE_SIZE) != XISO_FILESIZE_SIZE) read_err(); @@ -1300,7 +1283,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 little16(r_offset); little32(node->file_size); little32(node->start_sector); - if ((filename = malloc((size_t)node->filename_length + 1)) == nil) mem_err(); + if ((filename = malloc((size_t)node->filename_length + 1)) == NULL) mem_err(); if (!err && read(in_xiso, filename, node->filename_length) != node->filename_length) read_err(); if (!err) { filename[node->filename_length] = '\0'; @@ -1313,9 +1296,9 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 if (s_cp1252) { node->filename = filename; - filename = nil; + filename = NULL; } - else if ((node->filename = getUTF8String(filename)) == nil) mem_err(); + else if ((node->filename = getUTF8String(filename)) == NULL) mem_err(); } } @@ -1323,16 +1306,16 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 // Process the node according to the mode if (!err) { if (in_mode == k_generate_avl) { - if ((avl = (dir_node_avl*)calloc(1, sizeof(dir_node_avl))) == nil) mem_err(); + if ((avl = (dir_node_avl*)calloc(1, sizeof(dir_node_avl))) == NULL) mem_err(); if (!err) { if (s_cp1252) { - avl->filename = nil; - avl->filename_cp1252 = node->filename; // Don't set node->filename to nil yet + avl->filename = NULL; + avl->filename_cp1252 = node->filename; // Don't set node->filename to NULL yet } else { - avl->filename = node->filename; // Don't set node->filename to nil yet + avl->filename = node->filename; // Don't set node->filename to NULL yet avl->filename_cp1252 = filename; - filename = nil; + filename = NULL; } avl->file_size = node->file_size; avl->old_start_sector = node->start_sector; @@ -1348,15 +1331,15 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 free(avl); } else misc_err("this iso appears to be corrupt"); // When not discovering, a duplicate node is an error - node->filename = nil; + node->filename = NULL; } } else { if (filename) { free(filename); - filename = nil; + filename = NULL; } - err = process_node(in_xiso, node, in_path, in_mode, nil, strategy); + err = process_node(in_xiso, node, in_path, in_mode, NULL, strategy); } } @@ -1366,12 +1349,12 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 // Free memory before recurring or iterating if (filename) { free(filename); - filename = nil; + filename = NULL; } if (node) { if (node->filename) free(node->filename); free(node); - node = nil; + node = NULL; } } while (!err && entry_offset < end_offset && strategy == discover_strategy); // Iterate only if using discover_strategy @@ -1394,7 +1377,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 } int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { - char *path = nil; + char *path = NULL; int err = 0; xoff_t dir_start = (xoff_t)node->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; uint16_t end_offset = 0; @@ -1419,7 +1402,7 @@ int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode if (!err) { // Recurse on subdirectory if (node->file_size == 0) { - if (in_mode == k_generate_avl) *in_root = nil; + if (in_mode == k_generate_avl) *in_root = NULL; } else { if (in_path && asprintf(&path, "%s%s%c", in_path, node->filename, PATH_CHAR) == -1) mem_err(); @@ -1465,7 +1448,7 @@ dir_node_avl *avl_fetch( dir_node_avl *in_root, const char *in_filename ) { int result; for ( ;; ) { - if ( in_root == nil ) return nil; + if ( in_root == NULL ) return NULL; result = avl_compare_key( in_filename, in_root->filename_cp1252); @@ -1480,7 +1463,7 @@ avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ) { avl_result tmp; int result; - if ( *in_root == nil ) { *in_root = in_node; return k_avl_balanced; } + if ( *in_root == NULL ) { *in_root = in_node; return k_avl_balanced; } result = avl_compare_key( in_node->filename_cp1252, (*in_root)->filename_cp1252); @@ -1610,7 +1593,7 @@ int avl_compare_key( const char *in_lhs, const char *in_rhs ) { int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, int in_depth ) { int err; - if ( in_root == nil ) return 0; + if ( in_root == NULL ) return 0; switch ( in_method ) { case k_prefix: { @@ -1649,13 +1632,13 @@ int boyer_moore_init( const char *in_pattern, long in_pat_len, long in_alphabet_ s_pattern = in_pattern; s_pat_len = in_pat_len; - if ( ( s_bc_table = (long *) malloc( in_alphabet_size * sizeof(long) ) ) == nil ) mem_err(); + if ( ( s_bc_table = (long *) malloc( in_alphabet_size * sizeof(long) ) ) == NULL ) mem_err(); if ( ! err ) { for ( i = 0; i < in_alphabet_size; ++i ) s_bc_table[ i ] = in_pat_len; for ( i = 0; i < in_pat_len - 1; ++i ) s_bc_table[ (uint8_t) in_pattern[ i ] ] = in_pat_len - i - 1; - if ( ( s_gs_table = (long *) malloc( 2 * ( in_pat_len + 1 ) * sizeof(long) ) ) == nil ) mem_err(); + if ( ( s_gs_table = (long *) malloc( 2 * ( in_pat_len + 1 ) * sizeof(long) ) ) == NULL ) mem_err(); } if ( ! err ) { @@ -1684,8 +1667,8 @@ int boyer_moore_init( const char *in_pattern, long in_pat_len, long in_alphabet_ void boyer_moore_done() { - if ( s_bc_table ) { free( s_bc_table ); s_bc_table = nil; } - if ( s_gs_table ) { free( s_gs_table ); s_gs_table = nil; } + if ( s_bc_table ) { free( s_bc_table ); s_bc_table = NULL; } + if ( s_gs_table ) { free( s_gs_table ); s_gs_table = NULL; } } @@ -1704,7 +1687,7 @@ char *boyer_moore_search( char *in_text, long in_text_len ) { } } - return i < 0 ? in_text + j + 1 : nil; + return i < 0 ? in_text + j + 1 : NULL; } @@ -1763,7 +1746,7 @@ int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const char* path int free_dir_node_avl( dir_node_avl *in_dir_node_avl, unused void *in_context, unused int in_depth ) { - if ((in_dir_node_avl->attributes & XISO_ATTRIBUTE_DIR) && in_dir_node_avl->subdirectory) avl_traverse_depth_first(in_dir_node_avl->subdirectory, (traversal_callback)free_dir_node_avl, nil, k_postfix, 0); + if ((in_dir_node_avl->attributes & XISO_ATTRIBUTE_DIR) && in_dir_node_avl->subdirectory) avl_traverse_depth_first(in_dir_node_avl->subdirectory, (traversal_callback)free_dir_node_avl, NULL, k_postfix, 0); if (in_dir_node_avl->filename) free(in_dir_node_avl->filename); free(in_dir_node_avl->filename_cp1252); @@ -1825,7 +1808,7 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { - char *p = nil; + char *p = NULL; uint32_t bytes = 0, size = 0; int err = 0, fd = -1, n = 0, i = 0; size_t len; @@ -1859,7 +1842,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int bytes -= n; if (s_media_enable && xbe_file) { n += i; - for (p = s_copy_buffer; (p = boyer_moore_search(p, n - (long)(p - s_copy_buffer))) != nil; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; + for (p = s_copy_buffer; (p = boyer_moore_search(p, n - (long)(p - s_copy_buffer))) != NULL; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; if (bytes) { i = XISO_MEDIA_ENABLE_LENGTH - 1; n -= i; @@ -1971,7 +1954,7 @@ int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io int calculate_total_files_and_bytes( dir_node_avl *in_avl, unused void *in_context, unused int in_depth ) { if (in_avl->attributes & XISO_ATTRIBUTE_DIR) { if (in_avl->subdirectory) { - avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_total_files_and_bytes, nil, k_prefix, 0); + avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_total_files_and_bytes, NULL, k_prefix, 0); } } else { ++s_total_files; @@ -2016,16 +1999,16 @@ int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, int in_d int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { - struct dirent *p = nil; + struct dirent *p = NULL; struct stat sb = { 0 }; - dir_node_avl *avl = nil; - DIR *dir = nil; + dir_node_avl *avl = NULL; + DIR *dir = NULL; int err = 0, i = 0, j = 0; bool empty_dir = true; - if ( ( dir = opendir( "." ) ) == nil ) mem_err(); + if ( ( dir = opendir( "." ) ) == NULL ) mem_err(); - while ( ! err && ( p = readdir( dir ) ) != nil ) { + while ( ! err && ( p = readdir( dir ) ) != NULL ) { if ( ! strcmp( p->d_name, "." ) || ! strcmp( p->d_name, ".." ) ) continue; for ( i = *io_n; i; --i ) exiso_log( "\b" ); @@ -2035,13 +2018,13 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { *io_n = i; flush(); - if ( ( avl = (dir_node_avl *) calloc( 1, sizeof(dir_node_avl) ) ) == nil ) mem_err(); - if (!err && (avl->filename = strdup(p->d_name)) == nil) mem_err(); + if ( ( avl = (dir_node_avl *) calloc( 1, sizeof(dir_node_avl) ) ) == NULL ) mem_err(); + if (!err && (avl->filename = strdup(p->d_name)) == NULL) mem_err(); if (!err) { if (s_cp1252) { avl->filename_cp1252 = avl->filename; - avl->filename = nil; - } else if ((avl->filename_cp1252 = getCP1252String(p->d_name)) == nil) mem_err(); + avl->filename = NULL; + } else if ((avl->filename_cp1252 = getCP1252String(p->d_name)) == NULL) mem_err(); } if ( ! err && stat( p->d_name, &sb ) == -1 ) read_err(); if ( ! err ) { @@ -2083,7 +2066,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { } } - if ( empty_dir ) *out_root = nil; + if ( empty_dir ) *out_root = NULL; if ( dir ) closedir( dir ); @@ -2095,8 +2078,8 @@ int get_filetime_now(file_time_t *ft) { time_t now = 0; int err = 0; - if (ft == nil) return 1; - if ( ( now = time( nil ) ) == -1 ) unknown_err(); + if (ft == NULL) return 1; + if ( ( now = time( NULL ) ) == -1 ) unknown_err(); if ( ! err ) { *ft = (now * 10000000LL) + 116444736000000000LL; // Magic numbers directly from Microsoft little64(*ft); // convert to little endian here because this is a PC only struct and we won't read it anyway @@ -2159,9 +2142,9 @@ void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char ssize_t wrote; xoff_t curpos = 0; int fp = -1, err = 0; - char *cwd, *sect = nil, buf[ 256 ]; + char *cwd, *sect = NULL, buf[ 256 ]; - if ( ( cwd = getcwd( nil, 0 ) ) == nil ) mem_err(); + if ( ( cwd = getcwd( NULL, 0 ) ) == NULL ) mem_err(); if ( ! err && chdir( DEBUG_DUMP_DIRECTORY ) == -1 ) chdir_err( DEBUG_DUMP_DIRECTORY ); sprintf( buf, "%" PRId64 ".%s.%s", in_start, in_name, in_extension ? in_extension : ""); @@ -2170,7 +2153,7 @@ void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char if ( ! err && ( curpos = lseek_with_error( in_xiso, 0, SEEK_CUR ) ) == -1 ) seek_err(); if ( ! err && lseek_with_error( in_xiso, in_start, SEEK_SET ) == -1 ) seek_err(); - if ( ! err && ( sect = (char *) malloc( XISO_SECTOR_SIZE ) ) == nil ) mem_err(); + if ( ! err && ( sect = (char *) malloc( XISO_SECTOR_SIZE ) ) == NULL ) mem_err(); if ( ! err && read( in_xiso, sect, XISO_SECTOR_SIZE ) != XISO_SECTOR_SIZE ) read_err(); if ( ! err && ( wrote = write( fp, sect, XISO_SECTOR_SIZE ) ) != XISO_SECTOR_SIZE ) write_err(); From a56c7b287af120263edf9ec8eeb174b21f053f91 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Thu, 30 Mar 2023 00:02:25 +0200 Subject: [PATCH 38/59] Simplify locale selection code --- extract-xiso.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index ed9b538..11a7a5f 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -743,23 +743,17 @@ int main( int argc, char **argv ) { if ((extract || rewrite || create) && (s_copy_buffer = (char*)malloc(READWRITE_BUFFER_SIZE)) == NULL) mem_err(); + } + + if (!err) { locale_arr = cp1252_locales; - while (*locale_arr) { - locale = setlocale(LC_ALL, *locale_arr); - if (locale) break; - locale_arr++; - } + while (*locale_arr && !locale) locale = setlocale(LC_ALL, *locale_arr++); if (locale) s_cp1252 = true; else { locale_arr = utf8_locales; - while (*locale_arr) { - locale = setlocale(LC_ALL, *locale_arr); - if (locale) break; - locale_arr++; - } + while (*locale_arr && !locale) locale = setlocale(LC_ALL, *locale_arr++); if (!locale) exiso_warn("Using %s locale. Non-ASCII characters will probably not be represented correctly.", setlocale(LC_ALL, NULL)); } - } if ( ! err && ( create || rewrite ) ) err = boyer_moore_init( XISO_MEDIA_ENABLE, XISO_MEDIA_ENABLE_LENGTH, k_default_alphabet_size ); From 0e6eeafc69353b8446a27c173bc4a0e33a25bc49 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Thu, 30 Mar 2023 09:16:03 +0200 Subject: [PATCH 39/59] Add const qualifiers --- extract-xiso.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 11a7a5f..4d36f99 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -457,7 +457,7 @@ typedef int64_t file_time_t; #define XGD2_ALT_LSEEK_OFFSET 0x89D80000ul #define LSEEK_OFFSETS_LEN 5 /* The offsets should be in ascending order, otherwise we could get a seek error before checking the correct one */ -xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_OFFSET, XGD2_LSEEK_OFFSET, XGD1_LSEEK_OFFSET, XGD2_ALT_LSEEK_OFFSET}; +const xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_OFFSET, XGD2_LSEEK_OFFSET, XGD1_LSEEK_OFFSET, XGD2_ALT_LSEEK_OFFSET}; #define XISO_HEADER_DATA "MICROSOFT*XBOX*MEDIA" #define XISO_HEADER_DATA_LENGTH 20 @@ -512,8 +512,8 @@ xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_OFFSET #define GETOPT_STRING "c:d:Dhlmp:qQrsvx" -char* cp1252_locales[] = { ".1252" /* Windows */, "C.CP1252", "en_US.CP1252", "de_DE.CP1252", NULL }; -char* utf8_locales[] = { ".UTF-8" /* Windows */, "C.UTF-8", "en_US.UTF-8", NULL }; +const char* const cp1252_locales[] = { ".1252" /* Windows */, "C.CP1252", "en_US.CP1252", "de_DE.CP1252", NULL }; +const char* const utf8_locales[] = { ".UTF-8" /* Windows */, "C.UTF-8", "en_US.UTF-8", NULL }; typedef enum avl_skew { k_no_skew , k_left_skew , k_right_skew } avl_skew; @@ -649,13 +649,15 @@ static xoff_t s_xbox_disc_lseek = 0; int main( int argc, char **argv ) { - struct stat sb; - create_list *create = NULL, *p, *q; - int i, fd, opt_char, err = 0, isos = 0; - bool extract = true, rewrite = false, x_seen = false, delete = false, optimized; - ptrdiff_t diff; - char *path = NULL, *buf = NULL, *new_iso_path = NULL, *locale = NULL, **locale_arr = NULL; - char tag[XISO_OPTIMIZED_TAG_LENGTH + 1]; + struct stat sb; + create_list *create = NULL, *p, *q; + int i, fd, opt_char, err = 0, isos = 0; + bool extract = true, rewrite = false, x_seen = false, delete = false, optimized; + ptrdiff_t diff; + char *path = NULL, *buf = NULL, *new_iso_path = NULL; + const char *locale = NULL; + const char* const *locale_arr = NULL; + char tag[XISO_OPTIMIZED_TAG_LENGTH + 1]; if (argc < 2) usage_and_exit(1); From 36a9a1f8cc9b5e135156a033e3de63ef3be3c816 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sat, 1 Apr 2023 16:37:18 +0200 Subject: [PATCH 40/59] Rewrite boyer moore implementation It has been externally tested with many test cases, including specific tests for the Rytter correction --- extract-xiso.c | 101 ++++++++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 4d36f99..d6ffe9d 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -593,8 +593,8 @@ avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ); int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, int in_depth ); void boyer_moore_done(); -char *boyer_moore_search( char *in_text, long in_text_len ); -int boyer_moore_init( const char *in_pattern, long in_pat_len, long in_alphabet_size ); +char *boyer_moore_search( char *in_text, size_t in_text_len ); +int boyer_moore_init( const char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ); int free_dir_node_avl(dir_node_avl* in_dir_node_avl, void* in_context, int in_depth); int extract_file( int in_xiso, dir_node *in_file, modes in_mode, const char *path ); @@ -622,11 +622,11 @@ void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char #endif -static long s_pat_len; +static size_t s_pat_len; static bool s_quiet = false; static const char *s_pattern = NULL; -static long *s_gs_table = NULL; -static long *s_bc_table = NULL; +static size_t *s_gs_table = NULL; +static size_t *s_bc_table = NULL; static long long s_total_bytes = 0; static int s_total_files = 0; static char *s_copy_buffer = NULL; @@ -1622,41 +1622,58 @@ int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callb #endif -int boyer_moore_init( const char *in_pattern, long in_pat_len, long in_alphabet_size ) { - long i, j, k, *backup, err = 0; +int boyer_moore_init( const char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ) { + size_t j, k, t, t1, q, q1, *aux = NULL; + int err = 0; s_pattern = in_pattern; s_pat_len = in_pat_len; - - if ( ( s_bc_table = (long *) malloc( in_alphabet_size * sizeof(long) ) ) == NULL ) mem_err(); - - if ( ! err ) { - for ( i = 0; i < in_alphabet_size; ++i ) s_bc_table[ i ] = in_pat_len; - for ( i = 0; i < in_pat_len - 1; ++i ) s_bc_table[ (uint8_t) in_pattern[ i ] ] = in_pat_len - i - 1; - - if ( ( s_gs_table = (long *) malloc( 2 * ( in_pat_len + 1 ) * sizeof(long) ) ) == NULL ) mem_err(); - } - if ( ! err ) { - backup = s_gs_table + in_pat_len + 1; - - for ( i = 1; i <= in_pat_len; ++i ) s_gs_table[ i ] = 2 * in_pat_len - i; - for ( i = in_pat_len, j = in_pat_len + 1; i; --i, --j ) { - backup[ i ] = j; + boyer_moore_done(); // Prepare for a new init + + if (in_pat_len == 0) return 0; - while ( j <= in_pat_len && in_pattern[ i - 1 ] != in_pattern[ j - 1 ] ) { - if ( s_gs_table[ j ] > in_pat_len - i ) s_gs_table[ j ] = in_pat_len - i; - j = backup[ j ]; + // Delta1 table + if ((s_bc_table = (size_t*)malloc(in_alphabet_size * sizeof(size_t))) == NULL) mem_err(); + if (!err) { + for (k = 0; k < in_alphabet_size; k++) s_bc_table[k] = in_pat_len; + for (k = 0; k < in_pat_len; k++) s_bc_table[(unsigned char)in_pattern[k]] = in_pat_len - 1 - k; + } + + // Delta2 table (dd' algorithm with Rytter correction) + if (!err && (s_gs_table = (size_t*)malloc(in_pat_len * sizeof(size_t))) == NULL) mem_err(); + if (!err && (aux = (size_t*)malloc(in_pat_len * sizeof(size_t))) == NULL) mem_err(); + if (!err) { + // Step A1 + for (k = 1; k <= in_pat_len; k++) s_gs_table[k - 1] = 2 * in_pat_len - k; + + // Step A2 + for (j = in_pat_len, t = in_pat_len + 1; j > 0; j--, t--) { + aux[j - 1] = t; + while (t <= in_pat_len && in_pattern[j - 1] != in_pattern[t - 1]) { + s_gs_table[t - 1] = min(s_gs_table[t - 1], in_pat_len - j); + t = aux[t - 1]; } } - for ( i = 1; i <= j; ++i ) if ( s_gs_table[ i ] > in_pat_len + j - i ) s_gs_table[ i ] = in_pat_len + j - i; - - k = backup[ j ]; - - for ( ; j <= in_pat_len; k = backup[ k ] ) { - for ( ; j <= k; ++j ) if ( s_gs_table[ j ] >= k - j + in_pat_len ) s_gs_table[ j ] = k - j + in_pat_len; + + // Step B1 + q = t; t = in_pat_len + 1 - q; + for (j = 1, t1 = 0; j <= t; t1++, j++) { + aux[j - 1] = t1; + while (t1 >= 1 && in_pattern[j - 1] != in_pattern[t1 - 1]) t1 = aux[t1 - 1]; + } + + // Step B2 + q1 = 1; + while (q < in_pat_len) { + for (k = q1; k <= q; k++) { + s_gs_table[k - 1] = min(s_gs_table[k - 1], in_pat_len + q - k); + } + q1 = q + 1; q = q + t - aux[t - 1]; t = aux[t - 1]; } } + + if (aux) free(aux); return err; } @@ -1668,22 +1685,20 @@ void boyer_moore_done() { } -char *boyer_moore_search( char *in_text, long in_text_len ) { - long i, j, k, l; +char* boyer_moore_search(char* in_text, size_t in_text_len) { + size_t i, j; - for ( i = j = s_pat_len - 1; j < in_text_len && i >= 0; ) { - if ( in_text[ j ] == s_pattern[ i ] ) { --i; --j; } - else { - k = s_gs_table[ i + 1 ]; - l = s_bc_table[ (uint8_t) in_text[ j ] ]; + if (s_pat_len == 0) return in_text; - j += max( k, l ); - - i = s_pat_len - 1; + i = s_pat_len - 1; + while (i < in_text_len) { + for (j = s_pat_len - 1; in_text[i] == s_pattern[j]; --i, --j) { + if (j == 0) return in_text + i; } + + i += max(s_bc_table[(unsigned char)in_text[i]], s_gs_table[j]); } - - return i < 0 ? in_text + j + 1 : NULL; + return NULL; } From 1bc46b469b3fd4b526ba158f5d91f28ed60074da Mon Sep 17 00:00:00 2001 From: rapperskull Date: Mon, 4 Sep 2023 12:38:01 +0200 Subject: [PATCH 41/59] Fix multiple ISOs extraction (fixes XboxDev/extract-xiso#85) --- extract-xiso.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index d6ffe9d..e8b4764 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -1179,14 +1179,14 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat } if (!err && in_mode == k_extract) { + if ((cwd = getcwd(NULL, 0)) == NULL) mem_err(); if (in_path) { - if (strlen(in_path) == 0) misc_err("empty destination path"); - if (!err && (cwd = getcwd(NULL, 0)) == NULL) mem_err(); + if (!err && strlen(in_path) == 0) misc_err("empty destination path"); if (!err && mkdir(in_path, 0755) == -1) mkdir_err(in_path); if (!err && chdir(in_path) == -1) chdir_err(in_path); } else { - if (strlen(iso_name) == 0) misc_err("invalid xiso image name: %s", in_xiso); + if (!err && strlen(iso_name) == 0) misc_err("invalid xiso image name: %s", in_xiso); if (!err && mkdir(iso_name, 0755) == -1) mkdir_err(iso_name); if (!err && chdir(iso_name) == -1) chdir_err(iso_name); } From 779b0b69e6f306eabbb57437ce908bbd8765634b Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 3 Oct 2023 22:13:46 +0200 Subject: [PATCH 42/59] Remove unnecessary seek Fix file size test in verify_xiso() broken since 715d798 --- extract-xiso.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index e8b4764..edd0bfc 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -971,7 +971,7 @@ int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_ if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) ) misc_err( "%s appears to be corrupt", in_iso_name ); // seek to root directory sector - if (!err && lseek_with_error(in_xiso, (xoff_t)*out_root_dir_sector * XISO_SECTOR_SIZE, SEEK_SET) == -1) seek_err(); + if (!err && lseek_with_error(in_xiso, (xoff_t)*out_root_dir_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); return err; } @@ -1201,8 +1201,6 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat root_dir_start = (xoff_t)root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek; root_end_offset = (uint16_t)(n_sectors(root_dir_size) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE); - - if (!err && lseek_with_error(xiso, root_dir_start, SEEK_SET) == -1) seek_err(); if (in_mode == k_rewrite) { if (!err && root_dir_size == 0) root = NULL; From 63840743cb4d16fddffcb4090857a28d4fc542d2 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Wed, 4 Oct 2023 00:47:45 +0200 Subject: [PATCH 43/59] Fix Release CI Move to 'softprops/action-gh-release@v1' action Update 'actions/checkout' to v4 --- .github/workflows/CI.yml | 156 ++++++--------------------------------- 1 file changed, 23 insertions(+), 133 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index ac9ddf0..f3574c0 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -43,7 +43,7 @@ jobs: platform: x64 artifact_os: Win64 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CMake generate run: | mkdir build && cd build @@ -57,14 +57,14 @@ jobs: mv -vb build\${{ matrix.configuration }}\extract-xiso.exe, LICENSE.TXT artifacts - uses: actions/upload-artifact@v3 with: - name: extract-xiso_${{ matrix.artifact_os }}_${{ matrix.configuration }} + name: extract-xiso-${{ matrix.artifact_os }}-${{ matrix.configuration }} path: artifacts build-linux: runs-on: ubuntu-latest needs: Init steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CMake generate run: | mkdir build && cd build @@ -78,14 +78,14 @@ jobs: mv -v build/extract-xiso LICENSE.TXT artifacts - uses: actions/upload-artifact@v3 with: - name: extract-xiso_${{ runner.os }} + name: extract-xiso-linux path: artifacts build-macos: runs-on: macos-latest needs: Init steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: CMake generate run: | mkdir build && cd build @@ -99,7 +99,7 @@ jobs: mv -v build/extract-xiso LICENSE.TXT artifacts - uses: actions/upload-artifact@v3 with: - name: extract-xiso_${{ runner.os }} + name: extract-xiso-macos path: artifacts build-freebsd: @@ -108,7 +108,7 @@ jobs: env: SYSROOT_PATH: /opt/cross-freebsd-13 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: FreeBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ @@ -131,7 +131,7 @@ jobs: mv -v build/extract-xiso LICENSE.TXT artifacts - uses: actions/upload-artifact@v3 with: - name: extract-xiso_freebsd + name: extract-xiso-freebsd path: artifacts build-openbsd: @@ -140,7 +140,7 @@ jobs: env: SYSROOT_PATH: /opt/cross-openbsd-7 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: OpenBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ @@ -163,7 +163,7 @@ jobs: mv -v build/extract-xiso LICENSE.TXT artifacts - uses: actions/upload-artifact@v3 with: - name: extract-xiso_openbsd + name: extract-xiso-openbsd path: artifacts build-netbsd: @@ -172,7 +172,7 @@ jobs: env: SYSROOT_PATH: /opt/cross-netbsd-9 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: NetBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ @@ -195,15 +195,13 @@ jobs: mv -v build/extract-xiso LICENSE.TXT artifacts - uses: actions/upload-artifact@v3 with: - name: extract-xiso_netbsd + name: extract-xiso-netbsd path: artifacts Release: if: github.event_name == 'push' && github.ref == 'refs/heads/master' runs-on: ubuntu-latest needs: [build-windows, build-linux, build-macos, build-freebsd, build-openbsd, build-netbsd] - env: - BUILD_TAG: steps: - name: Download artifacts uses: actions/download-artifact@v3 @@ -211,133 +209,25 @@ jobs: path: dist - name: Create archives run: | - pushd dist/extract-xiso_Win32_Release - zip -r ../extract-xiso-win32-release.zip * - popd - pushd dist/extract-xiso_Win32_Debug - zip -r ../extract-xiso-win32-debug.zip * - popd - pushd dist/extract-xiso_Win64_Release - zip -r ../extract-xiso-win64-release.zip * - popd - pushd dist/extract-xiso_Win64_Debug - zip -r ../extract-xiso-win64-debug.zip * - popd - pushd dist/extract-xiso_linux - zip -r ../extract-xiso-linux.zip * - popd - pushd dist/extract-xiso_macOS - zip -r ../extract-xiso-macos.zip * - popd - pushd dist/extract-xiso_freebsd - zip -r ../extract-xiso-freebsd.zip * - popd - pushd dist/extract-xiso_openbsd - zip -r ../extract-xiso-openbsd.zip * - popd - pushd dist/extract-xiso_netbsd - zip -r ../extract-xiso-netbsd.zip * - popd + for dir in dist/extract-xiso-*/ + do + pushd ${dir} + zip_file="../$(basename ${dir} | tr '[:upper:]' '[:lower:]').zip" + echo "Create ${zip_file}" + zip -r ${zip_file} * + popd + done - name: Get package info run: | echo "BUILD_TAG=$(cat dist/tag/tag)" >> $GITHUB_ENV - name: Create release id: create_release - uses: actions/create-release@v1 + uses: softprops/action-gh-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ env.BUILD_TAG }} - release_name: ${{ env.BUILD_TAG }} draft: false prerelease: false - - name: Upload release assets (Win32 build) - id: upload-release-assets-win32-release - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_name: extract-xiso-win32-release.zip - asset_path: dist/extract-xiso-win32-release.zip - asset_content_type: application/zip - - name: Upload release assets (Win32 debug build) - id: upload-release-assets-win32-debug - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_name: extract-xiso-win32-debug.zip - asset_path: dist/extract-xiso-win32-debug.zip - asset_content_type: application/zip - - name: Upload release assets (Win64 build) - id: upload-release-assets-win64-release - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_name: extract-xiso-win64-release.zip - asset_path: dist/extract-xiso-win64-release.zip - asset_content_type: application/zip - - name: Upload release assets (Win64 debug build) - id: upload-release-assets-win64-debug - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_name: extract-xiso-win64-debug.zip - asset_path: dist/extract-xiso-win64-debug.zip - asset_content_type: application/zip - - name: Upload release assets (Linux build) - id: upload-release-assets-linux-release - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_name: extract-xiso-linux.zip - asset_path: dist/extract-xiso-linux.zip - asset_content_type: application/zip - - name: Upload release assets (macOS build) - id: upload-release-assets-macos-release - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_name: extract-xiso-macos.zip - asset_path: dist/extract-xiso-macos.zip - asset_content_type: application/zip - - name: Upload release assets (FreeBSD build) - id: upload-release-assets-freebsd-release - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_name: extract-xiso-freebsd.zip - asset_path: dist/extract-xiso-freebsd.zip - asset_content_type: application/zip - - name: Upload release assets (OpenBSD build) - id: upload-release-assets-openbsd-release - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_name: extract-xiso-openbsd.zip - asset_path: dist/extract-xiso-openbsd.zip - asset_content_type: application/zip - - name: Upload release assets (NetBSD build) - id: upload-release-assets-netbsd-release - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_name: extract-xiso-netbsd.zip - asset_path: dist/extract-xiso-netbsd.zip - asset_content_type: application/zip + fail_on_unmatched_files: true + files: dist/*.zip From 83f5901194f90288fc38004aa226b65307fd3e54 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 27 Feb 2024 18:58:13 +0100 Subject: [PATCH 44/59] Properly convert CP1252 filenames to uppercase Replace invalid CP1252 characters with question mark --- cp1252/cp1252.c | 19 ++++++++++++++++++- extract-xiso.c | 7 ++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/cp1252/cp1252.c b/cp1252/cp1252.c index a6d8659..339542d 100644 --- a/cp1252/cp1252.c +++ b/cp1252/cp1252.c @@ -15,6 +15,7 @@ size_t strcplen(const char* buf, bool utf8); const char* getCodePointFromUTF8Sequence(const char* buf, uint32_t* out); char* getUTF8String(const char* input); char* getCP1252String(const char* input); +char toupperCP1252(char c); uint32_t getUnicodeFromCP1252(char input) { switch ((unsigned char)input) { @@ -144,7 +145,7 @@ char getCP1252FromUnicode(uint32_t input) { return (char)input; } else { - return '\x20'; // SPACE + return '\x3F'; // QUESTION MARK } } } @@ -274,4 +275,20 @@ char* getCP1252String(const char* input) { return ret; } +char toupperCP1252(char c) { + if (c >= 'a' && c <= 'z') { + c -= 32; + } + else if (c == '\x9A' || c == '\x9C' || c == '\x9E') { + c -= 16; + } + else if ((c >= '\xE0' && c <= '\xF6') || (c >= '\xF8' && c <= '\xFE')) { + c -= 32; + } + else if (c == '\xFF') { + c = '\x9F'; + } + return c; +} + #endif //CP1252_INCLUDED diff --git a/extract-xiso.c b/extract-xiso.c index edd0bfc..2b1f3a6 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -1568,11 +1568,8 @@ int avl_compare_key( const char *in_lhs, const char *in_rhs ) { unsigned char a, b; for ( ;; ) { - a = (unsigned char)*in_lhs++; - b = (unsigned char)*in_rhs++; - - if ( a >= 'a' && a <= 'z' ) a -= 32; // uppercase(a); - if ( b >= 'a' && b <= 'z' ) b -= 32; // uppercase(b); + a = (unsigned char)toupperCP1252(*in_lhs++); + b = (unsigned char)toupperCP1252(*in_rhs++); if ( a ) { if ( b ) { From 4ce46e3f815e5eb2991c4d8f960f504b21a1ec50 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 27 Feb 2024 19:10:43 +0100 Subject: [PATCH 45/59] Fix CI build by updating FreeBSD to 13.2 and OpenBSD to 7.4 --- .github/workflows/CI.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index f3574c0..c306e2e 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -112,7 +112,7 @@ jobs: - name: FreeBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ - wget -nv http://ftp.plusline.de/FreeBSD/releases/amd64/13.1-RELEASE/base.txz && \ + wget -nv http://ftp.plusline.de/FreeBSD/releases/amd64/13.2-RELEASE/base.txz && \ mkdir -p $SYSROOT_PATH && cd $SYSROOT_PATH && \ tar -xf /tmp/base.txz ./lib/ ./usr/lib/ ./usr/include/ && \ cd $SYSROOT_PATH/usr/lib && \ @@ -144,12 +144,12 @@ jobs: - name: OpenBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ - wget -nv https://cdn.openbsd.org/pub/OpenBSD/7.2/amd64/base72.tgz \ - https://cdn.openbsd.org/pub/OpenBSD/7.2/amd64/comp72.tgz && \ + wget -nv https://cdn.openbsd.org/pub/OpenBSD/7.4/amd64/base74.tgz \ + https://cdn.openbsd.org/pub/OpenBSD/7.4/amd64/comp74.tgz && \ mkdir -p $SYSROOT_PATH && cd $SYSROOT_PATH && \ - tar -xf /tmp/base72.tgz ./usr/lib/ ./usr/include/ && \ - tar -xf /tmp/comp72.tgz ./usr/lib/ ./usr/include/ && \ - rm -f /tmp/base72.tgz /tmp/comp72.tgz + tar -xf /tmp/base74.tgz ./usr/lib/ ./usr/include/ && \ + tar -xf /tmp/comp74.tgz ./usr/lib/ ./usr/include/ && \ + rm -f /tmp/base74.tgz /tmp/comp74.tgz - name: CMake generate run: | mkdir build && cd build From bca856c639d936e40bd49ecc7ba3498cce3f67f3 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 27 Feb 2024 19:23:00 +0100 Subject: [PATCH 46/59] Update upload-artifact and download-artifact to v4 --- .github/workflows/CI.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c306e2e..3b13d94 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -20,7 +20,7 @@ jobs: echo "BUILD_TAG=$BUILD_TAG" >> $GITHUB_ENV echo -n $BUILD_TAG > tag - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: tag path: tag @@ -55,7 +55,7 @@ jobs: run: | mkdir artifacts mv -vb build\${{ matrix.configuration }}\extract-xiso.exe, LICENSE.TXT artifacts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: extract-xiso-${{ matrix.artifact_os }}-${{ matrix.configuration }} path: artifacts @@ -76,7 +76,7 @@ jobs: run: | mkdir artifacts mv -v build/extract-xiso LICENSE.TXT artifacts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: extract-xiso-linux path: artifacts @@ -97,7 +97,7 @@ jobs: run: | mkdir artifacts mv -v build/extract-xiso LICENSE.TXT artifacts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: extract-xiso-macos path: artifacts @@ -129,7 +129,7 @@ jobs: run: | mkdir artifacts mv -v build/extract-xiso LICENSE.TXT artifacts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: extract-xiso-freebsd path: artifacts @@ -161,7 +161,7 @@ jobs: run: | mkdir artifacts mv -v build/extract-xiso LICENSE.TXT artifacts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: extract-xiso-openbsd path: artifacts @@ -193,7 +193,7 @@ jobs: run: | mkdir artifacts mv -v build/extract-xiso LICENSE.TXT artifacts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: extract-xiso-netbsd path: artifacts @@ -204,7 +204,7 @@ jobs: needs: [build-windows, build-linux, build-macos, build-freebsd, build-openbsd, build-netbsd] steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: dist - name: Create archives From 6113b15fe919ecd6fd0cd5a6d8167318f025a22b Mon Sep 17 00:00:00 2001 From: rapperskull Date: Wed, 28 Feb 2024 00:14:07 +0100 Subject: [PATCH 47/59] Allow the path to file to include symlinks Symlinks are not followed below the root, to avoid potential recursions Windows is an exception, since we don't have an 'lstat' equivalent --- extract-xiso.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 2b1f3a6..a73985b 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -352,6 +352,7 @@ #define lseek _lseeki64 #define mkdir(a, b) _mkdir(a) #define stat _stat64 + #define lstat _stat64 #define realpath(a, b) _fullpath(b, a, _MAX_PATH) #define bswap_16(x) _byteswap_ushort(x) @@ -986,35 +987,39 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n write_tree_context wt_context = { 0 }; uint32_t start_sector = 0; int i = 0, n = 0, xiso = -1, err = 0; - char *cwd = NULL, *iso_name = NULL, *xiso_path = NULL, *iso_dir = NULL, *real_path = NULL; + char *cwd = NULL, *iso_name = NULL, *xiso_path = NULL, *iso_dir = NULL, *real_path = NULL, *in_dir_path = NULL; s_total_bytes = s_total_files = 0; if ( ( cwd = getcwd( NULL, 0 ) ) == NULL ) mem_err(); - if ( ! err ) { - if ( ! in_root ) { - i = (int)strlen(in_root_directory) - 1; - if ( in_root_directory[i] == '/' || in_root_directory[i] == '\\' ) in_root_directory[i] = 0; - if ((iso_dir = strrchr(in_root_directory, PATH_CHAR))) iso_dir++; - else iso_dir = in_root_directory; - - iso_name = in_name ? in_name : iso_dir; - } else { + if (!err) { + if (!in_root) { + if ((in_dir_path = realpath(in_root_directory, NULL)) == NULL) misc_err("unable to get absolute path of %s: %s", in_root_directory, strerror(errno)); + if (!err) { + // Remember not to free in_dir_path until iso_dir is not needed anymore + if ((iso_dir = strrchr(in_dir_path, PATH_CHAR)) != NULL) iso_dir++; + else iso_dir = in_dir_path; + iso_name = in_name ? in_name : iso_dir; + } + } + else { iso_dir = iso_name = in_root_directory; } } - if ( ! err ) { - if ( ! *iso_dir ) iso_dir = PATH_CHAR_STR; - if ( ! iso_name || ! *iso_name ) iso_name = "root"; - else if ( iso_name[ 1 ] == ':' ) { iso_name[ 1 ] = iso_name[ 0 ]; ++iso_name; } - if (!err && (real_path = realpath(in_output_directory ? in_output_directory : ".", NULL)) == NULL) misc_err("unable to get absolute path of %s: %s", real_path, strerror(errno)); + if(!err) { + if (!iso_dir || !*iso_dir) iso_dir = PATH_CHAR_STR; + if (!iso_name || !*iso_name) iso_name = "root"; + else if (iso_name[1] == ':') { iso_name[1] = iso_name[0]; ++iso_name; } + + if (in_output_directory == NULL) in_output_directory = "."; + if (!err && (real_path = realpath(in_output_directory, NULL)) == NULL) misc_err("unable to get absolute path of %s: %s", in_output_directory, strerror(errno)); if (!err && (asprintf(&xiso_path, "%s%c%s%s", real_path, PATH_CHAR, iso_name, in_name ? "" : ".iso")) == -1) mem_err(); if (real_path) { free(real_path); real_path = NULL; } - if (!err && !in_root && chdir(in_root_directory) == -1) chdir_err(in_root_directory); + if (!err && !in_root && chdir(in_dir_path) == -1) chdir_err(in_dir_path); } if ( ! err ) { exiso_log( "\n%s %s%s:\n", in_root ? "rewriting" : "creating", iso_name, in_name ? "" : ".iso" ); @@ -1090,7 +1095,7 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if ( ! err && write( xiso, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) write_err(); if ( ! err && ! in_root ) { - if ( chdir( ".." ) == -1 ) chdir_err( ".." ); + if (chdir("..") == -1) chdir_err(".."); } if (!err && (root.filename = strdup(iso_dir)) == NULL) mem_err(); if (!err) { @@ -1138,6 +1143,11 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n if (root.filename) free(root.filename); if (root.filename_cp1252) free(root.filename_cp1252); + if (in_dir_path) { + free(in_dir_path); + in_dir_path = NULL; + } + if ( cwd ) { if ( chdir( cwd ) == -1 ) chdir_err( cwd ); free( cwd ); @@ -2032,7 +2042,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { avl->filename = NULL; } else if ((avl->filename_cp1252 = getCP1252String(p->d_name)) == NULL) mem_err(); } - if ( ! err && stat( p->d_name, &sb ) == -1 ) read_err(); + if ( ! err && lstat( p->d_name, &sb ) == -1 ) read_err(); if ( ! err ) { if ( S_ISDIR( sb.st_mode ) ) { empty_dir = false; From 233478523df169959550e95ebd5fcc0578671865 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Wed, 28 Feb 2024 23:43:19 +0100 Subject: [PATCH 48/59] Replace getopt and aspritf implementations The new code is licensed under BSD --- .gitmodules | 6 ++ CMakeLists.txt | 26 ++++++ deps/asprintf | 1 + deps/getopt_port | 1 + extract-xiso.c | 5 +- win32/asprintf.c | 79 ---------------- win32/getopt.c | 233 ----------------------------------------------- 7 files changed, 37 insertions(+), 314 deletions(-) create mode 100644 .gitmodules create mode 160000 deps/asprintf create mode 160000 deps/getopt_port delete mode 100644 win32/asprintf.c delete mode 100644 win32/getopt.c diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c273dc2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "deps/getopt_port"] + path = deps/getopt_port + url = https://github.com/kimgr/getopt_port.git +[submodule "deps/asprintf"] + path = deps/asprintf + url = https://github.com/eiszapfen2000/asprintf.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 618a7e2..521a39f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,10 @@ set(SOURCE_FILES extract-xiso.c ) +set(DEPS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps) +set(GETOPT_DIR ${DEPS_DIR}/getopt_port) +set(ASPRINTF_DIR ${DEPS_DIR}/asprintf) + if(MSVC) set(CMAKE_C_FLAGS_RELEASE_INIT "/O2") add_compile_options(/W4 /utf-8) @@ -21,6 +25,7 @@ else() set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG") add_compile_options(-Wall -Wextra -Wpedantic -Wno-comment) endif() + add_executable(extract-xiso ${SOURCE_FILES}) target_compile_definitions(extract-xiso PRIVATE ${TARGET_OS}) if(CMAKE_C_BYTE_ORDER MATCHES "^$") @@ -29,4 +34,25 @@ endif() target_compile_definitions(extract-xiso PRIVATE CMAKE_ENDIANNESS=${CMAKE_C_BYTE_ORDER}) set_property(TARGET extract-xiso PROPERTY C_STANDARD 99) set_property(TARGET extract-xiso PROPERTY C_EXTENSIONS OFF) + +if(WIN32) + add_library(getopt STATIC ${GETOPT_DIR}/getopt.c) + target_sources(getopt PUBLIC ${GETOPT_DIR}/getopt.h) + target_include_directories(getopt PUBLIC ${GETOPT_DIR}) + set_property(TARGET getopt PROPERTY C_STANDARD 99) + set_property(TARGET getopt PROPERTY C_EXTENSIONS OFF) + + target_link_libraries(extract-xiso getopt) +endif() + +if(MSVC) + add_library(asprintf STATIC ${ASPRINTF_DIR}/asprintf.c) + target_sources(asprintf PUBLIC ${ASPRINTF_DIR}/asprintf.h) + target_include_directories(asprintf PUBLIC ${ASPRINTF_DIR}) + set_property(TARGET asprintf PROPERTY C_STANDARD 99) + set_property(TARGET asprintf PROPERTY C_EXTENSIONS OFF) + + target_link_libraries(extract-xiso asprintf) +endif() + install(TARGETS extract-xiso RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/deps/asprintf b/deps/asprintf new file mode 160000 index 0000000..29fe98d --- /dev/null +++ b/deps/asprintf @@ -0,0 +1 @@ +Subproject commit 29fe98d242377e27b20e2d64f6161a466ec6b806 diff --git a/deps/getopt_port b/deps/getopt_port new file mode 160000 index 0000000..6ad8cc1 --- /dev/null +++ b/deps/getopt_port @@ -0,0 +1 @@ +Subproject commit 6ad8cc105b55ad9f83136129fd0c6c2a209da43e diff --git a/extract-xiso.c b/extract-xiso.c index a73985b..cdaea0e 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -281,9 +281,10 @@ #endif #if defined(_WIN32) + #include #include #include "win32/dirent.c" - #include "win32/getopt.c" + #include /* Provided by CMake */ #else #include #include @@ -291,7 +292,7 @@ #endif #if defined(_MSC_VER) - #include "win32/asprintf.c" + #include /* Provided by CMake */ #include #else #include diff --git a/win32/asprintf.c b/win32/asprintf.c deleted file mode 100644 index 98df5a9..0000000 --- a/win32/asprintf.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2001 Federico Di Gregorio - * Copyright (C) 1991, 1994-1999, 2000, 2001 Free Software Foundation, Inc. - * - * This code has been derived from an example in the glibc2 documentation. - * This file is part of the psycopg module. - * - * This program 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 2, - * or (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * asprintf.c -- asprintf() implementation for braindamaged operating systems - */ - -#ifndef _WIN32 -#include -#endif -#include -#include -#ifndef _WIN32 -#include -#endif -#include - -#ifdef _WIN32 -#define vsnprintf _vsnprintf -#endif - -int asprintf(char **buffer, char *fmt, ...); -int asprintf(char **buffer, char *fmt, ...) -{ - /* Guess we need no more than 200 chars of space. */ - int size = 200; - int nchars; - va_list ap; - - *buffer = (char*)malloc(size); - if (*buffer == NULL) return -1; - - /* Try to print in the allocated space. */ - va_start(ap, fmt); - nchars = vsnprintf(*buffer, size, fmt, ap); - va_end(ap); - - if (nchars >= size) - { - char *tmpbuff; - /* Reallocate buffer now that we know how much space is needed. */ - size = nchars+1; - tmpbuff = (char*)realloc(*buffer, size); - - - if (tmpbuff == NULL) { /* we need to free it*/ - free(*buffer); - return -1; - } - - *buffer=tmpbuff; - /* Try again. */ - va_start(ap, fmt); - nchars = vsnprintf(*buffer, size, fmt, ap); - va_end(ap); - } - - if (nchars < 0) return nchars; - return size; -} diff --git a/win32/getopt.c b/win32/getopt.c deleted file mode 100644 index e09dba3..0000000 --- a/win32/getopt.c +++ /dev/null @@ -1,233 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2003 The Apache Software Foundation. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifdef _WIN32 - -#include -#include -#include -#include - -#define OPTERRCOLON (1) -#define OPTERRNF (2) -#define OPTERRARG (3) - -char *optarg; -int optreset = 0; -int optind = 1; -int opterr = 1; -int optopt; - -static int -optiserr(int argc, char * const *argv, int oint, const char *optstr, - int optchr, int err) -{ - (void)argc; - (void)optstr; - - if(opterr) - { - fprintf(stderr, "Error in argument %d, char %d: ", oint, optchr+1); - switch(err) - { - case OPTERRCOLON: - fprintf(stderr, ": in flags\n"); - break; - case OPTERRNF: - fprintf(stderr, "option not found %c\n", argv[oint][optchr]); - break; - case OPTERRARG: - fprintf(stderr, "no argument for option %c\n", argv[oint][optchr]); - break; - default: - fprintf(stderr, "unknown\n"); - break; - } - } - optopt = argv[oint][optchr]; - return('?'); -} - - -int getopt(int argc, char* const *argv, const char *optstr); -int getopt(int argc, char* const *argv, const char *optstr) -{ - static int optchr = 0; - static int dash = 0; /* have already seen the - */ - - char *cp; - - if (optreset) - optreset = optchr = dash = 0; - if(optind >= argc) - return(EOF); - if(!dash && (argv[optind][0] != '-')) - return(EOF); - if(!dash && (argv[optind][0] == '-') && !argv[optind][1]) - { - /* - * use to specify stdin. Need to let pgm process this and - * the following args - */ - return(EOF); - } - if((argv[optind][0] == '-') && (argv[optind][1] == '-')) - { - /* -- indicates end of args */ - optind++; - return(EOF); - } - if(!dash) - { - assert((argv[optind][0] == '-') && argv[optind][1]); - dash = 1; - optchr = 1; - } - - /* Check if the guy tries to do a -: kind of flag */ - assert(dash); - if(argv[optind][optchr] == ':') - { - dash = 0; - optind++; - return(optiserr(argc, argv, optind-1, optstr, optchr, OPTERRCOLON)); - } - if(!(cp = strchr(optstr, argv[optind][optchr]))) - { - int errind = optind; - int errchr = optchr; - - if(!argv[optind][optchr+1]) - { - dash = 0; - optind++; - } - else - optchr++; - return(optiserr(argc, argv, errind, optstr, errchr, OPTERRNF)); - } - if(cp[1] == ':') - { - dash = 0; - optind++; - if(optind == argc) - return(optiserr(argc, argv, optind-1, optstr, optchr, OPTERRARG)); - optarg = argv[optind++]; - return(*cp); - } - else - { - if(!argv[optind][optchr+1]) - { - dash = 0; - optind++; - } - else - optchr++; - return(*cp); - } - assert(0); - return(0); -} - -#ifdef TESTGETOPT -int - main (int argc, char **argv) - { - int c; - extern char *optarg; - extern int optind; - int aflg = 0; - int bflg = 0; - int errflg = 0; - char *ofile = NULL; - - while ((c = getopt(argc, argv, "abo:")) != EOF) - switch (c) { - case 'a': - if (bflg) - errflg++; - else - aflg++; - break; - case 'b': - if (aflg) - errflg++; - else - bflg++; - break; - case 'o': - ofile = optarg; - (void)printf("ofile = %s\n", ofile); - break; - case '?': - errflg++; - } - if (errflg) { - (void)fprintf(stderr, - "usage: cmd [-a|-b] [-o ] files...\n"); - exit (2); - } - for ( ; optind < argc; optind++) - (void)printf("%s\n", argv[optind]); - return 0; - } - -#endif /* TESTGETOPT */ - -#endif /* WIN32 */ From 1d92f4fa7d8b5ff09ba535b23a522583088f58ba Mon Sep 17 00:00:00 2001 From: rapperskull Date: Wed, 28 Feb 2024 23:52:33 +0100 Subject: [PATCH 49/59] Fix CI by checking out submodules --- .github/workflows/CI.yml | 12 ++++++++++++ appveyor.yml | 1 + 2 files changed, 13 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 3b13d94..de11ee0 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,6 +44,8 @@ jobs: artifact_os: Win64 steps: - uses: actions/checkout@v4 + with: + submodules: 'true' - name: CMake generate run: | mkdir build && cd build @@ -65,6 +67,8 @@ jobs: needs: Init steps: - uses: actions/checkout@v4 + with: + submodules: 'true' - name: CMake generate run: | mkdir build && cd build @@ -86,6 +90,8 @@ jobs: needs: Init steps: - uses: actions/checkout@v4 + with: + submodules: 'true' - name: CMake generate run: | mkdir build && cd build @@ -109,6 +115,8 @@ jobs: SYSROOT_PATH: /opt/cross-freebsd-13 steps: - uses: actions/checkout@v4 + with: + submodules: 'true' - name: FreeBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ @@ -141,6 +149,8 @@ jobs: SYSROOT_PATH: /opt/cross-openbsd-7 steps: - uses: actions/checkout@v4 + with: + submodules: 'true' - name: OpenBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ @@ -173,6 +183,8 @@ jobs: SYSROOT_PATH: /opt/cross-netbsd-9 steps: - uses: actions/checkout@v4 + with: + submodules: 'true' - name: NetBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ diff --git a/appveyor.yml b/appveyor.yml index 95f84d0..1ee6037 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,7 @@ configuration: - Release before_build: - cmd: |- + git submodule update --init --recursive mkdir build cd build cmake .. -G "Visual Studio 17 2022" From 59bfde6c0a2d0c225016950fb80011f4e4d41d61 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Thu, 29 Feb 2024 23:22:16 +0100 Subject: [PATCH 50/59] Replace dirent implementation with one capable of detecting symlinks Now symlinks are skipped on Windows too --- .gitmodules | 3 + CMakeLists.txt | 6 ++ deps/dirent | 1 + extract-xiso.c | 79 +++++++++++++++----- win32/dirent.c | 195 ------------------------------------------------- 5 files changed, 70 insertions(+), 214 deletions(-) create mode 160000 deps/dirent delete mode 100644 win32/dirent.c diff --git a/.gitmodules b/.gitmodules index c273dc2..0be85d0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "deps/asprintf"] path = deps/asprintf url = https://github.com/eiszapfen2000/asprintf.git +[submodule "deps/dirent"] + path = deps/dirent + url = https://github.com/tronkko/dirent.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 521a39f..d521dbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCE_FILES ) set(DEPS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps) +set(DIRENT_DIR ${DEPS_DIR}/dirent) set(GETOPT_DIR ${DEPS_DIR}/getopt_port) set(ASPRINTF_DIR ${DEPS_DIR}/asprintf) @@ -36,6 +37,11 @@ set_property(TARGET extract-xiso PROPERTY C_STANDARD 99) set_property(TARGET extract-xiso PROPERTY C_EXTENSIONS OFF) if(WIN32) + add_library(dirent INTERFACE) + target_include_directories(dirent INTERFACE ${DIRENT_DIR}/include) + + target_link_libraries(extract-xiso dirent) + add_library(getopt STATIC ${GETOPT_DIR}/getopt.c) target_sources(getopt PUBLIC ${GETOPT_DIR}/getopt.h) target_include_directories(getopt PUBLIC ${GETOPT_DIR}) diff --git a/deps/dirent b/deps/dirent new file mode 160000 index 0000000..57ff230 --- /dev/null +++ b/deps/dirent @@ -0,0 +1 @@ +Subproject commit 57ff23098eca49db016b8f66a12d31713f1c45d5 diff --git a/extract-xiso.c b/extract-xiso.c index cdaea0e..c5711ba 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -242,24 +242,14 @@ #if defined(__GNUC__) #define _GNU_SOURCE - #define unused __attribute__((__unused__)) #elif defined(_MSC_VER) #pragma warning(disable: 4706) // C4706: assignment within conditional expression - #define unused __pragma(warning(suppress:4100)) /* This unfortunately disables the warning for the whole line and the next one */ -#else - #define unused #endif #ifndef DEBUG #define DEBUG 0 #endif -#if DEBUG - #define unused_release -#else - #define unused_release unused -#endif - #include #include #include @@ -272,6 +262,7 @@ #include #include #include +#include /* Provided by CMake on Windows */ #include #include #include "cp1252/cp1252.c" @@ -283,10 +274,8 @@ #if defined(_WIN32) #include #include - #include "win32/dirent.c" #include /* Provided by CMake */ #else - #include #include #include #endif @@ -337,9 +326,6 @@ #define exiso_target "Windows" #if defined(_MSC_VER) - #define S_ISDIR(x) ((x) & _S_IFDIR) - #define S_ISREG(x) ((x) & _S_IFREG) - typedef SSIZE_T ssize_t; #define strcasecmp _stricmp #define strncasecmp _strnicmp @@ -353,7 +339,6 @@ #define lseek _lseeki64 #define mkdir(a, b) _mkdir(a) #define stat _stat64 - #define lstat _stat64 #define realpath(a, b) _fullpath(b, a, _MAX_PATH) #define bswap_16(x) _byteswap_ushort(x) @@ -425,6 +410,21 @@ typedef int64_t file_time_t; #define max(a, b) ( (a) > (b) ? (a) : (b) ) #endif +/* These definitions need to be after all the includes */ +#if defined(__GNUC__) + #define unused __attribute__((__unused__)) +#elif defined(_MSC_VER) + #define unused __pragma(warning(suppress:4100)) /* This unfortunately disables the warning for the whole line and the next one */ +#else + #define unused +#endif + +#if DEBUG + #define unused_release +#else + #define unused_release unused +#endif + #define exiso_version "2.7.1 (01.11.14)" #define VERSION_LENGTH 16 @@ -619,6 +619,9 @@ int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_context, int int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io_context, int in_depth ); int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ); +static int is_lnk_lstat(struct dirent* p, bool* lnk); +static int is_lnk(struct dirent* p, bool* lnk); + #if DEBUG void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char *in_extension ); #endif @@ -2014,6 +2017,41 @@ int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, int in_d return 0; } +static int is_lnk_lstat(struct dirent* p, bool* lnk) { + if (p == NULL || lnk == NULL) { + errno = EFAULT; + return -1; + } +#if !defined(_WIN32) + struct stat sb = { 0 }; + if (lstat(p->d_name, &sb) == -1) { + return -1; + } + *lnk = S_ISLNK(sb.st_mode); +#else + *lnk = false; +#endif // _WIN32 + return 0; +} + +static int is_lnk(struct dirent* p, bool* lnk) { + if (p == NULL || lnk == NULL) { + errno = EFAULT; + return -1; + } +#if defined(_DIRENT_HAVE_D_TYPE) + if (p->d_type == DT_UNKNOWN) { + return is_lnk_lstat(p, lnk); + } + else { + *lnk = (p->d_type == DT_LNK); + return 0; + } +#else + return is_lnk_lstat(p, lnk); +#endif // _DIRENT_HAVE_D_TYPE +} + int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { struct dirent *p = NULL; @@ -2021,7 +2059,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { dir_node_avl *avl = NULL; DIR *dir = NULL; int err = 0, i = 0, j = 0; - bool empty_dir = true; + bool empty_dir = true, lnk; if ( ( dir = opendir( "." ) ) == NULL ) mem_err(); @@ -2034,8 +2072,11 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { for ( j = i; j < *io_n; ++j ) exiso_log( "\b" ); *io_n = i; flush(); + + if (is_lnk(p, &lnk) == -1) read_err(); + else if (lnk) continue; - if ( ( avl = (dir_node_avl *) calloc( 1, sizeof(dir_node_avl) ) ) == NULL ) mem_err(); + if (!err && ( avl = (dir_node_avl *) calloc( 1, sizeof(dir_node_avl) ) ) == NULL ) mem_err(); if (!err && (avl->filename = strdup(p->d_name)) == NULL) mem_err(); if (!err) { if (s_cp1252) { @@ -2043,7 +2084,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { avl->filename = NULL; } else if ((avl->filename_cp1252 = getCP1252String(p->d_name)) == NULL) mem_err(); } - if ( ! err && lstat( p->d_name, &sb ) == -1 ) read_err(); + if ( ! err && stat( p->d_name, &sb ) == -1 ) read_err(); if ( ! err ) { if ( S_ISDIR( sb.st_mode ) ) { empty_dir = false; diff --git a/win32/dirent.c b/win32/dirent.c deleted file mode 100644 index 7accefc..0000000 --- a/win32/dirent.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - - Implementation of POSIX directory browsing functions and types for Win32. - - Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) - History: Created March 1997. Updated June 2003. - Rights: See end of file. - -*/ - -#ifndef DIRENT_INCLUDED -#define DIRENT_INCLUDED - -/* - - Declaration of POSIX directory browsing functions and types for Win32. - - Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) - History: Created March 1997. Updated June 2003. - Rights: See end of file. - -*/ - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef struct DIR DIR; - -struct dirent -{ - char *d_name; -}; - -DIR *opendir(const char *); -int closedir(DIR *); -struct dirent *readdir(DIR *); -void rewinddir(DIR *); - -/* - - Copyright Kevlin Henney, 1997, 2003. All rights reserved. - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that this copyright and permissions notice appear in all copies and - derivatives. - - This software is supplied "as is" without express or implied warranty. - - But that said, if there are any problems please get in touch. - -*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#include -#include /* _findfirst and _findnext set errno iff they return -1 */ -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -struct DIR -{ - intptr_t handle; /* -1 for failed rewind */ - struct _finddata_t info; - struct dirent result; /* d_name null iff first time */ - char *name; /* null-terminated char string */ -}; - -DIR *opendir(const char *name) -{ - DIR *dir = 0; - - if(name && name[0]) - { - size_t base_length = strlen(name); - const char *all = /* search pattern must end with suitable wildcard */ - strchr("/\\", name[base_length - 1]) ? "*" : "/*"; - - if((dir = (DIR *) malloc(sizeof *dir)) != 0 && - (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) - { - strcat(strcpy(dir->name, name), all); - - if((dir->handle = _findfirst(dir->name, &dir->info)) != -1) - { - dir->result.d_name = 0; - } - else /* rollback */ - { - free(dir->name); - free(dir); - dir = 0; - } - } - else /* rollback */ - { - free(dir); - dir = 0; - errno = ENOMEM; - } - } - else - { - errno = EINVAL; - } - - return dir; -} - -int closedir(DIR *dir) -{ - int result = -1; - - if(dir) - { - if(dir->handle != -1) - { - result = _findclose(dir->handle); - } - - free(dir->name); - free(dir); - } - - if(result == -1) /* map all errors to EBADF */ - { - errno = EBADF; - } - - return result; -} - -struct dirent *readdir(DIR *dir) -{ - struct dirent *result = 0; - - if(dir && dir->handle != -1) - { - if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) - { - result = &dir->result; - result->d_name = dir->info.name; - } - } - else - { - errno = EBADF; - } - - return result; -} - -void rewinddir(DIR *dir) -{ - if(dir && dir->handle != -1) - { - _findclose(dir->handle); - dir->handle = _findfirst(dir->name, &dir->info); - dir->result.d_name = 0; - } - else - { - errno = EBADF; - } -} - -#ifdef __cplusplus -} -#endif - -/* - - Copyright Kevlin Henney, 1997, 2003. All rights reserved. - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that this copyright and permissions notice appear in all copies and - derivatives. - - This software is supplied "as is" without express or implied warranty. - - But that said, if there are any problems please get in touch. - -*/ From 9a0f38c8912db3cc75fe57256f77c033bf46c4bd Mon Sep 17 00:00:00 2001 From: rapperskull Date: Fri, 1 Mar 2024 00:29:13 +0100 Subject: [PATCH 51/59] Include the licenses of our dependencies in the Windows release --- .github/workflows/CI.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index de11ee0..481f09d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -53,10 +53,18 @@ jobs: - name: Build working-directory: build run: cmake --build . --config ${{ matrix.configuration }} -j $env:NUMBER_OF_PROCESSORS + - name: Copy licenses + run: | + mkdir LICENSES + for /D %%x in (deps/*) do ( + mkdir LICENSES\%%x + copy deps\%%x\LICENSE* LICENSES\%%x + ) + shell: cmd - name: Prepare artifacts run: | mkdir artifacts - mv -vb build\${{ matrix.configuration }}\extract-xiso.exe, LICENSE.TXT artifacts + mv -vb build\${{ matrix.configuration }}\extract-xiso.exe, LICENSE.TXT, LICENSES artifacts - uses: actions/upload-artifact@v4 with: name: extract-xiso-${{ matrix.artifact_os }}-${{ matrix.configuration }} From 21fe68f8cdc02025338f9a3de2a3079208d50445 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sat, 2 Mar 2024 17:45:01 +0100 Subject: [PATCH 52/59] Make all functions static Remove unused defines --- extract-xiso.c | 148 ++++++++++++++++++++++++------------------------- 1 file changed, 71 insertions(+), 77 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index c5711ba..cbf4c99 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -440,15 +440,10 @@ typedef int64_t file_time_t; #define read_err() do{ log_err( __FILE__, __LINE__, "read error: %s", strerror( errno ) ); err = 1; } while(0) #define seek_err() do{ log_err( __FILE__, __LINE__, "seek error: %s", strerror( errno ) ); err = 1; } while(0) #define write_err() do{ log_err( __FILE__, __LINE__, "write error: %s", strerror( errno ) ); err = 1; } while(0) -#define rread_err() do{ log_err( __FILE__, __LINE__, "unable to read remote file" ); err = 1; } while(0) -#define rwrite_err() do{ log_err( __FILE__, __LINE__, "unable to write to remote file" ); err = 1; } while(0) #define unknown_err() do{ log_err( __FILE__, __LINE__, "an unrecoverable error has occurred" ); err = 1; } while(0) #define open_err( in_file ) do{ log_err( __FILE__, __LINE__, "open error: %s %s", ( in_file ), strerror( errno ) ); err = 1; } while(0) #define chdir_err( in_dir ) do{ log_err( __FILE__, __LINE__, "unable to change to directory %s: %s", ( in_dir ), strerror( errno ) ); err = 1; } while(0) #define mkdir_err( in_dir ) do{ log_err( __FILE__, __LINE__, "unable to create directory %s: %s", ( in_dir ), strerror( errno ) ); err = 1; } while(0) -#define ropen_err( in_file ) do{ log_err( __FILE__, __LINE__, "unable to open remote file %s", ( in_file ) ); err = 1; } while(0) -#define rchdir_err( in_dir ) do{ log_err( __FILE__, __LINE__, "unable to change to remote directory %s", ( in_dir ) ); err = 1; } while(0) -#define rmkdir_err( in_dir ) do{ log_err( __FILE__, __LINE__, "unable to create remote directory %s", ( in_dir ) ); err = 1; } while(0) #define misc_err( ... ) do{ log_err( __FILE__, __LINE__, __VA_ARGS__ ); err = 1; } while(0) @@ -514,6 +509,8 @@ const xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_ #define GETOPT_STRING "c:d:Dhlmp:qQrsvx" +static const char* s_systemupdate = "$SystemUpdate"; + const char* const cp1252_locales[] = { ".1252" /* Windows */, "C.CP1252", "en_US.CP1252", "de_DE.CP1252", NULL }; const char* const utf8_locales[] = { ".UTF-8" /* Windows */, "C.UTF-8", "en_US.UTF-8", NULL }; @@ -582,48 +579,47 @@ typedef struct write_tree_context { } write_tree_context; -void print_usage_and_exit(int ret, const char* name); -xoff_t lseek_with_error(int fd, xoff_t offset, int whence); -int log_err( const char *in_file, int in_line, const char *in_format, ... ); -void avl_rotate_left( dir_node_avl **in_root ); -void avl_rotate_right( dir_node_avl **in_root ); -int avl_compare_key( const char *in_lhs, const char *in_rhs ); -avl_result avl_left_grown( dir_node_avl **in_root ); -avl_result avl_right_grown( dir_node_avl **in_root ); -dir_node_avl *avl_fetch( dir_node_avl *in_root, const char *in_filename ); -avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ); -int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, int in_depth ); - -void boyer_moore_done(); -char *boyer_moore_search( char *in_text, size_t in_text_len ); -int boyer_moore_init( const char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ); - -int free_dir_node_avl(dir_node_avl* in_dir_node_avl, void* in_context, int in_depth); -int extract_file( int in_xiso, dir_node *in_file, modes in_mode, const char *path ); -int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ); -int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, const char *in_iso_name ); -int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); -int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); -int create_xiso( char *in_root_directory, const char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ); - -int get_filetime_now( file_time_t *ft ); -int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ); -int generate_avl_tree_remote( dir_node_avl **out_root, int *io_n ); -int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int in_depth ); -int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ); -int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ); -int calculate_total_files_and_bytes( dir_node_avl *in_avl, void *in_context, int in_depth ); -int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, int in_depth ); -int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, int in_depth ); -int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_context, int in_depth ); -int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io_context, int in_depth ); -int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ); +static void print_usage_and_exit(int ret, const char* name); +static xoff_t lseek_with_error(int fd, xoff_t offset, int whence); +static int log_err( const char *in_file, int in_line, const char *in_format, ... ); +static void avl_rotate_left( dir_node_avl **in_root ); +static void avl_rotate_right( dir_node_avl **in_root ); +static int avl_compare_key( const char *in_lhs, const char *in_rhs ); +static avl_result avl_left_grown( dir_node_avl **in_root ); +static avl_result avl_right_grown( dir_node_avl **in_root ); +static dir_node_avl *avl_fetch( dir_node_avl *in_root, const char *in_filename ); +static avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ); +static int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, int in_depth ); + +static void boyer_moore_done(); +static char *boyer_moore_search( char *in_text, size_t in_text_len ); +static int boyer_moore_init( const char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ); + +static int free_dir_node_avl(dir_node_avl* in_dir_node_avl, void* in_context, int in_depth); +static int extract_file( int in_xiso, dir_node *in_file, modes in_mode, const char *path ); +static int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ); +static int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, const char *in_iso_name ); +static int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); +static int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); +static int create_xiso( char *in_root_directory, const char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ); + +static int get_filetime_now( file_time_t *ft ); +static int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ); +static int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, int in_depth ); +static int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ); +static int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_depth ); +static int calculate_total_files_and_bytes( dir_node_avl *in_avl, void *in_context, int in_depth ); +static int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, int in_depth ); +static int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, int in_depth ); +static int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_context, int in_depth ); +static int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io_context, int in_depth ); +static int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ); static int is_lnk_lstat(struct dirent* p, bool* lnk); static int is_lnk(struct dirent* p, bool* lnk); #if DEBUG -void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char *in_extension ); +static void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char *in_extension ); #endif @@ -641,9 +637,7 @@ static long long s_total_bytes_all_isos = 0; static int s_total_files_all_isos = 0; static bool s_warned = false; static bool s_cp1252 = false; - static bool s_remove_systemupdate = false; -static char *s_systemupdate = "$SystemUpdate"; static xoff_t s_xbox_disc_lseek = 0; @@ -860,7 +854,7 @@ int main( int argc, char **argv ) { return err; } -void print_usage_and_exit(int ret, const char* name) { +static void print_usage_and_exit(int ret, const char* name) { fprintf(ret ? stderr : stdout, banner "\n\ Usage:\n\ \n\ @@ -902,7 +896,7 @@ void print_usage_and_exit(int ret, const char* name) { } /* Wrapper to avoid changing old code, since lseek will not return error if offset is beyond end of file. Use only on input. */ -xoff_t lseek_with_error(int fd, xoff_t offset, int whence) { +static xoff_t lseek_with_error(int fd, xoff_t offset, int whence) { xoff_t pos = lseek(fd, offset, whence); // First execute the seek, to save the offset if (pos == -1) return -1; xoff_t end = lseek(fd, 0, SEEK_END); // Then save the end of the file @@ -915,7 +909,7 @@ xoff_t lseek_with_error(int fd, xoff_t offset, int whence) { } -int log_err(unused_release const char* in_file, unused_release int in_line, const char* in_format, ...) { +static int log_err(unused_release const char* in_file, unused_release int in_line, const char* in_format, ...) { va_list ap; char *format; int ret; @@ -949,7 +943,7 @@ int log_err(unused_release const char* in_file, unused_release int in_line, cons #endif -int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, const char *in_iso_name ) { +static int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, const char *in_iso_name ) { int i, err = 0; char buffer[XISO_HEADER_DATA_LENGTH]; @@ -984,7 +978,7 @@ int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_ -int create_xiso( char *in_root_directory, const char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ) { +static int create_xiso( char *in_root_directory, const char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ) { xoff_t pos = 0; dir_node_avl root = { 0 }; file_time_t ft = 0; @@ -1161,7 +1155,7 @@ int create_xiso( char *in_root_directory, const char *in_output_directory, dir_n } -int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ) { +static int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ) { dir_node_avl *root = NULL; xoff_t root_dir_start; uint32_t root_dir_sect = 0, root_dir_size = 0; @@ -1249,7 +1243,7 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat } -int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { +static int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { dir_node_avl *avl = NULL; dir_node *node = NULL; uint16_t l_offset = 0, r_offset = 0; @@ -1384,7 +1378,7 @@ int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint1 return err; } -int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { +static int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy) { char *path = NULL; int err = 0; xoff_t dir_start = (xoff_t)node->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; @@ -1452,7 +1446,7 @@ int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode #endif -dir_node_avl *avl_fetch( dir_node_avl *in_root, const char *in_filename ) { +static dir_node_avl *avl_fetch( dir_node_avl *in_root, const char *in_filename ) { int result; for ( ;; ) { @@ -1467,7 +1461,7 @@ dir_node_avl *avl_fetch( dir_node_avl *in_root, const char *in_filename ) { } -avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ) { +static avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ) { avl_result tmp; int result; @@ -1482,7 +1476,7 @@ avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ) { } -avl_result avl_left_grown( dir_node_avl **in_root ) { +static avl_result avl_left_grown( dir_node_avl **in_root ) { switch ( (*in_root)->skew ) { case k_left_skew: if ( (*in_root)->left->skew == k_left_skew ) { @@ -1521,7 +1515,7 @@ avl_result avl_left_grown( dir_node_avl **in_root ) { } -avl_result avl_right_grown( dir_node_avl **in_root ) { +static avl_result avl_right_grown( dir_node_avl **in_root ) { switch ( (*in_root)->skew ) { case k_right_skew: if ( (*in_root)->right->skew == k_right_skew ) { @@ -1560,7 +1554,7 @@ avl_result avl_right_grown( dir_node_avl **in_root ) { } -void avl_rotate_left( dir_node_avl **in_root ) { +static void avl_rotate_left( dir_node_avl **in_root ) { dir_node_avl *tmp = *in_root; *in_root = (*in_root)->right; @@ -1569,7 +1563,7 @@ void avl_rotate_left( dir_node_avl **in_root ) { } -void avl_rotate_right( dir_node_avl **in_root ) { +static void avl_rotate_right( dir_node_avl **in_root ) { dir_node_avl *tmp = *in_root; *in_root = (*in_root)->left; @@ -1578,7 +1572,7 @@ void avl_rotate_right( dir_node_avl **in_root ) { } -int avl_compare_key( const char *in_lhs, const char *in_rhs ) { +static int avl_compare_key( const char *in_lhs, const char *in_rhs ) { unsigned char a, b; for ( ;; ) { @@ -1595,7 +1589,7 @@ int avl_compare_key( const char *in_lhs, const char *in_rhs ) { } -int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, int in_depth ) { +static int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, int in_depth ) { int err; if ( in_root == NULL ) return 0; @@ -1631,7 +1625,7 @@ int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callb #endif -int boyer_moore_init( const char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ) { +static int boyer_moore_init( const char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ) { size_t j, k, t, t1, q, q1, *aux = NULL; int err = 0; @@ -1688,13 +1682,13 @@ int boyer_moore_init( const char *in_pattern, size_t in_pat_len, size_t in_alpha } -void boyer_moore_done() { +static void boyer_moore_done() { if ( s_bc_table ) { free( s_bc_table ); s_bc_table = NULL; } if ( s_gs_table ) { free( s_gs_table ); s_gs_table = NULL; } } -char* boyer_moore_search(char* in_text, size_t in_text_len) { +static char* boyer_moore_search(char* in_text, size_t in_text_len) { size_t i, j; if (s_pat_len == 0) return in_text; @@ -1716,7 +1710,7 @@ char* boyer_moore_search(char* in_text, size_t in_text_len) { #endif -int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const char* path) { +static int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const char* path) { int err = 0; xoff_t file_start = (xoff_t)in_file->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; uint32_t i, size, totalsize = 0; @@ -1765,7 +1759,7 @@ int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const char* path } -int free_dir_node_avl( dir_node_avl *in_dir_node_avl, unused void *in_context, unused int in_depth ) { +static int free_dir_node_avl( dir_node_avl *in_dir_node_avl, unused void *in_context, unused int in_depth ) { if ((in_dir_node_avl->attributes & XISO_ATTRIBUTE_DIR) && in_dir_node_avl->subdirectory) avl_traverse_depth_first(in_dir_node_avl->subdirectory, (traversal_callback)free_dir_node_avl, NULL, k_postfix, 0); if (in_dir_node_avl->filename) free(in_dir_node_avl->filename); @@ -1776,7 +1770,7 @@ int free_dir_node_avl( dir_node_avl *in_dir_node_avl, unused void *in_context, u } -int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { +static int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { xoff_t pos = 0, dir_start = (xoff_t)in_avl->start_sector * XISO_SECTOR_SIZE; write_tree_context context = { 0 }; char* filename = in_avl->filename ? in_avl->filename : in_avl->filename_cp1252; @@ -1827,7 +1821,7 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unused int } -int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { +static int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { char *p = NULL; uint32_t bytes = 0, size = 0; int err = 0, fd = -1, n = 0, i = 0; @@ -1900,7 +1894,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int } -int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unused int in_depth ) { +static int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unused int in_depth ) { xoff_t pos; uint16_t l_offset, r_offset; uint32_t file_size = (in_avl->attributes & XISO_ATTRIBUTE_DIR) ? n_sectors(in_avl->file_size) * XISO_SECTOR_SIZE : in_avl->file_size; @@ -1936,7 +1930,7 @@ int write_directory( dir_node_avl *in_avl, write_tree_context* in_context, unuse } -int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_current_sector, unused int in_depth ) { +static int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_current_sector, unused int in_depth ) { wdsafp_context context = { 0 }; if ( in_avl->attributes & XISO_ATTRIBUTE_DIR ) { @@ -1959,7 +1953,7 @@ int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_current_sect } -int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io_context, unused int in_depth ) { +static int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io_context, unused int in_depth ) { in_avl->dir_start = io_context->dir_start; if (!(in_avl->attributes & XISO_ATTRIBUTE_DIR)) { @@ -1971,7 +1965,7 @@ int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io } -int calculate_total_files_and_bytes( dir_node_avl *in_avl, unused void *in_context, unused int in_depth ) { +static int calculate_total_files_and_bytes( dir_node_avl *in_avl, unused void *in_context, unused int in_depth ) { if (in_avl->attributes & XISO_ATTRIBUTE_DIR) { if (in_avl->subdirectory) { avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_total_files_and_bytes, NULL, k_prefix, 0); @@ -1984,7 +1978,7 @@ int calculate_total_files_and_bytes( dir_node_avl *in_avl, unused void *in_conte } -int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, unused int in_depth ) { +static int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, unused int in_depth ) { if (in_avl->attributes & XISO_ATTRIBUTE_DIR) { if (in_avl->subdirectory) { avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_directory_size, &in_avl->file_size, k_prefix, 0); @@ -1998,7 +1992,7 @@ int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, un } -int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, int in_depth ) { +static int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, int in_depth ) { uint32_t length; if ( in_depth == 0 ) *out_size = 0; @@ -2053,7 +2047,7 @@ static int is_lnk(struct dirent* p, bool* lnk) { } -int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { +static int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { struct dirent *p = NULL; struct stat sb = { 0 }; dir_node_avl *avl = NULL; @@ -2132,7 +2126,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { } -int get_filetime_now(file_time_t *ft) { +static int get_filetime_now(file_time_t *ft) { time_t now = 0; int err = 0; @@ -2160,7 +2154,7 @@ int get_filetime_now(file_time_t *ft) { // write_volume_descriptors() assumes that the iso file block from offset // 0x8000 to 0x8808 has been zeroed prior to entry. -int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ) { +static int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ) { uint32_t big, little; char date[] = "0000000000000000"; char spaces[ ECMA_119_VOLUME_CREATION_DATE - ECMA_119_VOLUME_SET_IDENTIFIER ]; @@ -2196,7 +2190,7 @@ int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ) { #if DEBUG -void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char *in_extension ) { +static void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char *in_extension ) { ssize_t wrote; xoff_t curpos = 0; int fp = -1, err = 0; From 1013c56db95200f85b531c57ad4693c49fe8c4f0 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sun, 3 Mar 2024 12:44:55 +0100 Subject: [PATCH 53/59] Skip $SystemUpdate directory during tree parsing, not writing Disable -s option in listing mode --- extract-xiso.c | 103 +++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index cbf4c99..582b8f8 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -823,6 +823,10 @@ int main( int argc, char **argv ) { if (buf) { free(buf); buf = NULL; } } else { // the order of the mutually exclusive options here is important, the extract ? k_extract : k_list test *must* be the final comparison + if (!extract && s_remove_systemupdate) { /* List mode */ + s_remove_systemupdate = false; + exiso_log("\nINFO: \"-s\" option disabled in list mode"); + } err = decode_xiso( argv[ i ], extract ? path : NULL, extract ? k_extract : k_list, NULL ); } } @@ -1281,6 +1285,9 @@ static int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset if (!err && (entry_offset * XISO_DWORD_SIZE + XISO_FILENAME_OFFSET + node->filename_length) > (end_offset * XISO_DWORD_SIZE)) misc_err("node entry spans beyond directory end"); if (!err) { + /* Save next offset for discovery */ + entry_offset = n_dword(entry_offset * XISO_DWORD_SIZE + XISO_FILENAME_OFFSET + node->filename_length); + little16(l_offset); little16(r_offset); little32(node->file_size); @@ -1306,7 +1313,7 @@ static int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset } // Process the node according to the mode - if (!err) { + if (!err && (!s_remove_systemupdate || strcmp(node->filename, s_systemupdate))) { if (in_mode == k_generate_avl) { if ((avl = (dir_node_avl*)calloc(1, sizeof(dir_node_avl))) == NULL) mem_err(); if (!err) { @@ -1345,9 +1352,6 @@ static int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset } } - // Save next offset for discovery - if (!err) entry_offset = n_dword(entry_offset * XISO_DWORD_SIZE + XISO_FILENAME_OFFSET + node->filename_length); - // Free memory before recurring or iterating if (filename) { free(filename); @@ -1389,15 +1393,12 @@ static int process_node(int in_xiso, dir_node* node, const char* in_path, modes if (!err) if (lseek_with_error(in_xiso, dir_start, SEEK_SET) == -1) seek_err(); if (!err) { - if (!s_remove_systemupdate || !strstr(node->filename, s_systemupdate)) - { - if (in_mode == k_extract) { - if ((err = mkdir(node->filename, 0755))) mkdir_err(node->filename); - if (!err && (err = chdir(node->filename))) chdir_err(node->filename); - } - if (!err && in_mode != k_generate_avl) { - exiso_log("\n%s%s%s%s (0 bytes)%s", in_mode == k_extract ? "creating\t" : "", in_path, node->filename, PATH_CHAR_STR, in_mode == k_extract ? " [OK]" : ""); flush(); - } + if (in_mode == k_extract) { + if ((err = mkdir(node->filename, 0755))) mkdir_err(node->filename); + if (!err && (err = chdir(node->filename))) chdir_err(node->filename); + } + if (!err && in_mode != k_generate_avl) { + exiso_log("\n%s%s%s%s (0 bytes)%s", in_mode == k_extract ? "creating\t" : "", in_path, node->filename, PATH_CHAR_STR, in_mode == k_extract ? " [OK]" : ""); flush(); } } @@ -1415,25 +1416,19 @@ static int process_node(int in_xiso, dir_node* node, const char* in_path, modes if (path) free(path); } - if (!s_remove_systemupdate || !strstr(node->filename, s_systemupdate)) - { - if (!err && in_mode == k_extract && (err = chdir(".."))) chdir_err(".."); - } + if (!err && in_mode == k_extract && (err = chdir(".."))) chdir_err(".."); } } else if (in_mode != k_generate_avl) { // Write file if (!err) { - if (!s_remove_systemupdate || !strstr(in_path, s_systemupdate)) - { - if (in_mode == k_extract) err = extract_file(in_xiso, node, in_mode, in_path); - else { - exiso_log("\n%s%s (%u bytes)", in_path, node->filename, node->file_size); flush(); - } - - ++s_total_files; - s_total_bytes += node->file_size; + if (in_mode == k_extract) err = extract_file(in_xiso, node, in_mode, in_path); + else { + exiso_log("\n%s%s (%u bytes)", in_path, node->filename, node->file_size); flush(); } + + ++s_total_files; + s_total_bytes += node->file_size; } } @@ -1720,39 +1715,37 @@ static int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const cha if (lseek_with_error(in_xiso, file_start, SEEK_SET) == -1) seek_err(); - if ( !s_remove_systemupdate || !strstr( path, s_systemupdate ) ) { - if ( in_mode == k_extract ) { - if (!err && (out = open(in_file->filename, WRITEFLAGS, 0644)) == -1) open_err(in_file->filename); - } else err = 1; + if ( in_mode == k_extract ) { + if (!err && (out = open(in_file->filename, WRITEFLAGS, 0644)) == -1) open_err(in_file->filename); + } else err = 1; - if ( ! err ) { - exiso_log("\n"); - if (in_file->file_size == 0) exiso_log("%s%s%s (0 bytes) [100%%]\r", in_mode == k_extract ? "extracting\t" : "", path, in_file->filename); - else { - i = 0; - size = min(in_file->file_size, READWRITE_BUFFER_SIZE); - do { - read_size = read(in_xiso, s_copy_buffer, size); - if (read_size < 0) read_err(); - else if (in_mode == k_extract && read_size != 0) { - if (write(out, s_copy_buffer, read_size) != read_size) write_err(); - } - if (!err) { - totalsize += read_size; - totalpercent = (totalsize * 100.0f) / in_file->file_size; - exiso_log("%s%s%s (%u bytes) [%.1f%%]\r", in_mode == k_extract ? "extracting\t" : "", path, in_file->filename, in_file->file_size, totalpercent); + if ( ! err ) { + exiso_log("\n"); + if (in_file->file_size == 0) exiso_log("%s%s%s (0 bytes) [100%%]\r", in_mode == k_extract ? "extracting\t" : "", path, in_file->filename); + else { + i = 0; + size = min(in_file->file_size, READWRITE_BUFFER_SIZE); + do { + read_size = read(in_xiso, s_copy_buffer, size); + if (read_size < 0) read_err(); + else if (in_mode == k_extract && read_size != 0) { + if (write(out, s_copy_buffer, read_size) != read_size) write_err(); + } + if (!err) { + totalsize += read_size; + totalpercent = (totalsize * 100.0f) / in_file->file_size; + exiso_log("%s%s%s (%u bytes) [%.1f%%]\r", in_mode == k_extract ? "extracting\t" : "", path, in_file->filename, in_file->file_size, totalpercent); - i += read_size; - size = min(in_file->file_size - i, READWRITE_BUFFER_SIZE); - } - } while (!err && i < in_file->file_size && read_size > 0); - if (!err && i < in_file->file_size) { - exiso_warn("File %s is truncated. Reported size: %u bytes, read size: %u bytes!", in_file->filename, in_file->file_size, i); - in_file->file_size = i; + i += read_size; + size = min(in_file->file_size - i, READWRITE_BUFFER_SIZE); } + } while (!err && i < in_file->file_size && read_size > 0); + if (!err && i < in_file->file_size) { + exiso_warn("File %s is truncated. Reported size: %u bytes, read size: %u bytes!", in_file->filename, in_file->file_size, i); + in_file->file_size = i; } - if (in_mode == k_extract) close(out); } + if (in_mode == k_extract) close(out); } return err; @@ -2058,7 +2051,7 @@ static int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { if ( ( dir = opendir( "." ) ) == NULL ) mem_err(); while ( ! err && ( p = readdir( dir ) ) != NULL ) { - if ( ! strcmp( p->d_name, "." ) || ! strcmp( p->d_name, ".." ) ) continue; + if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || (s_remove_systemupdate && !strcmp(p->d_name, s_systemupdate))) continue; for ( i = *io_n; i; --i ) exiso_log( "\b" ); exiso_log( "%s", p->d_name ); From eb47daacec11fc9b8042ca48ef1934e62d609e00 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sun, 3 Mar 2024 13:31:51 +0100 Subject: [PATCH 54/59] Remove unnecessary variable --- extract-xiso.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 582b8f8..e54046e 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -649,7 +649,7 @@ static xoff_t s_xbox_disc_lseek = 0; int main( int argc, char **argv ) { struct stat sb; - create_list *create = NULL, *p, *q; + create_list *create = NULL, *p; int i, fd, opt_char, err = 0, isos = 0; bool extract = true, rewrite = false, x_seen = false, delete = false, optimized; ptrdiff_t diff; @@ -760,30 +760,30 @@ int main( int argc, char **argv ) { if ( ! err && ( create || rewrite ) ) err = boyer_moore_init( XISO_MEDIA_ENABLE, XISO_MEDIA_ENABLE_LENGTH, k_default_alphabet_size ); if ( ! err && create ) { - p = create; - while (!err && p != NULL) { + /* After this loop create will be NULL, so remember not to check it anymore */ + while (!err && create != NULL) { diff = 0; - if ( p->name && (buf = strrchr(p->name, PATH_CHAR)) ) { - diff = buf - p->name; - if ( ( buf = (char *) malloc( diff + 1 ) ) == NULL ) mem_err(); - if ( ! err ) { - strncpy( buf, p->name, diff ); - buf[ diff ] = 0; + if (create->name && (buf = strrchr(create->name, PATH_CHAR))) { + diff = buf - create->name; + if ((buf = (char*)malloc(diff + 1)) == NULL) mem_err(); + if (!err) { + strncpy(buf, create->name, diff); + buf[diff] = 0; } diff += 1; } - - if ( ! err ) err = create_xiso( p->path, buf, NULL, -1, NULL, p->name ? p->name + diff : NULL, NULL ); + + if (!err) err = create_xiso(create->path, buf, NULL, -1, NULL, create->name ? create->name + diff : NULL, NULL); if (buf) { free(buf); buf = NULL; } - q = p->next; + p = create->next; - if ( p->name ) free( p->name ); - if ( p->path ) free( p->path ); - free( p ); - - p = q; + if (create->name) free(create->name); + if (create->path) free(create->path); + free(create); + + create = p; } } else for ( i = optind; ! err && i < argc; ++i ) { ++isos; From ae5f1971005700ff1324e45587ce1d7463e05b67 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Sun, 3 Mar 2024 20:43:22 +0100 Subject: [PATCH 55/59] Update dependecy --- deps/getopt_port | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/getopt_port b/deps/getopt_port index 6ad8cc1..9d3d387 160000 --- a/deps/getopt_port +++ b/deps/getopt_port @@ -1 +1 @@ -Subproject commit 6ad8cc105b55ad9f83136129fd0c6c2a209da43e +Subproject commit 9d3d387087d252970923db7f297f681622c4e026 From 15633023d4914136b6b01c830f815835f8044141 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 17 Sep 2024 00:03:35 +0200 Subject: [PATCH 56/59] Use unsigned char for buffers Replace fors with whiles when appropriate Small cleanups --- extract-xiso.c | 88 +++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index e54046e..8b21ff0 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -495,10 +495,10 @@ const xoff_t lseek_offsets[LSEEK_OFFSETS_LEN] = {START_LSEEK_OFFSET, XGD3_LSEEK_ #define XISO_PAD_BYTE 0xff #define XISO_PAD_SHORT 0xffff -#define XISO_MEDIA_ENABLE "\xe8\xca\xfd\xff\xff\x85\xc0\x7d" -#define XISO_MEDIA_ENABLE_BYTE '\xeb' #define XISO_MEDIA_ENABLE_LENGTH 8 #define XISO_MEDIA_ENABLE_BYTE_POS 7 +const unsigned char xiso_media_enable[XISO_MEDIA_ENABLE_LENGTH] = { 0xe8, 0xca, 0xfd, 0xff, 0xff, 0x85, 0xc0, 0x7d }; +const unsigned char xiso_media_enable_byte = 0xeb; #define n_sectors(size) ( (size) / XISO_SECTOR_SIZE + ( (size) % XISO_SECTOR_SIZE ? 1 : 0 ) ) #define n_dword(offset) ( (offset) / XISO_DWORD_SIZE + ( (offset) % XISO_DWORD_SIZE ? 1 : 0 ) ) @@ -592,8 +592,8 @@ static avl_result avl_insert( dir_node_avl **in_root, dir_node_avl *in_node ); static int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback in_callback, void *in_context, avl_traversal_method in_method, int in_depth ); static void boyer_moore_done(); -static char *boyer_moore_search( char *in_text, size_t in_text_len ); -static int boyer_moore_init( const char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ); +static unsigned char *boyer_moore_search( unsigned char *in_text, size_t in_text_len ); +static int boyer_moore_init( const unsigned char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ); static int free_dir_node_avl(dir_node_avl* in_dir_node_avl, void* in_context, int in_depth); static int extract_file( int in_xiso, dir_node *in_file, modes in_mode, const char *path ); @@ -625,12 +625,12 @@ static void write_sector( int in_xiso, xoff_t in_start, const char *in_name, con static size_t s_pat_len; static bool s_quiet = false; -static const char *s_pattern = NULL; +static const unsigned char *s_pattern = NULL; static size_t *s_gs_table = NULL; static size_t *s_bc_table = NULL; static long long s_total_bytes = 0; static int s_total_files = 0; -static char *s_copy_buffer = NULL; +static unsigned char *s_copy_buffer = NULL; static bool s_real_quiet = false; static bool s_media_enable = true; static long long s_total_bytes_all_isos = 0; @@ -742,7 +742,7 @@ int main( int argc, char **argv ) { exiso_log(banner); - if ((extract || rewrite || create) && (s_copy_buffer = (char*)malloc(READWRITE_BUFFER_SIZE)) == NULL) mem_err(); + if ((extract || rewrite || create) && (s_copy_buffer = (unsigned char*)malloc(READWRITE_BUFFER_SIZE)) == NULL) mem_err(); } @@ -757,7 +757,7 @@ int main( int argc, char **argv ) { } } - if ( ! err && ( create || rewrite ) ) err = boyer_moore_init( XISO_MEDIA_ENABLE, XISO_MEDIA_ENABLE_LENGTH, k_default_alphabet_size ); + if ( ! err && ( create || rewrite ) ) err = boyer_moore_init( xiso_media_enable, XISO_MEDIA_ENABLE_LENGTH, k_default_alphabet_size ); if ( ! err && create ) { /* After this loop create will be NULL, so remember not to check it anymore */ @@ -949,7 +949,7 @@ static int log_err(unused_release const char* in_file, unused_release int in_lin static int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, const char *in_iso_name ) { int i, err = 0; - char buffer[XISO_HEADER_DATA_LENGTH]; + unsigned char buffer[XISO_HEADER_DATA_LENGTH]; for (i = 0; !err && i < LSEEK_OFFSETS_LEN; i++) { if (lseek_with_error(in_xiso, (xoff_t)XISO_HEADER_OFFSET + lseek_offsets[i], SEEK_SET) == -1) seek_err(); @@ -967,7 +967,7 @@ static int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *ou little32( *out_root_dir_sector ); little32( *out_root_dir_size ); - + // seek to header tail and verify media tag if ( ! err && lseek_with_error(in_xiso, (xoff_t)XISO_FILETIME_SIZE + XISO_UNUSED_SIZE, SEEK_CUR) == -1) seek_err(); if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err(); @@ -983,12 +983,12 @@ static int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *ou static int create_xiso( char *in_root_directory, const char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ) { - xoff_t pos = 0; + xoff_t size = 0; dir_node_avl root = { 0 }; file_time_t ft = 0; write_tree_context wt_context = { 0 }; uint32_t start_sector = 0; - int i = 0, n = 0, xiso = -1, err = 0; + int i = 0, n = 0, xiso = -1, err = 0, pad = 0; char *cwd = NULL, *iso_name = NULL, *xiso_path = NULL, *iso_dir = NULL, *real_path = NULL, *in_dir_path = NULL; s_total_bytes = s_total_files = 0; @@ -1118,14 +1118,15 @@ static int create_xiso( char *in_root_directory, const char *in_output_directory err = avl_traverse_depth_first( &root, (traversal_callback) write_tree, &wt_context, k_prefix, 0 ); } - if ( ! err && ( pos = lseek( xiso, (xoff_t) 0, SEEK_END ) ) == -1 ) seek_err(); + if ( ! err && ( size = lseek( xiso, (xoff_t) 0, SEEK_END ) ) == -1 ) seek_err(); if (!err) { - i = (int)((XISO_FILE_MODULUS - pos % XISO_FILE_MODULUS) % XISO_FILE_MODULUS); - memset(s_copy_buffer, 0, i); - if (write(xiso, s_copy_buffer, i) != i) write_err(); + pad = (int)((XISO_FILE_MODULUS - (size % XISO_FILE_MODULUS)) % XISO_FILE_MODULUS); + size += pad; + memset(s_copy_buffer, 0, pad); + if (write(xiso, s_copy_buffer, pad) != pad) write_err(); } - if ( ! err ) err = write_volume_descriptors( xiso, (uint32_t)((pos + (xoff_t)i) / XISO_SECTOR_SIZE) ); + if ( ! err ) err = write_volume_descriptors( xiso, (uint32_t)(size / XISO_SECTOR_SIZE) ); if ( ! err && lseek( xiso, (xoff_t) XISO_OPTIMIZED_TAG_OFFSET, SEEK_SET ) == -1 ) seek_err(); if ( ! err && write( xiso, XISO_OPTIMIZED_TAG, XISO_OPTIMIZED_TAG_LENGTH ) != XISO_OPTIMIZED_TAG_LENGTH ) write_err(); @@ -1267,15 +1268,15 @@ static int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset } else if (strategy != discover_strategy) { // When discovering, the padding means end of sector exiso_warn("Invalid node found and skipped!"); // When not discovering, the padding means a bad entry, skip it without failing - return err; // We're done if not discovering + return 0; // We're done if not discovering } // We're discovering, so set the offset to the start of the next sector - if (!err) entry_offset = n_sectors(entry_offset * XISO_DWORD_SIZE) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE; + entry_offset = n_sectors(entry_offset * XISO_DWORD_SIZE) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE; continue; } // Read node - if (!err) if ((node = calloc(1, sizeof(dir_node))) == NULL) mem_err(); + if (!err && (node = calloc(1, sizeof(dir_node))) == NULL) mem_err(); if (!err && read(in_xiso, &r_offset, XISO_TABLE_OFFSET_SIZE) != XISO_TABLE_OFFSET_SIZE) read_err(); if (!err && read(in_xiso, &node->start_sector, XISO_SECTOR_OFFSET_SIZE) != XISO_SECTOR_OFFSET_SIZE) read_err(); if (!err && read(in_xiso, &node->file_size, XISO_FILESIZE_SIZE) != XISO_FILESIZE_SIZE) read_err(); @@ -1444,15 +1445,15 @@ static int process_node(int in_xiso, dir_node* node, const char* in_path, modes static dir_node_avl *avl_fetch( dir_node_avl *in_root, const char *in_filename ) { int result; - for ( ;; ) { - if ( in_root == NULL ) return NULL; - + while (in_root != NULL) { result = avl_compare_key( in_filename, in_root->filename_cp1252); if ( result < 0 ) in_root = in_root->left; else if ( result > 0 ) in_root = in_root->right; else return in_root; } + + return NULL; } @@ -1567,20 +1568,19 @@ static void avl_rotate_right( dir_node_avl **in_root ) { } -static int avl_compare_key( const char *in_lhs, const char *in_rhs ) { +static int avl_compare_key(const char* in_lhs, const char* in_rhs) { unsigned char a, b; - for ( ;; ) { + do { a = (unsigned char)toupperCP1252(*in_lhs++); b = (unsigned char)toupperCP1252(*in_rhs++); - - if ( a ) { - if ( b ) { - if ( a < b ) return -1; - if ( a > b ) return 1; - } else return 1; - } else return b ? -1 : 0; - } + + if (a < b) return -1; + if (a > b) return 1; + } while (a && b); + + /* If we're here, both a and b are '\0', otherwise we would have returned before. */ + return 0; } @@ -1620,7 +1620,7 @@ static int avl_traverse_depth_first( dir_node_avl *in_root, traversal_callback i #endif -static int boyer_moore_init( const char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ) { +static int boyer_moore_init( const unsigned char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ) { size_t j, k, t, t1, q, q1, *aux = NULL; int err = 0; @@ -1635,7 +1635,7 @@ static int boyer_moore_init( const char *in_pattern, size_t in_pat_len, size_t i if ((s_bc_table = (size_t*)malloc(in_alphabet_size * sizeof(size_t))) == NULL) mem_err(); if (!err) { for (k = 0; k < in_alphabet_size; k++) s_bc_table[k] = in_pat_len; - for (k = 0; k < in_pat_len; k++) s_bc_table[(unsigned char)in_pattern[k]] = in_pat_len - 1 - k; + for (k = 0; k < in_pat_len; k++) s_bc_table[in_pattern[k]] = in_pat_len - 1 - k; } // Delta2 table (dd' algorithm with Rytter correction) @@ -1683,7 +1683,7 @@ static void boyer_moore_done() { } -static char* boyer_moore_search(char* in_text, size_t in_text_len) { +static unsigned char* boyer_moore_search(unsigned char* in_text, size_t in_text_len) { size_t i, j; if (s_pat_len == 0) return in_text; @@ -1694,7 +1694,7 @@ static char* boyer_moore_search(char* in_text, size_t in_text_len) { if (j == 0) return in_text + i; } - i += max(s_bc_table[(unsigned char)in_text[i]], s_gs_table[j]); + i += max(s_bc_table[in_text[i]], s_gs_table[j]); } return NULL; } @@ -1815,7 +1815,7 @@ static int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, unu static int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unused int in_depth ) { - char *p = NULL; + unsigned char* p = NULL; uint32_t bytes = 0, size = 0; int err = 0, fd = -1, n = 0, i = 0; size_t len; @@ -1849,7 +1849,11 @@ static int write_file( dir_node_avl *in_avl, write_tree_context *in_context, unu bytes -= n; if (s_media_enable && xbe_file) { n += i; - for (p = s_copy_buffer; (p = boyer_moore_search(p, n - (long)(p - s_copy_buffer))) != NULL; p += XISO_MEDIA_ENABLE_LENGTH) p[XISO_MEDIA_ENABLE_BYTE_POS] = XISO_MEDIA_ENABLE_BYTE; + p = s_copy_buffer; + while ((p = boyer_moore_search(p, (size_t)n - (p - s_copy_buffer))) != NULL) { + p[XISO_MEDIA_ENABLE_BYTE_POS] = xiso_media_enable_byte; + p += XISO_MEDIA_ENABLE_LENGTH; + } if (bytes) { i = XISO_MEDIA_ENABLE_LENGTH - 1; n -= i; @@ -2187,7 +2191,9 @@ static void write_sector( int in_xiso, xoff_t in_start, const char *in_name, con ssize_t wrote; xoff_t curpos = 0; int fp = -1, err = 0; - char *cwd, *sect = NULL, buf[ 256 ]; + char buf[256]; + char *cwd; + unsigned char *sect = NULL; if ( ( cwd = getcwd( NULL, 0 ) ) == NULL ) mem_err(); if ( ! err && chdir( DEBUG_DUMP_DIRECTORY ) == -1 ) chdir_err( DEBUG_DUMP_DIRECTORY ); @@ -2198,7 +2204,7 @@ static void write_sector( int in_xiso, xoff_t in_start, const char *in_name, con if ( ! err && ( curpos = lseek_with_error( in_xiso, 0, SEEK_CUR ) ) == -1 ) seek_err(); if ( ! err && lseek_with_error( in_xiso, in_start, SEEK_SET ) == -1 ) seek_err(); - if ( ! err && ( sect = (char *) malloc( XISO_SECTOR_SIZE ) ) == NULL ) mem_err(); + if ( ! err && ( sect = (unsigned char *) malloc( XISO_SECTOR_SIZE ) ) == NULL ) mem_err(); if ( ! err && read( in_xiso, sect, XISO_SECTOR_SIZE ) != XISO_SECTOR_SIZE ) read_err(); if ( ! err && ( wrote = write( fp, sect, XISO_SECTOR_SIZE ) ) != XISO_SECTOR_SIZE ) write_err(); From 1596f944d861b4faef437fd6631183d3b4a4cba0 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 17 Sep 2024 00:17:56 +0200 Subject: [PATCH 57/59] Update CI for FreeBSD 13.4, OpenBSD 7.5 and NetBSD 9.4 --- .github/workflows/CI.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 481f09d..1b96200 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -128,7 +128,7 @@ jobs: - name: FreeBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ - wget -nv http://ftp.plusline.de/FreeBSD/releases/amd64/13.2-RELEASE/base.txz && \ + wget -nv http://ftp.plusline.de/FreeBSD/releases/amd64/13.4-RELEASE/base.txz && \ mkdir -p $SYSROOT_PATH && cd $SYSROOT_PATH && \ tar -xf /tmp/base.txz ./lib/ ./usr/lib/ ./usr/include/ && \ cd $SYSROOT_PATH/usr/lib && \ @@ -162,12 +162,12 @@ jobs: - name: OpenBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ - wget -nv https://cdn.openbsd.org/pub/OpenBSD/7.4/amd64/base74.tgz \ - https://cdn.openbsd.org/pub/OpenBSD/7.4/amd64/comp74.tgz && \ + wget -nv https://cdn.openbsd.org/pub/OpenBSD/7.5/amd64/base75.tgz \ + https://cdn.openbsd.org/pub/OpenBSD/7.5/amd64/comp75.tgz && \ mkdir -p $SYSROOT_PATH && cd $SYSROOT_PATH && \ - tar -xf /tmp/base74.tgz ./usr/lib/ ./usr/include/ && \ - tar -xf /tmp/comp74.tgz ./usr/lib/ ./usr/include/ && \ - rm -f /tmp/base74.tgz /tmp/comp74.tgz + tar -xf /tmp/base75.tgz ./usr/lib/ ./usr/include/ && \ + tar -xf /tmp/comp75.tgz ./usr/lib/ ./usr/include/ && \ + rm -f /tmp/base75.tgz /tmp/comp75.tgz - name: CMake generate run: | mkdir build && cd build @@ -196,8 +196,8 @@ jobs: - name: NetBSD toolchain setup run: | sudo apt-get -qq install clang lld && cd /tmp && \ - wget -nv https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.3/amd64/binary/sets/base.tar.xz \ - https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.3/amd64/binary/sets/comp.tar.xz && \ + wget -nv https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.4/amd64/binary/sets/base.tar.xz \ + https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.4/amd64/binary/sets/comp.tar.xz && \ mkdir -p $SYSROOT_PATH && cd $SYSROOT_PATH && \ tar -xf /tmp/base.tar.xz ./usr/lib/ ./usr/include/ && \ tar -xf /tmp/comp.tar.xz ./usr/lib/ ./usr/include/ && \ From 6e3ee442e5d5348c7e00cc0cdc37793321c1f87f Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 17 Sep 2024 22:13:56 +0200 Subject: [PATCH 58/59] Handle XISO timestamp explicitly --- extract-xiso.c | 57 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 8b21ff0..1fe9c58 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -598,10 +598,10 @@ static int boyer_moore_init( const unsigned char *in_pattern, size_t in_pat_len, static int free_dir_node_avl(dir_node_avl* in_dir_node_avl, void* in_context, int in_depth); static int extract_file( int in_xiso, dir_node *in_file, modes in_mode, const char *path ); static int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ); -static int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, const char *in_iso_name ); +static int verify_xiso(int in_xiso, uint32_t* out_root_dir_sector, uint32_t* out_root_dir_size, file_time_t* out_file_time, const char* in_iso_name); static int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); static int process_node(int in_xiso, dir_node* node, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); -static int create_xiso( char *in_root_directory, const char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ); +static int create_xiso(char* in_root_directory, const char* in_output_directory, dir_node_avl* in_root, int in_xiso, char** out_iso_path, char* in_name, file_time_t* ft, progress_callback in_progress_callback); static int get_filetime_now( file_time_t *ft ); static int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ); @@ -653,6 +653,7 @@ int main( int argc, char **argv ) { int i, fd, opt_char, err = 0, isos = 0; bool extract = true, rewrite = false, x_seen = false, delete = false, optimized; ptrdiff_t diff; + file_time_t ft = 0; char *path = NULL, *buf = NULL, *new_iso_path = NULL; const char *locale = NULL; const char* const *locale_arr = NULL; @@ -773,7 +774,9 @@ int main( int argc, char **argv ) { diff += 1; } - if (!err) err = create_xiso(create->path, buf, NULL, -1, NULL, create->name ? create->name + diff : NULL, NULL); + if (!err && (err = get_filetime_now(&ft))) misc_err("cannot get current time"); + + if (!err) err = create_xiso(create->path, buf, NULL, -1, NULL, create->name ? create->name + diff : NULL, &ft, NULL); if (buf) { free(buf); buf = NULL; } @@ -947,7 +950,7 @@ static int log_err(unused_release const char* in_file, unused_release int in_lin #endif -static int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *out_root_dir_size, const char *in_iso_name ) { +static int verify_xiso(int in_xiso, uint32_t* out_root_dir_sector, uint32_t* out_root_dir_size, file_time_t* out_file_time, const char* in_iso_name) { int i, err = 0; unsigned char buffer[XISO_HEADER_DATA_LENGTH]; @@ -962,30 +965,31 @@ static int verify_xiso( int in_xiso, uint32_t *out_root_dir_sector, uint32_t *ou if (!err && i == LSEEK_OFFSETS_LEN) misc_err("%s does not appear to be a valid xbox iso image", in_iso_name); // read root directory information - if ( ! err && read( in_xiso, out_root_dir_sector, XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) read_err(); - if ( ! err && read( in_xiso, out_root_dir_size, XISO_DIRTABLE_SIZE ) != XISO_DIRTABLE_SIZE ) read_err(); + if (!err && read(in_xiso, out_root_dir_sector, XISO_SECTOR_OFFSET_SIZE) != XISO_SECTOR_OFFSET_SIZE) read_err(); + if (!err && read(in_xiso, out_root_dir_size, XISO_DIRTABLE_SIZE) != XISO_DIRTABLE_SIZE) read_err(); + if (!err && read(in_xiso, out_file_time, XISO_FILETIME_SIZE) != XISO_FILETIME_SIZE) read_err(); - little32( *out_root_dir_sector ); - little32( *out_root_dir_size ); + little32(*out_root_dir_sector); + little32(*out_root_dir_size); + little64(*out_file_time); // seek to header tail and verify media tag - if ( ! err && lseek_with_error(in_xiso, (xoff_t)XISO_FILETIME_SIZE + XISO_UNUSED_SIZE, SEEK_CUR) == -1) seek_err(); - if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err(); - if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) ) misc_err( "%s appears to be corrupt", in_iso_name ); + if (!err && lseek_with_error(in_xiso, (xoff_t)XISO_UNUSED_SIZE, SEEK_CUR) == -1) seek_err(); + if (!err && read(in_xiso, buffer, XISO_HEADER_DATA_LENGTH) != XISO_HEADER_DATA_LENGTH) read_err(); + if (!err && memcmp(buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH)) misc_err("%s appears to be corrupt", in_iso_name); // seek to root directory sector if (!err && lseek_with_error(in_xiso, (xoff_t)*out_root_dir_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); - + return err; } -static int create_xiso( char *in_root_directory, const char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, progress_callback in_progress_callback ) { +static int create_xiso( char *in_root_directory, const char *in_output_directory, dir_node_avl *in_root, int in_xiso, char **out_iso_path, char *in_name, file_time_t *ft, progress_callback in_progress_callback ) { xoff_t size = 0; dir_node_avl root = { 0 }; - file_time_t ft = 0; write_tree_context wt_context = { 0 }; uint32_t start_sector = 0; int i = 0, n = 0, xiso = -1, err = 0, pad = 0; @@ -1083,14 +1087,9 @@ static int create_xiso( char *in_root_directory, const char *in_output_directory little32( root.file_size ); } if ( ! err ) { - if ( in_root ) { - if (lseek_with_error(in_xiso, (xoff_t)XISO_HEADER_OFFSET + XISO_HEADER_DATA_LENGTH + XISO_SECTOR_OFFSET_SIZE + XISO_DIRTABLE_SIZE + s_xbox_disc_lseek, SEEK_SET) == -1) seek_err(); - if ( ! err && read( in_xiso, s_copy_buffer, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) read_err(); - if ( ! err && write( xiso, s_copy_buffer, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) write_err(); - } else { - if ( ( err = get_filetime_now(&ft) ) ) misc_err("cannot get current time"); - if ( ! err && write( xiso, &ft, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) write_err(); - } + little64(*ft); + if (write(xiso, ft, XISO_FILETIME_SIZE) != XISO_FILETIME_SIZE) write_err(); + little64(*ft); } memset(s_copy_buffer, 0, XISO_UNUSED_SIZE); if ( ! err && write( xiso, s_copy_buffer, XISO_UNUSED_SIZE ) != XISO_UNUSED_SIZE ) write_err(); @@ -1164,6 +1163,7 @@ static int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_ dir_node_avl *root = NULL; xoff_t root_dir_start; uint32_t root_dir_sect = 0, root_dir_size = 0; + file_time_t file_time; uint16_t root_end_offset; size_t len; int xiso = 0, err = 0; @@ -1205,7 +1205,7 @@ static int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_ } } - if (!err) err = verify_xiso(xiso, &root_dir_sect, &root_dir_size, name); + if (!err) err = verify_xiso(xiso, &root_dir_sect, &root_dir_size, &file_time, name); if (!err && in_mode != k_rewrite) exiso_log("\n%s %s:\n", in_mode == k_extract ? "extracting" : "listing", name); @@ -1221,7 +1221,7 @@ static int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_ if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, k_generate_avl, &root, tree_strategy); if (!err) err = traverse_xiso(xiso, root_dir_start, 0, root_end_offset, path, k_generate_avl, &root, discover_strategy); } - if (!err) err = create_xiso(iso_name, in_path, root, xiso, out_iso_path, NULL, NULL); + if (!err) err = create_xiso(iso_name, in_path, root, xiso, out_iso_path, NULL, &file_time, NULL); } else { exiso_log("\n%s%s (0 bytes)%s", in_mode == k_extract ? "creating\t" : "", path, in_mode == k_extract ? " [OK]" : ""); flush(); @@ -2123,17 +2123,16 @@ static int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { } -static int get_filetime_now(file_time_t *ft) { +static int get_filetime_now(file_time_t* ft) { time_t now = 0; int err = 0; if (ft == NULL) return 1; - if ( ( now = time( NULL ) ) == -1 ) unknown_err(); - if ( ! err ) { + if ((now = time(NULL)) == -1) unknown_err(); + if (!err) { *ft = (now * 10000000LL) + 116444736000000000LL; // Magic numbers directly from Microsoft - little64(*ft); // convert to little endian here because this is a PC only struct and we won't read it anyway } - + return err; } From 05582e14240e98ac6c29789fae01802ac9fe5b04 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Tue, 17 Sep 2024 23:28:43 +0200 Subject: [PATCH 59/59] Remove unnecessary parameter from extract_file --- extract-xiso.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/extract-xiso.c b/extract-xiso.c index 1fe9c58..ce62670 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -596,7 +596,7 @@ static unsigned char *boyer_moore_search( unsigned char *in_text, size_t in_text static int boyer_moore_init( const unsigned char *in_pattern, size_t in_pat_len, size_t in_alphabet_size ); static int free_dir_node_avl(dir_node_avl* in_dir_node_avl, void* in_context, int in_depth); -static int extract_file( int in_xiso, dir_node *in_file, modes in_mode, const char *path ); +static int extract_file(int in_xiso, dir_node* in_file, const char* path); static int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_path ); static int verify_xiso(int in_xiso, uint32_t* out_root_dir_sector, uint32_t* out_root_dir_size, file_time_t* out_file_time, const char* in_iso_name); static int traverse_xiso(int in_xiso, xoff_t in_dir_start, uint16_t entry_offset, uint16_t end_offset, const char* in_path, modes in_mode, dir_node_avl** in_root, strategies strategy); @@ -1423,7 +1423,7 @@ static int process_node(int in_xiso, dir_node* node, const char* in_path, modes } else if (in_mode != k_generate_avl) { // Write file if (!err) { - if (in_mode == k_extract) err = extract_file(in_xiso, node, in_mode, in_path); + if (in_mode == k_extract) err = extract_file(in_xiso, node, in_path); else { exiso_log("\n%s%s (%u bytes)", in_path, node->filename, node->file_size); flush(); } @@ -1705,7 +1705,7 @@ static unsigned char* boyer_moore_search(unsigned char* in_text, size_t in_text_ #endif -static int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const char* path) { +static int extract_file(int in_xiso, dir_node* in_file, const char* path) { int err = 0; xoff_t file_start = (xoff_t)in_file->start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek; uint32_t i, size, totalsize = 0; @@ -1715,39 +1715,39 @@ static int extract_file(int in_xiso, dir_node *in_file, modes in_mode, const cha if (lseek_with_error(in_xiso, file_start, SEEK_SET) == -1) seek_err(); - if ( in_mode == k_extract ) { - if (!err && (out = open(in_file->filename, WRITEFLAGS, 0644)) == -1) open_err(in_file->filename); - } else err = 1; + if (!err && (out = open(in_file->filename, WRITEFLAGS, 0644)) == -1) open_err(in_file->filename); - if ( ! err ) { + if (!err) { exiso_log("\n"); - if (in_file->file_size == 0) exiso_log("%s%s%s (0 bytes) [100%%]\r", in_mode == k_extract ? "extracting\t" : "", path, in_file->filename); + if (in_file->file_size == 0) { + exiso_log("extracting\t%s%s (0 bytes) [100%%]\r", path, in_file->filename); + } else { i = 0; size = min(in_file->file_size, READWRITE_BUFFER_SIZE); do { - read_size = read(in_xiso, s_copy_buffer, size); - if (read_size < 0) read_err(); - else if (in_mode == k_extract && read_size != 0) { - if (write(out, s_copy_buffer, read_size) != read_size) write_err(); - } + if ((read_size = read(in_xiso, s_copy_buffer, size)) < 0) read_err(); + else if (read_size != 0 && (write(out, s_copy_buffer, read_size) != read_size)) write_err(); + if (!err) { totalsize += read_size; totalpercent = (totalsize * 100.0f) / in_file->file_size; - exiso_log("%s%s%s (%u bytes) [%.1f%%]\r", in_mode == k_extract ? "extracting\t" : "", path, in_file->filename, in_file->file_size, totalpercent); + exiso_log("extracting\t%s%s (%u bytes) [%.1f%%]\r", path, in_file->filename, in_file->file_size, totalpercent); i += read_size; size = min(in_file->file_size - i, READWRITE_BUFFER_SIZE); } } while (!err && i < in_file->file_size && read_size > 0); + if (!err && i < in_file->file_size) { exiso_warn("File %s is truncated. Reported size: %u bytes, read size: %u bytes!", in_file->filename, in_file->file_size, i); in_file->file_size = i; } } - if (in_mode == k_extract) close(out); } + if (out != -1) close(out); + return err; }