505
505
#define XISO_MEDIA_ENABLE_LENGTH 8
506
506
#define XISO_MEDIA_ENABLE_BYTE_POS 7
507
507
508
+ #define n_dword (offset ) ( (offset) / XISO_DWORD_SIZE + ( (offset) % XISO_DWORD_SIZE ? 1 : 0 ) )
509
+
508
510
#define EMPTY_SUBDIRECTORY ( (dir_node_avl *) 1 )
509
511
510
512
#define READWRITE_BUFFER_SIZE 0x00200000
@@ -522,6 +524,7 @@ typedef enum bm_constants { k_default_alphabet_size = 256 } bm_constants;
522
524
523
525
typedef enum modes { k_generate_avl , k_extract , k_list , k_rewrite } modes ;
524
526
typedef enum errors { err_end_of_sector = -5001 , err_iso_rewritten = -5002 , err_iso_no_files = -5003 } errors ;
527
+ typedef enum strategies { tree_strategy , discover_strategy } strategies ;
525
528
526
529
typedef void (* progress_callback )( xoff_t in_current_value , xoff_t in_final_value );
527
530
typedef int (* traversal_callback )( void * in_node , void * in_context , long in_depth );
@@ -597,8 +600,8 @@ int free_dir_node_avl( void *in_dir_node_avl, void *, long );
597
600
int extract_file ( int in_xiso , dir_node * in_file , modes in_mode , char * path );
598
601
int decode_xiso ( char * in_xiso , char * in_path , modes in_mode , char * * out_iso_path );
599
602
int verify_xiso ( int in_xiso , int32_t * out_root_dir_sector , int32_t * out_root_dir_size , char * in_iso_name );
600
- 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 );
601
- int process_node (int in_xiso , dir_node * node , char * in_path , modes in_mode , dir_node_avl * * in_root );
603
+ 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 );
604
+ int process_node (int in_xiso , dir_node * node , char * in_path , modes in_mode , dir_node_avl * * in_root , strategies strategy );
602
605
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 );
603
606
604
607
FILE_TIME * alloc_filetime_now ( void );
@@ -1112,7 +1115,9 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av
1112
1115
int decode_xiso ( char * in_xiso , char * in_path , modes in_mode , char * * out_iso_path ) {
1113
1116
dir_node_avl * root = nil ;
1114
1117
bool repair = false;
1118
+ xoff_t root_dir_start ;
1115
1119
int32_t root_dir_sect , root_dir_size ;
1120
+ uint16_t root_end_offset ;
1116
1121
int xiso , err = 0 , len , path_len = 0 , add_slash = 0 ;
1117
1122
char * buf , * cwd = nil , * name = nil , * short_name = nil , * iso_name , * folder = nil ;
1118
1123
@@ -1171,14 +1176,18 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat
1171
1176
if (!err ) {
1172
1177
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 ()
1173
1178
1174
- if (!err && lseek (xiso , (xoff_t )root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek , SEEK_SET ) == -1 ) seek_err ();
1179
+ root_dir_start = (xoff_t )root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek ;
1180
+ root_end_offset = n_sectors (root_dir_size ) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE ;
1175
1181
1182
+ if (!err && lseek (xiso , root_dir_start , SEEK_SET ) == -1 ) seek_err ();
1183
+
1176
1184
if ( in_mode == k_rewrite ) {
1177
- if (!err ) err = traverse_xiso (xiso , (xoff_t )root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek , 0 , buf , k_generate_avl , & root );
1185
+ if (!err ) err = traverse_xiso (xiso , root_dir_start , 0 , root_end_offset , buf , k_generate_avl , & root , tree_strategy );
1186
+ if (!err ) err = traverse_xiso (xiso , root_dir_start , 0 , root_end_offset , buf , k_generate_avl , & root , discover_strategy );
1178
1187
if (!err ) err = create_xiso ( iso_name , in_path , root , xiso , out_iso_path , nil , nil );
1179
1188
}
1180
1189
else {
1181
- if (!err ) err = traverse_xiso (xiso , ( xoff_t ) root_dir_sect * XISO_SECTOR_SIZE + s_xbox_disc_lseek , 0 , buf , in_mode , nil );
1190
+ if (!err ) err = traverse_xiso (xiso , root_dir_start , 0 , root_end_offset , buf , in_mode , nil , discover_strategy );
1182
1191
}
1183
1192
1184
1193
if (buf ) free (buf );
@@ -1202,97 +1211,122 @@ int decode_xiso( char *in_xiso, char *in_path, modes in_mode, char **out_iso_pat
1202
1211
}
1203
1212
1204
1213
1205
- 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 ) {
1206
- dir_node_avl * avl = nil ;
1207
- dir_node * node = nil ;
1208
- uint16_t l_offset , r_offset ;
1214
+ 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 ) {
1215
+ dir_node_avl * avl = nil ;
1216
+ dir_node * node = nil ;
1217
+ uint16_t l_offset = 0 , r_offset = 0 ;
1209
1218
int err = 0 ;
1210
1219
1211
- if (lseek ( in_xiso , in_dir_start + ( xoff_t ) entry_offset * XISO_DWORD_SIZE , SEEK_SET ) == -1 ) seek_err ( );
1220
+ if (entry_offset >= end_offset ) misc_err ( "attempt to read node entry beyond directory end" );
1212
1221
1213
- if (!err && read (in_xiso , & l_offset , XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) read_err ();
1214
- if (!err && l_offset == XISO_PAD_SHORT ) {
1215
- if (entry_offset == 0 ) { // Empty directory
1216
- if (in_mode == k_generate_avl ) err = (avl_insert (in_root , EMPTY_SUBDIRECTORY ) == k_avl_error );
1217
- }
1218
- else {
1219
- exiso_warn ("Invalid node found and skipped!" );
1222
+ do {
1223
+ if (!err && lseek (in_xiso , in_dir_start + (xoff_t )entry_offset * XISO_DWORD_SIZE , SEEK_SET ) == -1 ) seek_err ();
1224
+
1225
+ if (!err && read (in_xiso , & l_offset , XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) read_err ();
1226
+ if (!err && l_offset == XISO_PAD_SHORT ) {
1227
+ if (entry_offset == 0 ) { // Empty directories have padding starting at the beginning
1228
+ if (in_mode == k_generate_avl ) err = (avl_insert (in_root , EMPTY_SUBDIRECTORY ) == k_avl_error );
1229
+ return err ; // Done
1230
+ }
1231
+ else if (strategy != discover_strategy ) { // When discovering, the padding means end of sector
1232
+ exiso_warn ("Invalid node found and skipped!" ); // When not discovering, the padding means a bad entry, skip it without failing
1233
+ return err ; // We're done if not discovering
1234
+ }
1235
+ // We're discovering, so set the offset to the start of the next sector
1236
+ if (!err ) entry_offset = n_sectors (entry_offset * XISO_DWORD_SIZE ) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE ;
1237
+ continue ;
1220
1238
}
1221
- return err ;
1222
- }
1223
1239
1224
- // Read node
1225
- if (!err ) if ((node = calloc (1 , sizeof (dir_node ))) == nil ) mem_err ();
1226
- if (!err && read (in_xiso , & r_offset , XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) read_err ();
1227
- if (!err && read (in_xiso , & node -> start_sector , XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) read_err ();
1228
- if (!err && read (in_xiso , & node -> file_size , XISO_FILESIZE_SIZE ) != XISO_FILESIZE_SIZE ) read_err ();
1229
- if (!err && read (in_xiso , & node -> attributes , XISO_ATTRIBUTES_SIZE ) != XISO_ATTRIBUTES_SIZE ) read_err ();
1230
- if (!err && read (in_xiso , & node -> filename_length , XISO_FILENAME_LENGTH_SIZE ) != XISO_FILENAME_LENGTH_SIZE ) read_err ();
1240
+ // Read node
1241
+ if (!err ) if ((node = calloc (1 , sizeof (dir_node ))) == nil ) mem_err ();
1242
+ if (!err && read (in_xiso , & r_offset , XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) read_err ();
1243
+ if (!err && read (in_xiso , & node -> start_sector , XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) read_err ();
1244
+ if (!err && read (in_xiso , & node -> file_size , XISO_FILESIZE_SIZE ) != XISO_FILESIZE_SIZE ) read_err ();
1245
+ if (!err && read (in_xiso , & node -> attributes , XISO_ATTRIBUTES_SIZE ) != XISO_ATTRIBUTES_SIZE ) read_err ();
1246
+ if (!err && read (in_xiso , & node -> filename_length , XISO_FILENAME_LENGTH_SIZE ) != XISO_FILENAME_LENGTH_SIZE ) read_err ();
1231
1247
1232
- if (!err ) {
1233
- little16 (l_offset );
1234
- little16 (r_offset );
1235
- little32 (node -> file_size );
1236
- little32 (node -> start_sector );
1248
+ 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" );
1237
1249
1238
- if ((node -> filename = (char * )malloc (node -> filename_length + 1 )) == nil ) mem_err ();
1239
- }
1250
+ if (!err ) {
1251
+ little16 (l_offset );
1252
+ little16 (r_offset );
1253
+ little32 (node -> file_size );
1254
+ little32 (node -> start_sector );
1255
+
1256
+ if ((node -> filename = (char * )malloc (node -> filename_length + 1 )) == nil ) mem_err ();
1257
+ }
1240
1258
1241
- if (!err ) {
1242
- if (read (in_xiso , node -> filename , node -> filename_length ) != node -> filename_length ) read_err ();
1243
1259
if (!err ) {
1244
- node -> filename [node -> filename_length ] = 0 ;
1260
+ if (read (in_xiso , node -> filename , node -> filename_length ) != node -> filename_length ) read_err ();
1261
+ if (!err ) {
1262
+ node -> filename [node -> filename_length ] = 0 ;
1245
1263
1246
- // security patch (Chris Bainbridge), modified by in to support "...", etc. 02.14.06 (in)
1247
- if (!strcmp (node -> filename , "." ) || !strcmp (node -> filename , ".." ) || strchr (node -> filename , '/' ) || strchr (node -> filename , '\\' )) {
1248
- log_err (__FILE__ , __LINE__ , "filename '%s' contains invalid character(s), aborting." , node -> filename );
1249
- exit (1 );
1264
+ // security patch (Chris Bainbridge), modified by in to support "...", etc. 02.14.06 (in)
1265
+ if (!strcmp (node -> filename , "." ) || !strcmp (node -> filename , ".." ) || strchr (node -> filename , '/' ) || strchr (node -> filename , '\\' )) {
1266
+ log_err (__FILE__ , __LINE__ , "filename '%s' contains invalid character(s), aborting." , node -> filename );
1267
+ exit (1 );
1268
+ }
1250
1269
}
1251
1270
}
1252
- }
1253
1271
1254
- // Insert node in tree
1255
- if (!err && in_mode == k_generate_avl ) {
1256
- if ((avl = (dir_node_avl * )calloc (1 , sizeof (dir_node_avl ))) == nil ) mem_err ();
1257
- if (!err ) if ((avl -> filename = strdup (node -> filename )) == nil ) mem_err ();
1272
+ // Process the node according to the mode
1258
1273
if (!err ) {
1259
- avl -> file_size = node -> file_size ;
1260
- avl -> old_start_sector = node -> start_sector ;
1261
- if (avl_insert (in_root , avl ) == k_avl_error ) misc_err ("this iso appears to be corrupt" );
1274
+ if (in_mode == k_generate_avl ) {
1275
+ if ((avl = (dir_node_avl * )calloc (1 , sizeof (dir_node_avl ))) == nil ) mem_err ();
1276
+ if (!err ) if ((avl -> filename = strdup (node -> filename )) == nil ) mem_err ();
1277
+ if (!err ) {
1278
+ avl -> file_size = node -> file_size ;
1279
+ avl -> old_start_sector = node -> start_sector ;
1280
+ if (avl_insert (in_root , avl ) == k_avl_error ) { // Insert node in tree
1281
+ // If we're discovering files outside trees, we don't care about avl_insert errors,
1282
+ // since they represent nodes already discovered before, and we don't want to process them again
1283
+ if (strategy != discover_strategy ) misc_err ("this iso appears to be corrupt" );
1284
+ }
1285
+ else err = process_node (in_xiso , node , in_path , in_mode , & avl -> subdirectory , strategy );
1286
+ }
1287
+ }
1288
+ else {
1289
+ err = process_node (in_xiso , node , in_path , in_mode , nil , strategy );
1290
+ }
1262
1291
}
1263
- }
1264
1292
1265
- // Process the node, according to mode
1266
- if (!err ) err = process_node ( in_xiso , node , in_path , in_mode , ( in_mode == k_generate_avl ) ? & avl -> subdirectory : nil );
1293
+ // Save next offset for discovery
1294
+ if (!err ) entry_offset = n_dword ( entry_offset * XISO_DWORD_SIZE + XISO_FILENAME_OFFSET + node -> filename_length );
1267
1295
1268
- // Free memory before recurring
1269
- if (node ) {
1270
- if (node -> filename ) free (node -> filename );
1271
- free (node );
1272
- }
1296
+ // Free memory before recurring or iterating
1297
+ if (node ) {
1298
+ if (node -> filename ) free (node -> filename );
1299
+ free (node );
1300
+ }
1273
1301
1274
- // Repeat on left node
1275
- if (!err && l_offset ) {
1276
- if (!err ) if (lseek (in_xiso , in_dir_start + (xoff_t )l_offset * XISO_DWORD_SIZE , SEEK_SET ) == -1 ) seek_err ();
1277
- if (!err ) err = traverse_xiso (in_xiso , in_dir_start , l_offset , in_path , in_mode , & avl );
1278
- }
1302
+ } while (!err && entry_offset < end_offset && strategy == discover_strategy ); // Iterate only if using discover_strategy
1303
+
1304
+ if (strategy != discover_strategy ) {
1305
+ // Recurse on left node
1306
+ if (!err && l_offset ) {
1307
+ if (lseek (in_xiso , in_dir_start + (xoff_t )l_offset * XISO_DWORD_SIZE , SEEK_SET ) == -1 ) seek_err ();
1308
+ if (!err ) err = traverse_xiso (in_xiso , in_dir_start , l_offset , end_offset , in_path , in_mode , & avl , strategy );
1309
+ }
1279
1310
1280
- // Repeat on right node
1281
- if (!err && r_offset ) {
1282
- if (!err ) if (lseek (in_xiso , in_dir_start + (xoff_t )r_offset * XISO_DWORD_SIZE , SEEK_SET ) == -1 ) seek_err ();
1283
- if (!err ) err = traverse_xiso (in_xiso , in_dir_start , r_offset , in_path , in_mode , & avl );
1311
+ // Recurse on right node
1312
+ if (!err && r_offset ) {
1313
+ if (lseek (in_xiso , in_dir_start + (xoff_t )r_offset * XISO_DWORD_SIZE , SEEK_SET ) == -1 ) seek_err ();
1314
+ if (!err ) err = traverse_xiso (in_xiso , in_dir_start , r_offset , end_offset , in_path , in_mode , & avl , strategy );
1315
+ }
1284
1316
}
1285
1317
1286
1318
return err ;
1287
1319
}
1288
1320
1289
- int process_node (int in_xiso , dir_node * node , char * in_path , modes in_mode , dir_node_avl * * in_root ) {
1290
- char * path = nil ;
1291
- int err = 0 ;
1321
+ int process_node (int in_xiso , dir_node * node , char * in_path , modes in_mode , dir_node_avl * * in_root , strategies strategy ) {
1322
+ char * path = nil ;
1323
+ int err = 0 ;
1324
+ xoff_t dir_start = (xoff_t )node -> start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek ;
1325
+ uint16_t end_offset ;
1292
1326
1293
1327
if (node -> attributes & XISO_ATTRIBUTE_DIR ) { // Process directory
1294
1328
1295
- if (!err ) if (lseek (in_xiso , ( xoff_t ) node -> start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek , SEEK_SET ) == -1 ) seek_err ();
1329
+ if (!err ) if (lseek (in_xiso , dir_start , SEEK_SET ) == -1 ) seek_err ();
1296
1330
1297
1331
if (!err ) {
1298
1332
if (!s_remove_systemupdate || !strstr (node -> filename , s_systemupdate ))
@@ -1309,16 +1343,19 @@ int process_node(int in_xiso, dir_node* node, char* in_path, modes in_mode, dir_
1309
1343
1310
1344
if (!err ) {
1311
1345
// Recurse on subdirectory
1312
- if (in_path ) if (asprintf (& path , "%s%s%c" , in_path , node -> filename , PATH_CHAR ) == -1 ) mem_err ();
1313
- 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 );
1346
+ if (!err && node -> file_size > 0 ) {
1347
+ if (in_path ) if (asprintf (& path , "%s%s%c" , in_path , node -> filename , PATH_CHAR ) == -1 ) mem_err ();
1348
+ end_offset = n_sectors (node -> file_size ) * XISO_SECTOR_SIZE / XISO_DWORD_SIZE ;
1349
+ err = traverse_xiso (in_xiso , dir_start , 0 , end_offset , path , in_mode , in_root , strategy );
1350
+ if (path ) free (path );
1351
+ }
1314
1352
1315
1353
if (!s_remove_systemupdate || !strstr (node -> filename , s_systemupdate ))
1316
1354
{
1317
1355
if (!err && in_mode == k_extract && (err = chdir (".." ))) chdir_err (".." );
1318
1356
}
1319
1357
}
1320
-
1321
- if (path ) free (path );
1358
+
1322
1359
}
1323
1360
else if (in_mode != k_generate_avl ) { // Write file
1324
1361
if (!err ) {
@@ -1605,19 +1642,17 @@ char *boyer_moore_search( char *in_text, long in_text_len ) {
1605
1642
int extract_file ( int in_xiso , dir_node * in_file , modes in_mode , char * path ) {
1606
1643
int err = 0 ;
1607
1644
bool warn = false;
1645
+ xoff_t file_start = (xoff_t )in_file -> start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek ;
1608
1646
uint32_t i , size , read_size , totalsize = 0 ;
1609
1647
float totalpercent = 0.0f ;
1610
1648
int out ;
1611
1649
1612
- if ( s_remove_systemupdate && strstr ( path , s_systemupdate ) ){
1613
- if ( ! err && lseek ( in_xiso , (xoff_t ) in_file -> start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek , SEEK_SET ) == -1 ) seek_err ();
1614
- }
1615
- else {
1650
+ if (lseek (in_xiso , file_start , SEEK_SET ) == -1 ) seek_err ();
1651
+
1652
+ if ( !s_remove_systemupdate || !strstr ( path , s_systemupdate ) ) {
1616
1653
if ( in_mode == k_extract ) {
1617
- if ( ( out = open ( in_file -> filename , WRITEFLAGS , 0644 ) ) == -1 ) open_err ( in_file -> filename );
1654
+ if (! err && ( out = open (in_file -> filename , WRITEFLAGS , 0644 ) ) == -1 ) open_err (in_file -> filename );
1618
1655
} else err = 1 ;
1619
-
1620
- if ( ! err && lseek ( in_xiso , (xoff_t ) in_file -> start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek , SEEK_SET ) == -1 ) seek_err ();
1621
1656
1622
1657
if ( ! err ) {
1623
1658
exiso_log ("\n" );
@@ -1812,11 +1847,13 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep
1812
1847
1813
1848
1814
1849
int write_directory ( dir_node_avl * in_avl , write_tree_context * in_context , int in_depth ) {
1815
- xoff_t pos ;
1816
- int err = 0 , pad ;
1817
- uint16_t l_offset , r_offset ;
1818
- 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 );
1819
- char length = (char ) strlen ( in_avl -> filename ), attributes = in_avl -> subdirectory ? XISO_ATTRIBUTE_DIR : XISO_ATTRIBUTE_ARC , sector [ XISO_SECTOR_SIZE ];
1850
+ xoff_t pos ;
1851
+ int err = 0 , pad ;
1852
+ uint16_t l_offset , r_offset ;
1853
+ 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 );
1854
+ char length = (char )strlen (in_avl -> filename );
1855
+ char attributes = in_avl -> subdirectory ? XISO_ATTRIBUTE_DIR : XISO_ATTRIBUTE_ARC ;
1856
+ char sector [XISO_SECTOR_SIZE ];
1820
1857
1821
1858
little32 ( in_avl -> file_size );
1822
1859
little32 ( in_avl -> start_sector );
0 commit comments