Welcome to mirror list, hosted at ThFree Co, Russian Federation.

index_root.rs « structured_values « src - github.com/windirstat/ntfs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 47b52d6ee950a9ad89a4bd69f75c3e166274c024 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Copyright 2021 Colin Finck <colin@reactos.org>
// SPDX-License-Identifier: GPL-2.0-or-later

use crate::attribute::NtfsAttributeType;
use crate::attribute_value::NtfsAttributeValue;
use crate::error::{NtfsError, Result};
use crate::index_entry::NtfsIndexEntries;
use crate::index_record::{IndexNodeHeader, INDEX_NODE_HEADER_SIZE};
use crate::ntfs::Ntfs;
use crate::structured_values::NewNtfsStructuredValue;
use crate::traits::NtfsReadSeek;
use binread::io::{Read, Seek, SeekFrom};
use binread::{BinRead, BinReaderExt};

/// Size of all [`IndexRootHeader`] fields plus some reserved bytes.
const INDEX_ROOT_HEADER_SIZE: u64 = 16;

#[derive(BinRead, Clone, Debug)]
struct IndexRootHeader {
    ty: u32,
    collation_rule: u32,
    index_record_size: u32,
    clusters_per_index_record: i8,
}

#[derive(Clone, Debug)]
pub struct NtfsIndexRoot<'n> {
    ntfs: &'n Ntfs,
    value: NtfsAttributeValue<'n>,
    index_root_header: IndexRootHeader,
    index_node_header: IndexNodeHeader,
}

const LARGE_INDEX_FLAG: u8 = 0x01;

impl<'n> NtfsIndexRoot<'n> {
    pub fn index_allocated_size(&self) -> u32 {
        self.index_node_header.allocated_size
    }

    pub fn entries<K, T>(&self, fs: &mut T) -> Result<NtfsIndexEntries<'n, K>>
    where
        K: NewNtfsStructuredValue<'n>,
        T: Read + Seek,
    {
        let offset = self.value.stream_position() + INDEX_ROOT_HEADER_SIZE as u64;
        let start = offset + self.index_node_header.entries_offset as u64;
        let end = offset + self.index_used_size() as u64;

        let mut value = self.value.clone();
        value.seek(fs, SeekFrom::Start(start))?;

        Ok(NtfsIndexEntries::new(self.ntfs, value, end))
    }

    pub fn index_record_size(&self) -> u32 {
        self.index_root_header.index_record_size
    }

    pub fn index_used_size(&self) -> u32 {
        self.index_node_header.index_size
    }

    /// Returns whether the index belonging to this Index Root is large enough
    /// to need an extra Index Allocation attribute.
    /// Otherwise, the entire index information is stored in this Index Root.
    pub fn is_large_index(&self) -> bool {
        (self.index_node_header.flags & LARGE_INDEX_FLAG) != 0
    }
}

impl<'n> NewNtfsStructuredValue<'n> for NtfsIndexRoot<'n> {
    fn new<T>(
        ntfs: &'n Ntfs,
        fs: &mut T,
        value: NtfsAttributeValue<'n>,
        _length: u64,
    ) -> Result<Self>
    where
        T: Read + Seek,
    {
        if value.len() < INDEX_ROOT_HEADER_SIZE + INDEX_NODE_HEADER_SIZE {
            return Err(NtfsError::InvalidStructuredValueSize {
                position: value.data_position().unwrap(),
                ty: NtfsAttributeType::IndexRoot,
                expected: INDEX_ROOT_HEADER_SIZE,
                actual: value.len(),
            });
        }

        let mut value_attached = value.clone().attach(fs);
        let index_root_header = value_attached.read_le::<IndexRootHeader>()?;
        value_attached.seek(SeekFrom::Start(INDEX_ROOT_HEADER_SIZE))?;
        let index_node_header = value_attached.read_le::<IndexNodeHeader>()?;

        Ok(Self {
            ntfs,
            value,
            index_root_header,
            index_node_header,
        })
    }
}