Esempio n. 1
0
  def _ReadFileHeader(self, file_object):
    """Reads the file header.

    Args:
      file_object: the file-like object to read from.

    Raises:
      FileFormatError: if file format related errors are detected.
    """
    file_object.seek(0, os.SEEK_SET)
    file_header = self._FILE_HEADER_STRUCT.parse_stream(file_object)
    self._compressed_data_offset = file_object.get_offset()

    if file_header.signature != self._FILE_SIGNATURE:
      raise errors.FileFormatError(
          u'Unsuppored file signature: 0x{0:04x}.'.format(
              file_header.signature))

    if file_header.compression_method != self._COMPRESSION_METHOD_DEFLATE:
      raise errors.FileFormatError(
          u'Unsuppored compression method: {0:d}.'.format(
              file_header.compression_method))

    self.modification_time = file_header.modification_time
    self.operating_system = file_header.operating_system

    if file_header.flags & self._FLAG_FEXTRA:
      extra_field_data_size = construct.ULInt16(
          u'extra_field_data_size').parse_stream(file_object)
      file_object.seek(extra_field_data_size, os.SEEK_CUR)
      self._compressed_data_offset += 2 + extra_field_data_size

    if file_header.flags & self._FLAG_FNAME:
      # Since encoding is set construct will convert the C string to Unicode.
      # Note that construct 2 does not support the encoding to be a Unicode
      # string.
      self.original_filename = construct.CString(
          u'original_filename', encoding='iso-8859-1').parse_stream(
              file_object)
      self._compressed_data_offset = file_object.get_offset()

    if file_header.flags & self._FLAG_FCOMMENT:
      # Since encoding is set construct will convert the C string to Unicode.
      # Note that construct 2 does not support the encoding to be a Unicode
      # string.
      self.comment = construct.CString(
          u'comment', encoding='iso-8859-1').parse_stream(file_object)
      self._compressed_data_offset = file_object.get_offset()

    if file_header.flags & self._FLAG_FHCRC:
      self._compressed_data_offset += 2

    self._compressed_data_size = (
        file_object.get_size() - (self._compressed_data_offset + 8))
Esempio n. 2
0
    def _ReadMemberHeader(self, file_object):
        """Reads a member header.

    Args:
      file_object (FileIO): file-like object to read from.

    Raises:
      FileFormatError: if the member header cannot be read.
    """
        file_offset = file_object.get_offset()
        member_header = self._ReadStructure(file_object, file_offset,
                                            self._MEMBER_HEADER_SIZE,
                                            self._MEMBER_HEADER,
                                            'member header')

        if member_header.signature != self._GZIP_SIGNATURE:
            raise errors.FileFormatError(
                'Unsupported signature: 0x{0:04x}.'.format(
                    member_header.signature))

        if member_header.compression_method != self._COMPRESSION_METHOD_DEFLATE:
            raise errors.FileFormatError(
                'Unsupported compression method: {0:d}.'.format(
                    member_header.compression_method))

        self.modification_time = member_header.modification_time
        self.operating_system = member_header.operating_system

        if member_header.flags & self._FLAG_FEXTRA:
            file_offset = file_object.get_offset()
            extra_field_data_size = self._ReadStructure(
                file_object, file_offset, self._UINT16LE_SIZE, self._UINT16LE,
                'extra field data size')

            file_object.seek(extra_field_data_size, os.SEEK_CUR)

        if member_header.flags & self._FLAG_FNAME:
            file_offset = file_object.get_offset()
            string_value = self._ReadString(file_object, file_offset,
                                            self._CSTRING, 'original filename')

            self.original_filename = string_value.rstrip('\x00')

        if member_header.flags & self._FLAG_FCOMMENT:
            file_offset = file_object.get_offset()
            string_value = self._ReadString(file_object, file_offset,
                                            self._CSTRING, 'comment')

            self.comment = string_value.rstrip('\x00')

        if member_header.flags & self._FLAG_FHCRC:
            file_object.read(2)
