use core::iter::FusedIterator;
use binrw::io::{Read, Seek, SeekFrom};
use crate::attribute::NtfsAttributeType;
use crate::attribute_value::NtfsAttributeValue;
use crate::error::{NtfsError, Result};
use crate::index_record::NtfsIndexRecord;
use crate::ntfs::Ntfs;
use crate::structured_values::NtfsStructuredValue;
use crate::traits::NtfsReadSeek;
use crate::types::Vcn;
#[derive(Clone, Debug)]
pub struct NtfsIndexAllocation<'n, 'f> {
ntfs: &'n Ntfs,
value: NtfsAttributeValue<'n, 'f>,
}
impl<'n, 'f> NtfsIndexAllocation<'n, 'f> {
pub fn record_from_vcn<T>(
&self,
fs: &mut T,
index_record_size: u32,
vcn: Vcn,
) -> Result<NtfsIndexRecord>
where
T: Read + Seek,
{
let mut value = self.value.clone();
let offset = vcn.offset(self.ntfs)?;
value.seek(fs, SeekFrom::Current(offset))?;
if value.stream_position() >= value.len() {
return Err(NtfsError::VcnOutOfBoundsInIndexAllocation {
position: self.value.data_position(),
vcn,
});
}
let record = NtfsIndexRecord::new(fs, value, index_record_size)?;
if record.vcn() != vcn {
return Err(NtfsError::VcnMismatchInIndexAllocation {
position: self.value.data_position(),
expected: vcn,
actual: record.vcn(),
});
}
Ok(record)
}
pub fn records(&self, index_record_size: u32) -> NtfsIndexRecords<'n, 'f> {
NtfsIndexRecords::new(self.clone(), index_record_size)
}
}
impl<'n, 'f> NtfsStructuredValue<'n, 'f> for NtfsIndexAllocation<'n, 'f> {
const TY: NtfsAttributeType = NtfsAttributeType::IndexAllocation;
fn from_attribute_value<T>(_fs: &mut T, value: NtfsAttributeValue<'n, 'f>) -> Result<Self>
where
T: Read + Seek,
{
let ntfs = match &value {
NtfsAttributeValue::AttributeListNonResident(value) => value.ntfs(),
NtfsAttributeValue::NonResident(value) => value.ntfs(),
NtfsAttributeValue::Resident(_) => {
let position = value.data_position();
return Err(NtfsError::UnexpectedResidentAttribute { position });
}
};
Ok(Self { ntfs, value })
}
}
#[derive(Clone, Debug)]
pub struct NtfsIndexRecords<'n, 'f> {
index_allocation: NtfsIndexAllocation<'n, 'f>,
index_record_size: u32,
}
impl<'n, 'f> NtfsIndexRecords<'n, 'f> {
fn new(index_allocation: NtfsIndexAllocation<'n, 'f>, index_record_size: u32) -> Self {
Self {
index_allocation,
index_record_size,
}
}
pub fn attach<'a, T>(self, fs: &'a mut T) -> NtfsIndexRecordsAttached<'n, 'f, 'a, T>
where
T: Read + Seek,
{
NtfsIndexRecordsAttached::new(fs, self)
}
pub fn next<T>(&mut self, fs: &mut T) -> Option<Result<NtfsIndexRecord>>
where
T: Read + Seek,
{
if self.index_allocation.value.stream_position() >= self.index_allocation.value.len() {
return None;
}
let record = iter_try!(NtfsIndexRecord::new(
fs,
self.index_allocation.value.clone(),
self.index_record_size
));
iter_try!(self
.index_allocation
.value
.seek(fs, SeekFrom::Current(self.index_record_size as i64)));
Some(Ok(record))
}
}
#[derive(Debug)]
pub struct NtfsIndexRecordsAttached<'n, 'f, 'a, T>
where
T: Read + Seek,
{
fs: &'a mut T,
index_records: NtfsIndexRecords<'n, 'f>,
}
impl<'n, 'f, 'a, T> NtfsIndexRecordsAttached<'n, 'f, 'a, T>
where
T: Read + Seek,
{
fn new(fs: &'a mut T, index_records: NtfsIndexRecords<'n, 'f>) -> Self {
Self { fs, index_records }
}
pub fn detach(self) -> NtfsIndexRecords<'n, 'f> {
self.index_records
}
}
impl<'n, 'f, 'a, T> Iterator for NtfsIndexRecordsAttached<'n, 'f, 'a, T>
where
T: Read + Seek,
{
type Item = Result<NtfsIndexRecord>;
fn next(&mut self) -> Option<Self::Item> {
self.index_records.next(self.fs)
}
}
impl<'n, 'f, 'a, T> FusedIterator for NtfsIndexRecordsAttached<'n, 'f, 'a, T> where T: Read + Seek {}