1use 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}