Esempio n. 3
0
  def _ReadStructureFromByteStream(
      self, byte_stream, file_offset, data_type_map, description, context=None):
    """Reads a structure from a byte stream.

    Args:
      byte_stream (bytes): byte stream.
      file_offset (int): offset of the data relative from the start of
          the file-like object.
      data_type_map (dtfabric.DataTypeMap): data type map of the structure.
      description (str): description of the structure.
      context (Optional[dtfabric.DataTypeMapContext]): data type map context.

    Returns:
      object: structure values object.

    Raises:
      FileFormatError: if the structure cannot be read.
      ValueError: if file-like object or date type map are invalid.
    """
    if not byte_stream:
      raise ValueError('Invalid byte stream.')

    if not data_type_map:
      raise ValueError('Invalid data type map.')

    try:
      return data_type_map.MapByteStream(byte_stream, context=context)
    except dtfabric_errors.MappingError as exception:
      raise errors.FileFormatError((
          'Unable to map {0:s} data at offset: 0x{1:08x} with error: '
          '{2!s}').format(description, file_offset, exception))
Esempio n. 4
0
    def _ReadAndParseHeader(self, file_object):
        """Reads the member header and sets relevant member values.

    Args:
      file_object (FileIO): file-like object to read from.

    Raises:
      FileFormatError: if file format related errors are detected.
    """
        member_header = self._MEMBER_HEADER_STRUCT.parse_stream(file_object)

        if member_header.signature != self._GZIP_SIGNATURE:
            raise errors.FileFormatError(
                'Unsupported file signature: 0x{0:04x}.'.format(
                    member_header.signature))

        if member_header.compression_method != self._COMPRESSION_METHOD_DEFLATE:
            raise errors.FileFormatError(
                'Unsupported compression method: {0:d}.'.format(
                    member_header.compression_method))

        self.modification_time = member_header.modification_time
        self.operating_system = member_header.operating_system

        if member_header.flags & self._FLAG_FEXTRA:
            extra_field_data_size = construct.ULInt16(
                'extra_field_data_size').parse_stream(file_object)
            file_object.seek(extra_field_data_size, os.SEEK_CUR)

        if member_header.flags & self._FLAG_FNAME:
            # Since encoding is set construct will convert the C string to Unicode.
            # Note that construct 2 does not support the encoding to be a Unicode
            # string.
            self.original_filename = construct.CString(
                'original_filename',
                encoding=b'iso-8859-1').parse_stream(file_object)

        if member_header.flags & self._FLAG_FCOMMENT:
            # Since encoding is set construct will convert the C string to Unicode.
            # Note that construct 2 does not support the encoding to be a Unicode
            # string.
            self.comment = construct.CString(
                'comment', encoding=b'iso-8859-1').parse_stream(file_object)

        if member_header.flags & self._FLAG_FHCRC:
            file_object.read(2)
Esempio n. 5
0
  def _ReadData(self, file_object, file_offset, data_size, description):
    """Reads data.

    Args:
      file_object (FileIO): file-like object.
      file_offset (int): offset of the data relative from the start of
          the file-like object.
      data_size (int): size of the data.
      description (str): description of the data.

    Returns:
      bytes: byte stream containing the data.

    Raises:
      FileFormatError: if the structure cannot be read.
      ValueError: if file-like object or date type map are invalid.
    """
    if not file_object:
      raise ValueError('Invalid file-like object.')

    file_object.seek(file_offset, os.SEEK_SET)

    read_error = ''

    try:
      data = file_object.read(data_size)

      if len(data) != data_size:
        read_error = 'missing data'

    except IOError as exception:
      read_error = '{0!s}'.format(exception)

    if read_error:
      raise errors.FileFormatError((
          'Unable to read {0:s} data at offset: 0x{1:08x} with error: '
          '{2:s}').format(description, file_offset, read_error))

    return data
