'Backup the given volume.
If backup[\'parent_id\'] is given, then an incremental backup
is performed.'

def backup(self, backup, volume_file, backup_metadata=True):

    if (self.chunk_size_bytes % self.sha_block_size_bytes):
        err = _('Chunk    size    is    not    multiple    of    block    size    for    creating    hash.')
        raise exception.InvalidBackup(reason=err)
    parent_backup_shafile = None
    parent_backup = None
    if backup.parent_id:
        parent_backup = objects.Backup.get_by_id(self.context, backup.parent_id)
        parent_backup_shafile = self._read_sha256file(parent_backup)
        parent_backup_shalist = parent_backup_shafile['sha256s']
        if (parent_backup_shafile['chunk_size'] != self.sha_block_size_bytes):
            err = (_('Hash    block    size    has    changed    since    the    last    backup.    New    hash    block    size:    %(new)s.    Old    hash    block    size:    %(old)s.    Do    a    full    backup.') % {'old': parent_backup_shafile['chunk_size'], 'new': self.sha_block_size_bytes})
            raise exception.InvalidBackup(reason=err)
        if (backup.size > parent_backup.size):
            err = _('Volume    size    increased    since    the    last    backup.    Do    a    full    backup.')
            raise exception.InvalidBackup(reason=err)
    (object_meta, object_sha256, extra_metadata, container, volume_size_bytes) = self._prepare_backup(backup)
    counter = 0
    total_block_sent_num = 0
    def _notify_progress():
        self._send_progress_notification(self.context, backup, object_meta, total_block_sent_num, volume_size_bytes)
    timer = loopingcall.FixedIntervalLoopingCall(_notify_progress)
    if self.enable_progress_timer:
        timer.start(interval=self.backup_timer_interval)
    sha256_list = object_sha256['sha256s']
    shaindex = 0
    is_backup_canceled = False
    while True:
        backup = objects.Backup.get_by_id(self.context, backup.id)
        if (backup.status in (fields.BackupStatus.DELETING, fields.BackupStatus.DELETED)):
            is_backup_canceled = True
            self.delete_backup(backup)
            LOG.debug('Cancel    the    backup    process    of    %s.', backup.id)
            break
        data_offset = volume_file.tell()
        data = volume_file.read(self.chunk_size_bytes)
        if (data == ''):
            break
        shalist = []
        off = 0
        datalen = len(data)
        while (off < datalen):
            chunk_start = off
            chunk_end = (chunk_start + self.sha_block_size_bytes)
            if (chunk_end > datalen):
                chunk_end = datalen
            chunk = data[chunk_start:chunk_end]
            sha = hashlib.sha256(chunk).hexdigest()
            shalist.append(sha)
            off += self.sha_block_size_bytes
        sha256_list.extend(shalist)
        if parent_backup:
            extent_off = (-1)
            for (idx, sha) in enumerate(shalist):
                if (sha != parent_backup_shalist[shaindex]):
                    if (extent_off == (-1)):
                        extent_off = (idx * self.sha_block_size_bytes)
                elif (extent_off != (-1)):
                    extent_end = (idx * self.sha_block_size_bytes)
                    segment = data[extent_off:extent_end]
                    self._backup_chunk(backup, container, segment, (data_offset + extent_off), object_meta, extra_metadata)
                    extent_off = (-1)
                shaindex += 1
            if (extent_off != (-1)):
                extent_end = datalen
                segment = data[extent_off:extent_end]
                self._backup_chunk(backup, container, segment, (data_offset + extent_off), object_meta, extra_metadata)
                extent_off = (-1)
        else:
            self._backup_chunk(backup, container, data, data_offset, object_meta, extra_metadata)
        total_block_sent_num += self.data_block_num
        counter += 1
        if (counter == self.data_block_num):
            self._send_progress_notification(self.context, backup, object_meta, total_block_sent_num, volume_size_bytes)
            counter = 0
    timer.stop()
    if is_backup_canceled:
        return
    self._send_progress_end(self.context, backup, object_meta)
    object_sha256['sha256s'] = sha256_list
    if backup_metadata:
        try:
            self._backup_metadata(backup, object_meta)
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.exception('Backup    volume    metadata    failed.')
                self.delete_backup(backup)
    self._finalize_backup(backup, container, object_meta, object_sha256)
