teamy-mft 0.7.0

TeamDman's Master File Table CLI and library for NTFS.
use crate::mft::mft_record::MftRecord;
use crate::mft::mft_record_attribute::MftRecordAttribute;

#[derive(Debug)]
pub struct MftRecordAttributeIter<'a> {
    mft_record: &'a MftRecord,
    position: usize,
    mft_record_used_size: usize,
}
impl<'a> MftRecordAttributeIter<'a> {
    pub fn new(mft_record: &'a MftRecord) -> Self {
        let first_mft_attribute_offset = mft_record.get_first_attribute_offset() as usize;
        let mft_record_used_size = mft_record.get_used_size() as usize;
        debug_assert!(
            first_mft_attribute_offset < mft_record_used_size,
            "Attribute start {first_mft_attribute_offset} must be less than used size {mft_record_used_size}"
        );
        debug_assert!(
            mft_record_used_size <= mft_record.len(),
            "Used size {} must not exceed record length {}",
            mft_record_used_size,
            mft_record.len()
        );
        Self {
            mft_record,
            position: first_mft_attribute_offset,
            mft_record_used_size,
        }
    }
}
impl<'a> Iterator for MftRecordAttributeIter<'a> {
    type Item = MftRecordAttribute<'a>;
    // mftf[impl attribute-iteration.bounded-by-used-size]
    // mftf[impl attribute-iteration.ends-at-sentinel]
    fn next(&mut self) -> Option<Self::Item> {
        if self.position + 4 > self.mft_record_used_size {
            return None;
        }
        let attr_type = u32::from_le_bytes(
            self.mft_record[self.position..self.position + 4]
                .try_into()
                .ok()?,
        );
        if attr_type == MftRecordAttribute::TYPE_END {
            return None;
        }
        if self.position + 8 > self.mft_record_used_size {
            return None;
        }
        let attr_len = u32::from_le_bytes(
            self.mft_record[self.position + 4..self.position + 8]
                .try_into()
                .ok()?,
        ) as usize;
        if attr_len == 0 || self.position + attr_len > self.mft_record_used_size {
            return None;
        }
        let start = self.position;
        let end = start + attr_len;
        self.position = end;
        let raw = &self.mft_record[start..end];
        MftRecordAttribute::new(raw).ok()
    }
}