Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  reader.rs   Sprache: Rust

 

use crate::{
    common::keys::DataBackupPageKey,
    data_backup::{
        DataBackupRestoreError, DataBackupRestoreInternalErrorCause, TARGET_INSTRUCTION_BUFFER_LENGTH,
        cipher::{PageDecryptor, PageNumber},
        common::{Category, CategorySpan, Offset, Page},
    },
    utils::frame::{FixedLengthFrameDecoder, FrameDelimiter, VariableLengthFrameDecoder},
};

/// Buffers a stream of data from decrypted and decoded pages for subsequent processing.
pub(super) trait PageDataBuffer {
    /// Add page data to the buffer.
    fn add_data(&mut self, data: &[u8]);
}
impl<const LENGTH: usize> PageDataBuffer for FixedLengthFrameDecoder<LENGTH> {
    fn add_data(&mut self, data: &[u8]) {
        let _ = self.add_chunks(&[data]);
    }
}
impl<const DELIMITER_LENGTH: usize, TDelimiter: FrameDelimiter<DELIMITER_LENGTH>> PageDataBuffer
    for VariableLengthFrameDecoder<DELIMITER_LENGTH, TDelimiter>
{
    fn add_data(&mut self, data: &[u8]) {
        let _ = self.add_chunks(&[data]);
    }
}

/// Checkpoint to construct a new/subsequent [`PageReader`] from.
pub(super) struct PageReaderCheckpoint {
    pub(super) key: DataBackupPageKey,
}

/// A batch span of encrypted pages to feed into the reader.
///
/// Note: The contained length must be `N * length-with-overhead` with `N >= 1`.
pub(super) struct PageBatch {
    pub(super) offset: Offset,
    pub(super) length: u32,
}

/// Buffers incoming encrypted pages to decrypt page data from it.
pub(super) struct PageReader<TBuffer: PageDataBuffer> {
    decryptor: PageDecryptor,
    number: PageNumber,
    span: CategorySpan,
    buffer: TBuffer,
    max_batch_length: u32,
}
impl<TBuffer: PageDataBuffer> PageReader<TBuffer> {
    pub(super) fn new(
        checkpoint: PageReaderCheckpoint,
        category: Category,
        span: CategorySpan,
        buffer: TBuffer,
    ) -> Result<Self, DataBackupRestoreInternalErrorCause> {
        // Compute the largest multiple of page length (with overhead) that fits into the target instruction
        // buffer length, but never less than a single page, so a batch is never zero.
        let max_batch_length = {
            let length_with_overhead = span.page_length.length_with_overhead;
            TARGET_INSTRUCTION_BUFFER_LENGTH
                .checked_rem(length_with_overhead)
                .and_then(|remainder| TARGET_INSTRUCTION_BUFFER_LENGTH.checked_sub(remainder))
                .ok_or_else(|| {
                    DataBackupRestoreInternalErrorCause::Other("Computed batch length overflowed".to_owned())
                })?
                .max(length_with_overhead)
        };
        Ok(Self {
            decryptor: PageDecryptor::new(checkpoint.key, category),
            number: PageNumber::new(),
            span,
            buffer,
            max_batch_length,
        })
    }

    /// Hand out the underlying buffer implementation for draining / post-processing of the page data buffer.
    #[inline]
    pub(super) fn buffer(&mut self) -> &mut TBuffer {
        &mut self.buffer
    }

    /// Request the next batch of pages, or [`None`] if the page category has been read into the buffer
    /// completely.
    #[inline]
    pub(super) fn next_batch(&self) -> Result<Option<PageBatch>, DataBackupRestoreError> {
        let remaining_length = self.span.length().ok_or_else(|| {
            DataBackupRestoreError::InternalError(DataBackupRestoreInternalErrorCause::Other(format!(
                "Invalid category span {:?}",
                self.span
            )))
        })?;
        if remaining_length == 0 {
            return Ok(None);
        }
        Ok(Some(PageBatch {
            offset: self.span.start,
            length: remaining_length.min(self.max_batch_length),
        }))
    }

    /// Add an encrypted page by decrypting and decoding it into the reader's buffer.
    pub(super) fn add_pages(
        &mut self,
        offset: Offset,
        encrypted_pages: &[u8],
    ) -> Result<(), DataBackupRestoreError> {
        // Validate offset.
        if offset != self.span.start {
            return Err(DataBackupRestoreError::ContractViolation(format!(
                "Unexpected page at offset {offset}, expected {}",
                self.span.start
            )));
        }

        // Drain all encrypted pages.
        for encrypted_page in encrypted_pages.chunks(self.span.page_length.length_with_overhead as usize) {
            // Check if there are still expected pages.
            if self.span.is_empty() {
                return Err(DataBackupRestoreError::ContractViolation(
                    "Unexpected page after the page category was fully read".to_owned(),
                ));
            }

            // Decrypt and decode page.
            //
            // Note: Decoding implicitly validates the length of the page, so we can skip doing this.
            let page = Page::decode(
                self.span.page_length,
                self.decryptor
                    .decrypt(&mut self.number, encrypted_page.to_vec())?,
            )?;

            // Update the offset and add the page data to the buffer.
            self.span
                .start
                .add(self.span.page_length.length_with_overhead as usize)
                .ok_or_else(|| {
                    DataBackupRestoreError::InternalError(DataBackupRestoreInternalErrorCause::Other(
                        "Resulting page offset exceeds u64".to_owned(),
                    ))
                })?;
            self.buffer.add_data(&page);
        }
        Ok(())
    }

    /// Expect the reader to have consumed all pages.
    #[inline]
    pub(super) fn expect_consumed(self) -> Result<PageReaderCheckpoint, DataBackupRestoreError> {
        if !self.span.is_empty() {
            return Err(DataBackupRestoreError::InternalError(
                DataBackupRestoreInternalErrorCause::Other(format!(
                    "Pages left over to read, {:?}",
                    self.span
                )),
            ));
        }
        Ok(PageReaderCheckpoint {
            key: self.decryptor.dissolve(),
        })
    }
}

Messung
CHZG
9010010096

¤ Dauer der Verarbeitung: 0.14 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104857
#Domains=439033