def new(self, br, ino, sector_count, load_seg, media_name, system_type, platform_id, bootable): # type: (headervd.BootRecord, inode.Inode, int, int, str, int, int, bool) -> None ''' A method to create a new El Torito Boot Catalog. Parameters: br - The boot record that this El Torito Boot Catalog is associated with. ino - The Inode to associate with the initial entry. sector_count - The number of sectors for the initial entry. load_seg - The load segment address of the boot image. media_name - The name of the media type, one of 'noemul', 'floppy', or 'hdemul'. system_type - The partition type the entry should be. platform_id - The platform id to set in the validation entry. bootable - Whether this entry should be bootable. Returns: Nothing. ''' if self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Boot Catalog already initialized') # Create the El Torito validation entry self.validation_entry.new(platform_id) self.initial_entry.new(sector_count, load_seg, media_name, system_type, bootable) self.initial_entry.set_inode(ino) ino.linked_records.append(self.initial_entry) self.br = br self._initialized = True
def record(self, iso_size): # type: (int) -> bytes ''' A method to generate a string containing the ISO hybridization. Parameters: iso_size - The size of the ISO, excluding the hybridization. Returns: A string containing the ISO hybridization. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'This IsoHybrid object is not yet initialized') outlist = [ struct.pack('=32s400sLLLH', self.header, self.mbr, self.rba, 0, self.mbr_id, 0) ] for i in range(1, 5): if i == self.part_entry: cc, padding_unused = self._calc_cc(iso_size) esect = self.geometry_sectors + (((cc - 1) & 0x300) >> 2) ecyle = (cc - 1) & 0xff psize = cc * self.geometry_heads * self.geometry_sectors - self.part_offset outlist.append( struct.pack('=BBBBBBBBLL', 0x80, self.bhead, self.bsect, self.bcyle, self.ptype, self.ehead, esect, ecyle, self.part_offset, psize)) else: outlist.append(b'\x00' * 16) outlist.append(b'\x55\xaa') return b''.join(outlist)
def parse(self, vd, datastr, ino): # type: (headervd.PrimaryOrSupplementaryVD, bytes, inode.Inode) -> bool ''' A method to parse a boot info table out of a string. Parameters: vd - The Volume Descriptor associated with this Boot Info Table. datastr - The string to parse the boot info table out of. ino - The Inode associated with the boot file. Returns: True if this is a valid El Torito Boot Info Table, False otherwise. ''' if self._initialized: raise pycdlibexception.PyCdlibInternalError( 'This Eltorito Boot Info Table is already initialized') (pvd_extent, rec_extent, self.orig_len, self.csum) = struct.unpack_from('=LLLL', datastr, 0) if pvd_extent != vd.extent_location( ) or rec_extent != ino.extent_location(): return False self.vd = vd self.inode = ino self._initialized = True return True
def new(self): # type: () -> None ''' Create a new Directory Record date based on the current time. Parameters: tm - An optional argument that must be None Returns: Nothing. ''' if self._initialized: raise pycdlibexception.PyCdlibInternalError( 'Directory Record Date already initialized') # This algorithm was ported from cdrkit, genisoimage.c:iso9660_date() tm = time.time() local = time.localtime(tm) self.years_since_1900 = local.tm_year - 1900 self.month = local.tm_mon self.day_of_month = local.tm_mday self.hour = local.tm_hour self.minute = local.tm_min self.second = local.tm_sec self.gmtoffset = utils.gmtoffset_from_tm(tm, local) self._initialized = True
def new(self, sector_count, load_seg, media_name, system_type, bootable): # type: (int, int, str, int, bool) -> None ''' A method to create a new El Torito Entry. Parameters: sector_count - The number of sectors to assign to this El Torito Entry. load_seg - The load segment address of the boot image. media_name - The name of the media type, one of 'noemul', 'floppy', or 'hdemul'. system_type - The partition type to assign to the entry. bootable - Whether this entry is bootable. Returns: Nothing. ''' if self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Entry already initialized') if media_name == 'noemul': media_type = self.MEDIA_NO_EMUL elif media_name == 'floppy': if sector_count == 2400: media_type = self.MEDIA_12FLOPPY elif sector_count == 2880: media_type = self.MEDIA_144FLOPPY elif sector_count == 5760: media_type = self.MEDIA_288FLOPPY else: raise pycdlibexception.PyCdlibInvalidInput( 'Invalid sector count for floppy media type; must be 2400, 2880, or 5760' ) # With floppy booting, the sector_count always ends up being 1 sector_count = 1 elif media_name == 'hdemul': media_type = self.MEDIA_HD_EMUL # With HD emul booting, the sector_count always ends up being 1 sector_count = 1 else: raise pycdlibexception.PyCdlibInvalidInput( "Invalid media name '%s'" % (media_name)) if bootable: self.boot_indicator = 0x88 else: self.boot_indicator = 0 self.boot_media_type = media_type self.load_segment = load_seg self.system_type = system_type self.sector_count = sector_count self.load_rba = 0 # This will get set later self.selection_criteria_type = 0 # FIXME: allow the user to set this self.selection_criteria = b''.ljust(19, b'\x00') self._initialized = True
def set_data_length(self, length): # type: (int) -> None ''' A method to set the length of data for this El Torito Entry. Parameters: length - The new length for the El Torito Entry. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Entry not initialized') self.sector_count = utils.ceiling_div(length, 512)
def set_inode(self, ino): # type: (inode.Inode) -> None ''' A method to set the Inode associated with this El Torito Entry. Parameters: ino - The Inode object corresponding to this entry. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Entry not yet initialized') self.inode = ino
def set_data_location(self, current_extent, tag_location): # pylint: disable=unused-argument # type: (int, int) -> None ''' A method to update the extent (and RBA) for this entry. Parameters: current_extent - The new extent to set for this entry. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Entry not yet initialized') self.load_rba = current_extent
def get_rba(self): # type: () -> int ''' A method to get the load_rba for this El Torito Entry. Parameters: None. Returns: The load RBA for this El Torito Entry. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Entry not yet initialized') return self.load_rba
def update_rba(self, current_extent): # type: (int) -> None ''' A method to update the current rba for the ISO hybridization. Parameters: current_extent - The new extent to set the RBA to. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'This IsoHybrid object is not yet initialized') self.rba = current_extent
def update_parent_directory_number(self, parent_dir_num): # type: (int) -> None ''' A method to update the parent directory number for this Path Table Record from the directory record. Parameters: parent_dir_num - The new parent directory number to assign to this PTR. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'Path Table Record not yet initialized') self.parent_directory_num = parent_dir_num
def extent_location(self): # type: () -> int ''' A method to get the extent location of this El Torito Boot Catalog. Parameters: None. Returns: Integer extent location of this El Torito Boot Catalog. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Boot Catalog not yet initialized') return self._extent_location()
def set_extent_location(self, extent): # type: (int) -> None ''' Set the current location of this Inode on the ISO. Parameters: extent - The new extent location for this Inode. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'Inode is not yet initialized') self.new_extent_loc = extent
def get_data_length(self): # type: () -> int ''' Get the length of the data pointed to by this Inode. Parameters: None. Returns: The length of the data pointed to by this Inode. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'Inode is not yet initialized') return self.data_length
def update_extent_location(self, extent_loc): # type: (int) -> None ''' A method to update the extent location for this Path Table Record. Parameters: extent_loc - The new extent location. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'Path Table Record not yet initialized') self.extent_location = extent_loc
def record_padding(self, iso_size): # type: (int) -> bytes ''' A method to record padding for the ISO hybridization. Parameters: iso_size - The size of the ISO, excluding the hybridization. Returns: A string of zeros the right size to pad the ISO. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'This IsoHybrid object is not yet initialized') return b'\x00' * self._calc_cc(iso_size)[1]
def new_root(self): # type: () -> None ''' A method to create a new root Path Table Record. Parameters: None. Returns: Nothing. ''' if self._initialized: raise pycdlibexception.PyCdlibInternalError( 'Path Table Record already initialized') self._new(b'\x00', 1)
def update_catalog_extent(self, current_extent): # type: (int) -> None ''' A method to update the extent associated with this Boot Catalog. Parameters: current_extent - New extent to associate with this Boot Catalog Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Boot Catalog not yet initialized') self.br.update_boot_system_use(struct.pack('=L', current_extent))
def record(self): # type: () -> bytes ''' Return the date string for this object. Parameters: None. Returns: Date as a string. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'This Volume Descriptor Date is not yet initialized') return self.date_str
def add_dirrecord(self, rec): # type: (Union[dr.DirectoryRecord, udfmod.UDFFileEntry]) -> None ''' A method to set the Directory Record associated with this Boot Catalog. Parameters: rec - The DirectoryRecord object to associate with this Boot Catalog. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Boot Catalog not yet initialized') self.dirrecords.append(rec)
def add_boot_info_table(self, boot_info_table): # type: (eltorito.EltoritoBootInfoTable) -> None ''' A method to add a boot info table to this Inode. Parameters: boot_info_table - The Boot Info Table object to add to this Inode. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'Inode is not yet initialized') self.boot_info_table = boot_info_table
def add_section(self, ino, sector_count, load_seg, media_name, system_type, efi, bootable): # type: (inode.Inode, int, int, str, int, bool, bool) -> None ''' A method to add an section header and entry to this Boot Catalog. Parameters: ino - The Inode object to associate with the new Entry. sector_count - The number of sectors to assign to the new Entry. load_seg - The load segment address of the boot image. media_name - The name of the media type, one of 'noemul', 'floppy', or 'hdemul'. system_type - The type of partition this entry should be. efi - Whether this section is an EFI section. bootable - Whether this entry should be bootable. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Boot Catalog not yet initialized') # The Eltorito Boot Catalog can only be 2048 bytes (1 extent). By # default, the first 64 bytes are used by the Validation Entry and the # Initial Entry, which leaves 1984 bytes. Each section takes up 32 # bytes for the Section Header and 32 bytes for the Section Entry, for # a total of 64 bytes, so we can have a maximum of 1984/64 = 31 # sections. if len(self.sections) == 31: raise pycdlibexception.PyCdlibInvalidInput( 'Too many Eltorito sections') sec = EltoritoSectionHeader() platform_id = self.validation_entry.platform_id if efi: platform_id = 0xef sec.new(b'\x00' * 28, platform_id) secentry = EltoritoEntry() secentry.new(sector_count, load_seg, media_name, system_type, bootable) secentry.set_inode(ino) ino.linked_records.append(secentry) sec.add_new_entry(secentry) if self.sections: self.sections[-1].set_record_not_last() self.sections.append(sec)
def set_record_not_last(self): # type: () -> None ''' A method to set this Section Header so that it is *not* the last one in the Boot Catalog; this is used when a new header is added. Parameters: None. Returns: Nothing. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Section Header not yet initialized') self.header_indicator = 0x90
def new_dir(self, name): # type: (bytes) -> None ''' A method to create a new Path Table Record. Parameters: name - The name for this Path Table Record. Returns: Nothing. ''' if self._initialized: raise pycdlibexception.PyCdlibInternalError( 'Path Table Record already initialized') # Zero for the parent dir num is bogus, but that will get fixed later. self._new(name, 0)
def record_little_endian(self): # type: () -> bytes ''' A method to generate a string representing the little endian version of this Path Table Record. Parameters: None. Returns: A string representing the little endian version of this Path Table Record. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'Path Table Record not yet initialized') return self._record(self.extent_location, self.parent_directory_num)
def length(self): # type: () -> int ''' A method to get the length, in bytes, of this El Torito Entry. Parameters: None. Returns: An integer representing the length in bytes of this El Torito Entry. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Entry not initialized') # According to El Torito, the sector count is in virtual sectors, which # are defined to be 512 bytes. return self.sector_count * 512
def record(self): # type: () -> bytes ''' A method to generate a string representing this El Torito Validation Entry. Parameters: None. Returns: String representing this El Torito Validation Entry. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'El Torito Validation Entry not yet initialized') return self._record()
def new(self, mac, part_entry, mbr_id, part_offset, geometry_sectors, geometry_heads, part_type): # type: (bool, int, Optional[int], int, int, int, int) -> None ''' A method to add ISO hybridization to an ISO. Parameters: mac - Whether this ISO should be made bootable for the Macintosh. part_entry - The partition entry for the hybridization. mbr_id - The mbr_id to use for the hybridization. part_offset - The partition offset to use for the hybridization. geometry_sectors - The number of sectors to use for the hybridization. geometry_heads - The number of heads to use for the hybridization. part_type - The partition type for the hybridization. Returns: Nothing. ''' if self._initialized: raise pycdlibexception.PyCdlibInternalError( 'This IsoHybrid object is already initialized') if mac: self.header = self.MAC_AFP else: self.header = self.ORIG_HEADER isohybrid_data_hd0 = b'\x33\xed\xfa\x8e\xd5\xbc\x00\x7c\xfb\xfc\x66\x31\xdb\x66\x31\xc9\x66\x53\x66\x51\x06\x57\x8e\xdd\x8e\xc5\x52\xbe\x00\x7c\xbf\x00\x06\xb9\x00\x01\xf3\xa5\xea\x4b\x06\x00\x00\x52\xb4\x41\xbb\xaa\x55\x31\xc9\x30\xf6\xf9\xcd\x13\x72\x16\x81\xfb\x55\xaa\x75\x10\x83\xe1\x01\x74\x0b\x66\xc7\x06\xf1\x06\xb4\x42\xeb\x15\xeb\x00\x5a\x51\xb4\x08\xcd\x13\x83\xe1\x3f\x5b\x51\x0f\xb6\xc6\x40\x50\xf7\xe1\x53\x52\x50\xbb\x00\x7c\xb9\x04\x00\x66\xa1\xb0\x07\xe8\x44\x00\x0f\x82\x80\x00\x66\x40\x80\xc7\x02\xe2\xf2\x66\x81\x3e\x40\x7c\xfb\xc0\x78\x70\x75\x09\xfa\xbc\xec\x7b\xea\x44\x7c\x00\x00\xe8\x83\x00\x69\x73\x6f\x6c\x69\x6e\x75\x78\x2e\x62\x69\x6e\x20\x6d\x69\x73\x73\x69\x6e\x67\x20\x6f\x72\x20\x63\x6f\x72\x72\x75\x70\x74\x2e\x0d\x0a\x66\x60\x66\x31\xd2\x66\x03\x06\xf8\x7b\x66\x13\x16\xfc\x7b\x66\x52\x66\x50\x06\x53\x6a\x01\x6a\x10\x89\xe6\x66\xf7\x36\xe8\x7b\xc0\xe4\x06\x88\xe1\x88\xc5\x92\xf6\x36\xee\x7b\x88\xc6\x08\xe1\x41\xb8\x01\x02\x8a\x16\xf2\x7b\xcd\x13\x8d\x64\x10\x66\x61\xc3\xe8\x1e\x00\x4f\x70\x65\x72\x61\x74\x69\x6e\x67\x20\x73\x79\x73\x74\x65\x6d\x20\x6c\x6f\x61\x64\x20\x65\x72\x72\x6f\x72\x2e\x0d\x0a\x5e\xac\xb4\x0e\x8a\x3e\x62\x04\xb3\x07\xcd\x10\x3c\x0a\x75\xf1\xcd\x18\xf4\xeb\xfd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' self.mbr = isohybrid_data_hd0 self.rba = 0 # This will be set later self.mbr_id = mbr_id if self.mbr_id is None: self.mbr_id = random.getrandbits(32) self.part_entry = part_entry self.bhead = (part_offset // geometry_sectors) % geometry_heads self.bsect = (part_offset % geometry_sectors) + 1 self.bcyle = part_offset // (geometry_heads * geometry_sectors) self.bsect += (self.bcyle & 0x300) >> 2 self.bcyle &= 0xff self.ptype = part_type self.ehead = geometry_heads - 1 self.part_offset = part_offset self.geometry_heads = geometry_heads self.geometry_sectors = geometry_sectors self._initialized = True
def extent_location(self): # type: () -> int ''' Get the current location of this Inode on the ISO. Parameters: None. Returns: The extent location of this Inode on the ISO. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'Inode is not yet initialized') if self.new_extent_loc < 0: return self.orig_extent_loc return self.new_extent_loc
def record(self): # type: () -> bytes ''' A method to generate a string representing this boot info table. Parameters: None. Returns: A string representing this boot info table. ''' if not self._initialized: raise pycdlibexception.PyCdlibInternalError( 'This Eltorito Boot Info Table not yet initialized') return struct.pack('=LLLL', self.vd.extent_location(), self.inode.extent_location(), self.orig_len, self.csum) + b'\x00' * 40