18
18
from __future__ import annotations
19
19
20
20
import argparse
21
+ import copy
21
22
import logging
22
23
import os
23
24
import sys
@@ -290,6 +291,82 @@ def encode_string(args: argparse.Namespace) -> int:
290
291
return 0
291
292
292
293
294
+ def check_extension (args ):
295
+ args_copy = copy .copy (args )
296
+ args_copy .dryrun = True
297
+ extensions = ['joliet' , 'rr' , 'udf' ]
298
+ args_copy .dir = args .dir .joinpath ('test' )
299
+ args_copy .fs = 'iso9660'
300
+ args .silent = True
301
+ for extension in extensions :
302
+ args_copy .extension = extension
303
+ try :
304
+ extract_volume_iso (args_copy )
305
+ except Exception as e :
306
+ pass
307
+ else :
308
+ return extension
309
+
310
+
311
+ def check_fs (iso ):
312
+ APPLE_PM_SIGNATURE = b"PM\x00 \x00 "
313
+ SECTOR_SIZE = 512
314
+
315
+ disk_formats = []
316
+ f = open (iso , "rb" )
317
+
318
+ # ISO Primary Volume Descriptor
319
+ f .seek (64 * SECTOR_SIZE )
320
+ if f .read (6 ) == b"\x01 CD001" :
321
+ # print('Found ISO PVD')
322
+ disk_formats .append ("iso9660" )
323
+
324
+ f .seek (0 )
325
+ mac_1 = f .read (4 )
326
+ f .seek (1 * SECTOR_SIZE )
327
+ mac_2 = f .read (4 )
328
+ f .seek (2 * SECTOR_SIZE )
329
+ mac_3 = f .read (2 )
330
+ if mac_2 == APPLE_PM_SIGNATURE :
331
+ partition_num = 1
332
+ while True :
333
+ num_partitions , partition_start , partition_size = unpack (">III" , f .read (12 ))
334
+ f .seek (32 , 1 )
335
+ partition_type = f .read (32 ).decode ("mac-roman" ).split ("\x00 " )[0 ]
336
+ if partition_type == "Apple_HFS" :
337
+ disk_formats .append ("hfs" )
338
+ break
339
+ # Check if there are more partitions
340
+ if partition_num <= num_partitions :
341
+ # Move onto the next partition
342
+ partition_num += 1
343
+ f .seek (partition_num * SECTOR_SIZE + 4 )
344
+ # Bootable Mac-only disc
345
+ elif mac_1 == b"LK\x60 \x00 " and mac_3 == b"BD" :
346
+ disk_formats .append ("hfs" )
347
+
348
+ if len (disk_formats ) > 1 :
349
+ return 'hybrid'
350
+ else :
351
+ return disk_formats [0 ]
352
+
353
+
354
+ def extract_iso (args : argparse .Namespace ):
355
+ if not args .fs :
356
+ args .fs = check_fs (args .src )
357
+ print ('Detected filesystem:' , args .fs )
358
+ if (args .fs == 'hybrid' or args .fs == 'iso9660' ) and not args .extension :
359
+ args .extension = check_extension (args )
360
+ print ('Detected extension:' , args .extension )
361
+
362
+ if args .fs == 'iso9660' :
363
+ extract_volume_iso (args )
364
+ elif args .fs == 'hfs' :
365
+ extract_volume_hfs (args )
366
+ else :
367
+ extract_volume_hybrid (args )
368
+
369
+
293
370
def extract_volume_hfs (args : argparse .Namespace ) -> int :
294
371
"""Extract an HFS volume"""
295
372
source_volume : Path = args .src
@@ -381,15 +458,15 @@ def extract_volume_iso(args: argparse.Namespace):
381
458
joined_path = os .path .join (pwd , dir )
382
459
if not dryrun :
383
460
os .makedirs (joined_path , exist_ok = True )
384
- else :
461
+ elif not args . silent :
385
462
print (joined_path )
386
463
387
464
if dryrun :
388
465
continue
389
466
390
467
for file in filelist :
391
468
filename = file .split (';' )[0 ]
392
- iso_file_path = os .path .join (dirname , filename )
469
+ iso_file_path = os .path .join (dirname , file )
393
470
with open (os .path .join (pwd , filename ), 'wb' ) as f :
394
471
arg [path_type ] = iso_file_path
395
472
iso .get_file_from_iso_fp (outfp = f , ** arg )
@@ -409,15 +486,13 @@ def extract_volume_hybrid(args: argparse.Namespace):
409
486
410
487
logging .info (f"Loading { source_volume } ..." )
411
488
412
- if not args .macdump and not args .iso9660dump :
413
- logging .error ("Please provide at least one dump for the hybrid drive" )
414
- return
415
- if args .macdump :
416
- args .dir = args .macdump
417
- extract_volume_hfs (args )
418
- if args .iso9660dump :
419
- args .dir = args .iso9660dump
420
- extract_volume_iso (args )
489
+ main_dir = args .dir
490
+
491
+ args .dir = main_dir .joinpath ('hfs' )
492
+ extract_volume_hfs (args )
493
+
494
+ args .dir = main_dir .joinpath ('iso9660' )
495
+ extract_volume_iso (args )
421
496
422
497
423
498
def extract_partition (args : argparse .Namespace , vol ) -> int :
@@ -811,91 +886,39 @@ def generate_parser() -> argparse.ArgumentParser:
811
886
"""
812
887
parser = argparse .ArgumentParser ()
813
888
subparsers = parser .add_subparsers ()
814
- parser_hfs = subparsers .add_parser ("hfs " , help = "Dump HFS ISOs" )
889
+ parser_iso = subparsers .add_parser ("iso " , help = "Dump HFS ISOs" )
815
890
816
- parser_hfs .add_argument ("src" , metavar = "INPUT" , type = Path , help = "Disk image" )
817
- parser_hfs .add_argument (
891
+ parser_iso .add_argument ("src" , metavar = "INPUT" , type = Path , help = "Disk image" )
892
+ parser_iso .add_argument (
818
893
"--nopunycode" , action = "store_true" , help = "never encode pathnames into punycode"
819
894
)
820
- parser_hfs .add_argument (
895
+ parser_iso .add_argument (
821
896
"--japanese" , action = "store_true" , help = "read MacJapanese HFS"
822
897
)
823
- parser_hfs .add_argument (
898
+ parser_iso .add_argument (
824
899
"--dryrun" , action = "store_true" , help = "do not write any files"
825
900
)
826
- parser_hfs .add_argument (
901
+ parser_iso .add_argument (
827
902
"--log" , metavar = "LEVEL" , help = "set logging level" , default = "INFO"
828
903
)
829
- parser_hfs .add_argument (
904
+ parser_iso .add_argument (
830
905
"--forcemacbinary" ,
831
906
action = "store_true" ,
832
907
help = "always encode using MacBinary, even for files with no resource fork" ,
833
908
)
834
- parser_hfs .add_argument (
909
+ parser_iso .add_argument (
835
910
"--addmacbinaryext" ,
836
911
action = "store_true" ,
837
912
help = "add .bin extension when using MacBinary" ,
838
913
)
839
- parser_hfs .add_argument (
840
- "dir" , metavar = "OUTPUT" , type = Path , help = "Destination folder"
841
- )
842
- parser_hfs .set_defaults (func = extract_volume_hfs )
843
-
844
- parser_iso9660 = subparsers .add_parser (
845
- "iso9660" , help = "Dump ISO9660 ISOs"
846
- )
847
- parser_iso9660 .add_argument (
848
- "--log" , metavar = "LEVEL" , help = "set logging level" , default = "INFO"
849
- )
850
- parser_iso9660 .add_argument ("--extension" , choices = ['joliet' , 'rr' , 'udf' ], metavar = "EXTENSION" , help = "Use if the iso9660 has an extension" )
851
- parser_iso9660 .add_argument (
852
- "--nopunycode" , action = "store_true" , help = "never encode pathnames into punycode"
853
- )
854
- parser_iso9660 .add_argument (
855
- "--dryrun" , action = "store_true" , help = "do not write any files"
856
- )
857
- parser_iso9660 .add_argument (
858
- "--japanese" , action = "store_true" , help = "read MacJapanese HFS"
859
- )
860
- parser_iso9660 .add_argument ("src" , metavar = "INPUT" , type = Path , help = "Disk image" )
861
- parser_iso9660 .add_argument (
914
+ parser_iso .add_argument ("--extension" , choices = ['joliet' , 'rr' , 'udf' ], metavar = "EXTENSION" ,
915
+ help = "Use if the iso9660 has an extension" )
916
+ parser_iso .add_argument ("--fs" , choices = ['iso9660' , 'hfs' , 'hybrid' ], metavar = "FILE_SYSTEM" ,
917
+ help = "Specify the file system of the ISO" )
918
+ parser_iso .add_argument (
862
919
"dir" , metavar = "OUTPUT" , type = Path , help = "Destination folder"
863
920
)
864
- parser_iso9660 .set_defaults (func = extract_volume_iso )
865
-
866
- parser_hybrid = subparsers .add_parser (
867
- "hybrid" , help = "Dump Hybrid ISOs"
868
- )
869
- parser_hybrid .add_argument ("src" , metavar = "INPUT" , type = Path , help = "Disk image" )
870
- parser_hybrid .add_argument (
871
- "--nopunycode" , action = "store_true" , help = "never encode pathnames into punycode"
872
- )
873
- parser_hybrid .add_argument (
874
- "--japanese" , action = "store_true" , help = "read MacJapanese HFS"
875
- )
876
- parser_hybrid .add_argument (
877
- "--dryrun" , action = "store_true" , help = "do not write any files"
878
- )
879
- parser_hybrid .add_argument (
880
- "--log" , metavar = "LEVEL" , help = "set logging level" , default = "INFO"
881
- )
882
- parser_hybrid .add_argument (
883
- "--forcemacbinary" ,
884
- action = "store_true" ,
885
- help = "always encode using MacBinary, even for files with no resource fork" ,
886
- )
887
- parser_hybrid .add_argument (
888
- "--addmacbinaryext" ,
889
- action = "store_true" ,
890
- help = "add .bin extension when using MacBinary" ,
891
- )
892
- parser_hybrid .add_argument (
893
- "--macdump" , metavar = "OUTPUT" , type = Path , help = "Destination Folder for HFS Dump"
894
- )
895
- parser_hybrid .add_argument (
896
- "--iso9660dump" , metavar = "OUTPUT" , type = Path , help = "Destination Folder for ISO9660 Dump"
897
- )
898
- parser_hybrid .set_defaults (func = extract_volume_hybrid )
921
+ parser_iso .set_defaults (func = extract_iso )
899
922
900
923
parser_dir = subparsers .add_parser (
901
924
"dir" , help = "Punyencode all files and dirs in place"
0 commit comments