@@ -26,7 +26,7 @@ class ISOManager:
2626 (["macos" , "osx" , "mac_os" , "apple" , "hackintosh" ,
2727 "catalina" , "mojave" , "sierra" , "monterey" , "ventura" ,
2828 "sonoma" ], "macOS" ),
29- (["freedos" , "msdos" , "ms-dos" , "dos" ], "FreeDOS" ),
29+ (["freedos" , "fd" , " msdos" , "ms-dos" , "dos" ], "FreeDOS" ),
3030 ]
3131
3232 _CONTENT_SIGNATURES : Dict [str , list ] = {
@@ -87,14 +87,94 @@ def get_iso_info(self, iso_path: str) -> Dict[str, Any]:
8787 else f"{ size_mb :.2f} MB"
8888 )
8989 iso_type = self ._determine_iso_type (iso_path )
90+ is_hybrid = self ._is_hybrid_iso (iso_path )
91+ label = self ._read_volume_label (iso_path )
92+ has_efi = self ._has_efi_boot (iso_path )
9093
91- return {
94+ info = {
9295 "path" : iso_path ,
9396 "filename" : os .path .basename (iso_path ),
9497 "size_bytes" : size_bytes ,
9598 "size" : size_str ,
9699 "type" : iso_type ,
100+ "is_hybrid" : is_hybrid ,
101+ "has_efi" : has_efi ,
102+ "persistence_capable" : iso_type == "Linux" ,
103+ "recommended_fs" : self ._recommend_fs (iso_type , has_efi , size_mb / 1024 ),
104+ "recommended_scheme" : "GPT" if has_efi else "MBR" ,
105+ "min_usb_bytes" : size_bytes ,
97106 }
107+ if label :
108+ info ["label" ] = label
109+
110+ # Add to history
111+ self .add_to_history (iso_path )
112+
113+ return info
114+
115+ def _has_efi_boot (self , iso_path : str ) -> bool :
116+ """Check if ISO has EFI boot support."""
117+ try :
118+ if self .system == "Windows" :
119+ return self ._check_windows_efi (iso_path )
120+ elif self .system in ("Linux" , "Darwin" ):
121+ return self ._check_unix_efi (iso_path )
122+ return False
123+ except Exception :
124+ return False
125+
126+ def _check_windows_efi (self , iso_path : str ) -> bool :
127+ """Check for EFI boot on Windows."""
128+ script = (
129+ f"$m = Mount-DiskImage -ImagePath '{ iso_path } ' -PassThru;"
130+ "$dl = ($m | Get-Volume).DriveLetter; $dl"
131+ )
132+ try :
133+ result = subprocess .run (
134+ ["powershell" , "-NoProfile" , "-Command" , script ],
135+ capture_output = True , text = True , timeout = 15
136+ )
137+ drive = result .stdout .strip ()
138+ if not drive :
139+ return False
140+ root = drive + ":\\ "
141+ efi_path = os .path .join (root , "EFI" )
142+ has_efi = os .path .exists (efi_path )
143+ subprocess .run (
144+ ["powershell" , "-NoProfile" , "-Command" ,
145+ f"Dismount-DiskImage -ImagePath '{ iso_path } '" ],
146+ capture_output = True , timeout = 8
147+ )
148+ return has_efi
149+ except Exception :
150+ return False
151+
152+ def _check_unix_efi (self , iso_path : str ) -> bool :
153+ """Check for EFI boot on Unix-like systems."""
154+ import tempfile
155+ mount_point = tempfile .mkdtemp (prefix = "smartboot_iso_" )
156+ try :
157+ result = subprocess .run (
158+ ["sudo" , "mount" , "-o" , "loop,ro" , iso_path , mount_point ],
159+ capture_output = True , timeout = 10
160+ )
161+ if result .returncode != 0 :
162+ return False
163+ try :
164+ efi_path = os .path .join (mount_point , "EFI" )
165+ return os .path .exists (efi_path )
166+ finally :
167+ subprocess .run (
168+ ["sudo" , "umount" , mount_point ],
169+ capture_output = True , timeout = 8
170+ )
171+ except Exception :
172+ return False
173+ finally :
174+ try :
175+ os .rmdir (mount_point )
176+ except OSError :
177+ pass
98178
99179 def validate_iso (self , iso_path : str ) -> bool :
100180 """
@@ -207,7 +287,7 @@ def _determine_iso_type(self, iso_path: str) -> str:
207287 return "Windows (likely)"
208288 if size_gb > 4.5 :
209289 return "Unknown (large ISO)"
210- return "Unknown (small ISO) "
290+ return "Generic "
211291
212292 def _detect_by_content (self , iso_path : str ) -> Optional [str ]:
213293 """Mount the ISO (platform-specific) and inspect contents."""
@@ -311,4 +391,80 @@ def _validate_windows_mount(self, iso_path: str) -> bool:
311391 )
312392 return found
313393 except Exception :
314- return False
394+ return False
395+
396+ @staticmethod
397+ def _format_size (size_bytes : int ) -> str :
398+ """Format size in bytes to human-readable string."""
399+ size_mb = size_bytes / (1024 * 1024 )
400+ if size_mb >= 1024 :
401+ return f"{ size_mb / 1024 :.2f} GB"
402+ return f"{ size_mb :.2f} MB"
403+
404+ def _is_hybrid_iso (self , iso_path : str ) -> bool :
405+ """Check if ISO is hybrid (has both BIOS and UEFI boot)."""
406+ try :
407+ with open (iso_path , "rb" ) as f :
408+ f .seek (0 )
409+ # Check for MBR signature
410+ mbr_sig = f .read (2 )
411+ if mbr_sig != b"\x55 \xAA " :
412+ return False
413+ # Check for ISO 9660 signature
414+ f .seek (0x8001 )
415+ iso_sig = f .read (5 )
416+ return iso_sig == b"CD001"
417+ except OSError :
418+ return False
419+
420+ def _read_volume_label (self , iso_path : str ) -> str :
421+ """Read volume label from ISO."""
422+ try :
423+ with open (iso_path , "rb" ) as f :
424+ f .seek (0x8028 ) # Volume descriptor location
425+ label = f .read (32 ).decode ('utf-8' , errors = 'ignore' ).strip ('\x00 ' )
426+ return label or ""
427+ except OSError :
428+ return ""
429+
430+ @staticmethod
431+ def _recommend_fs (iso_type : str , has_efi : bool , size_gb : float ) -> str :
432+ """Recommend filesystem based on ISO type and size."""
433+ if iso_type == "Windows" :
434+ if size_gb > 32 :
435+ return "NTFS"
436+ return "FAT32"
437+ elif iso_type == "Linux" :
438+ if has_efi :
439+ return "FAT32"
440+ return "FAT32"
441+ elif iso_type == "macOS" :
442+ return "HFS+"
443+ elif iso_type == "FreeDOS" :
444+ return "FAT32"
445+ return "FAT32"
446+
447+ def compute_checksum (self , iso_path : str , algorithm : str = "sha256" , progress_callback = None ) -> str :
448+ """Compute checksum of ISO file."""
449+ import hashlib
450+ try :
451+ hash_func = getattr (hashlib , algorithm .lower ())
452+ except AttributeError :
453+ return ""
454+
455+ with open (iso_path , "rb" ) as f :
456+ hash_obj = hash_func ()
457+ total_size = os .path .getsize (iso_path )
458+ bytes_read = 0
459+ while chunk := f .read (8192 ):
460+ hash_obj .update (chunk )
461+ bytes_read += len (chunk )
462+ if progress_callback :
463+ progress = int ((bytes_read / total_size ) * 100 )
464+ progress_callback (progress , f"Computing { algorithm } checksum…" )
465+ return hash_obj .hexdigest ()
466+
467+ def verify_checksum (self , iso_path : str , expected : str , algorithm : str = "sha256" ) -> bool :
468+ """Verify ISO checksum matches expected value."""
469+ computed = self .compute_checksum (iso_path , algorithm )
470+ return computed .lower () == expected .lower ()
0 commit comments