Пример #1
0
    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
Пример #2
0
    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)
Пример #3
0
    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
Пример #4
0
    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
Пример #5
0
    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
Пример #6
0
    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)
Пример #7
0
    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
Пример #8
0
    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
Пример #9
0
    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
Пример #10
0
    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
Пример #11
0
    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
Пример #12
0
    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()
Пример #13
0
    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
Пример #14
0
    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
Пример #15
0
    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
Пример #16
0
    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]
Пример #17
0
    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)
Пример #18
0
    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))
Пример #19
0
    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
Пример #20
0
    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)
Пример #21
0
    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
Пример #22
0
    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)
Пример #23
0
    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
Пример #24
0
    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)
Пример #25
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)
Пример #26
0
    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
Пример #27
0
    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()
Пример #28
0
    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
Пример #29
0
    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
Пример #30
0
    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