ntfs_reader/
volume.rs

1// Copyright (c) 2022, Matteo Bernacchia <dev@kikijiki.com>. All rights reserved.
2// This project is dual licensed under the Apache License 2.0 and the MIT license.
3// See the LICENSE files in the project root for details.
4
5use std::path::{Path, PathBuf};
6
7use binread::BinReaderExt;
8
9use windows::Win32::{
10    Foundation::{CloseHandle, HANDLE},
11    Security::{GetTokenInformation, TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY},
12    System::Threading::{GetCurrentProcess, OpenProcessToken},
13};
14
15use crate::{
16    aligned_reader::open_volume,
17    api::*,
18    errors::{NtfsReaderError, NtfsReaderResult},
19};
20
21#[derive(Clone)]
22pub struct Volume {
23    pub path: PathBuf,
24    pub boot_sector: BootSector,
25    pub cluster_size: u64,
26    pub volume_size: u64,
27    pub file_record_size: u64,
28    pub mft_position: u64,
29}
30
31impl Volume {
32    pub fn new<P: AsRef<Path>>(path: P) -> NtfsReaderResult<Self> {
33        if !Self::is_elevated().unwrap_or(false) {
34            return Err(NtfsReaderError::ElevationError);
35        }
36
37        let mut reader = open_volume(path.as_ref())?;
38        let boot_sector = reader.read_le::<BootSector>()?;
39
40        let cluster_size = boot_sector.sectors_per_cluster as u64 * boot_sector.sector_size as u64;
41        let volume_size = boot_sector.total_sectors as u64 * boot_sector.sector_size as u64;
42        let file_record_size = {
43            if boot_sector.file_record_size_info > 0 {
44                (boot_sector.file_record_size_info as u64) * cluster_size
45            } else {
46                1u64 << (-boot_sector.file_record_size_info) as u64
47            }
48        };
49        let mft_position = boot_sector.mft_lcn * cluster_size;
50
51        Ok(Volume {
52            path: path.as_ref().into(),
53            boot_sector,
54            cluster_size,
55            volume_size,
56            file_record_size,
57            mft_position,
58        })
59    }
60
61    fn is_elevated() -> windows::core::Result<bool> {
62        unsafe {
63            let mut handle: HANDLE = HANDLE::default();
64            OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle)?;
65
66            let result = (|| -> windows::core::Result<bool> {
67                let mut elevation = TOKEN_ELEVATION::default();
68                let mut returned_length = 0;
69
70                GetTokenInformation(
71                    handle,
72                    TokenElevation,
73                    Some(&mut elevation as *mut _ as *mut _),
74                    std::mem::size_of::<TOKEN_ELEVATION>() as u32,
75                    &mut returned_length,
76                )?;
77
78                Ok(elevation.TokenIsElevated != 0)
79            })();
80
81            let _ = CloseHandle(handle);
82            result
83        }
84    }
85}