Esempio n. 6
0
    def _ReadFileEntry(self, file_object, file_offset):
        """Reads a file entry.

    Args:
      file_object (FileIO): file-like object.
      file_offset (int): offset of the data relative from the start of
          the file-like object.

    Returns:
      CPIOArchiveFileEntry: a file entry.

    Raises:
      FileFormatError: if the file entry cannot be read.
    """
        if self.file_format == 'bin-big-endian':
            data_type_map = self._CPIO_BINARY_BIG_ENDIAN_FILE_ENTRY
            file_entry_data_size = self._CPIO_BINARY_BIG_ENDIAN_FILE_ENTRY_SIZE
        elif self.file_format == 'bin-little-endian':
            data_type_map = self._CPIO_BINARY_LITTLE_ENDIAN_FILE_ENTRY
            file_entry_data_size = self._CPIO_BINARY_LITTLE_ENDIAN_FILE_ENTRY_SIZE
        elif self.file_format == 'odc':
            data_type_map = self._CPIO_PORTABLE_ASCII_FILE_ENTRY
            file_entry_data_size = self._CPIO_PORTABLE_ASCII_FILE_ENTRY_SIZE
        elif self.file_format in ('crc', 'newc'):
            data_type_map = self._CPIO_NEW_ASCII_FILE_ENTRY
            file_entry_data_size = self._CPIO_NEW_ASCII_FILE_ENTRY_SIZE

        file_entry = self._ReadStructure(file_object, file_offset,
                                         file_entry_data_size, data_type_map,
                                         'file entry')

        file_offset += file_entry_data_size

        if self.file_format in ('bin-big-endian', 'bin-little-endian'):
            file_entry.modification_time = (
                (file_entry.modification_time.upper << 16)
                | file_entry.modification_time.lower)

            file_entry.file_size = ((file_entry.file_size.upper << 16)
                                    | file_entry.file_size.lower)

        if self.file_format == 'odc':
            for attribute_name in self._CPIO_ATTRIBUTE_NAMES_ODC:
                value = getattr(file_entry, attribute_name, None)
                try:
                    value = int(value, 8)
                except ValueError:
                    raise errors.FileFormatError(
                        'Unable to convert attribute: {0:s} into an integer'.
                        format(attribute_name))

                value = setattr(file_entry, attribute_name, value)

        elif self.file_format in ('crc', 'newc'):
            for attribute_name in self._CPIO_ATTRIBUTE_NAMES_CRC:
                value = getattr(file_entry, attribute_name, None)
                try:
                    value = int(value, 16)
                except ValueError:
                    raise errors.FileFormatError(
                        'Unable to convert attribute: {0:s} into an integer'.
                        format(attribute_name))

                value = setattr(file_entry, attribute_name, value)

        path_data = file_object.read(file_entry.path_size)

        file_offset += file_entry.path_size

        path = path_data.decode(self._encoding)
        path, _, _ = path.partition('\x00')

        if self.file_format in ('bin-big-endian', 'bin-little-endian'):
            padding_size = file_offset % 2
            if padding_size > 0:
                padding_size = 2 - padding_size

        elif self.file_format == 'odc':
            padding_size = 0

        elif self.file_format in ('crc', 'newc'):
            padding_size = file_offset % 4
            if padding_size > 0:
                padding_size = 4 - padding_size

        file_offset += padding_size

        archive_file_entry = CPIOArchiveFileEntry()

        archive_file_entry.data_offset = file_offset
        archive_file_entry.data_size = file_entry.file_size
        archive_file_entry.group_identifier = file_entry.group_identifier
        archive_file_entry.inode_number = file_entry.inode_number
        archive_file_entry.modification_time = file_entry.modification_time
        archive_file_entry.path = path
        archive_file_entry.mode = file_entry.mode
        archive_file_entry.size = (file_entry_data_size +
                                   file_entry.path_size + padding_size +
                                   file_entry.file_size)
        archive_file_entry.user_identifier = file_entry.user_identifier

        file_offset += file_entry.file_size

        if self.file_format in ('bin-big-endian', 'bin-little-endian'):
            padding_size = file_offset % 2
            if padding_size > 0:
                padding_size = 2 - padding_size

        elif self.file_format == 'odc':
            padding_size = 0

        elif self.file_format in ('crc', 'newc'):
            padding_size = file_offset % 4
            if padding_size > 0:
                padding_size = 4 - padding_size

        if padding_size > 0:
            archive_file_entry.size += padding_size

        return archive_file_entry