1use std::io::{self, Read, Seek, SeekFrom};
7
8use crate::header::{GD_AT_END, SECTOR_SIZE};
9use crate::VmdkReader;
10
11impl<R: Read + Seek> VmdkReader<R> {
12 pub fn enable_rgd_fallback(&mut self) {
16 self.rgd_fallback = true;
17 }
18
19 #[must_use]
23 pub fn rgd_recovery_count(&self) -> u64 {
24 self.rgd_recovery_count
25 }
26
27 pub(crate) fn resilient_gt_sector(
32 &mut self,
33 gd_idx: usize,
34 primary: u32,
35 num_gtes_per_gt: u64,
36 ) -> io::Result<u32> {
37 let file_len = self.inner.seek(SeekFrom::End(0))?;
38 let gt_byte_len = num_gtes_per_gt * 4;
39 let usable = |sec: u32| {
40 sec != 0
41 && u64::from(sec)
42 .saturating_mul(SECTOR_SIZE)
43 .saturating_add(gt_byte_len)
44 <= file_len
45 };
46 if usable(primary) {
47 return Ok(primary);
48 }
49 let rgd = self.rgd_dir_entry(gd_idx, file_len)?;
50 if usable(rgd) {
51 crate::diag::pointer_recovered(gd_idx, primary, rgd);
52 return Ok(rgd);
53 }
54 Ok(primary)
55 }
56
57 pub(crate) fn rgd_dir_entry(&mut self, gd_idx: usize, file_len: u64) -> io::Result<u32> {
60 if self.rgd_offset == 0 || self.rgd_offset == GD_AT_END {
61 return Ok(0);
62 }
63 if gd_idx >= self.gd_entry_count {
64 return Ok(0);
65 }
66 let entry_byte = self
67 .rgd_offset
68 .saturating_mul(SECTOR_SIZE)
69 .saturating_add(gd_idx as u64 * 4);
70 if entry_byte.saturating_add(4) > file_len {
71 return Ok(0);
72 }
73 let mut b = [0u8; 4];
74 self.read_exact_at(entry_byte, &mut b)?;
75 Ok(u32::from_le_bytes(b))
76 }
77
78 pub(crate) fn read_redundant_gt(
81 &mut self,
82 gd_idx: usize,
83 num_gtes_per_gt: u64,
84 ) -> io::Result<Option<Vec<u8>>> {
85 let file_len = self.inner.seek(SeekFrom::End(0))?;
86 let sector = self.rgd_dir_entry(gd_idx, file_len)?;
87 if sector == 0 {
88 return Ok(None);
89 }
90 let gt_byte = u64::from(sector) * SECTOR_SIZE;
91 let gt_byte_len = num_gtes_per_gt * 4;
92 if gt_byte.saturating_add(gt_byte_len) > file_len {
93 return Ok(None);
94 }
95 let mut b = vec![0u8; gt_byte_len as usize];
96 self.read_exact_at(gt_byte, &mut b)?;
97 Ok(Some(b))
98 }
99
100 pub(crate) fn rgd_gte(
104 &mut self,
105 gd_idx: usize,
106 gte_idx: u64,
107 num_gtes_per_gt: u64,
108 ) -> io::Result<u32> {
109 let file_len = self.inner.seek(SeekFrom::End(0))?;
110 let rgd_gt_sector = self.rgd_dir_entry(gd_idx, file_len)?;
111 if rgd_gt_sector == 0 {
112 return Ok(0);
113 }
114 let gt_byte = u64::from(rgd_gt_sector) * SECTOR_SIZE;
115 let gt_byte_len = num_gtes_per_gt * 4;
116 if gt_byte.saturating_add(gt_byte_len) > file_len {
117 return Ok(0);
118 }
119 let entry_byte = gt_byte + gte_idx * 4;
120 if entry_byte.saturating_add(4) > file_len {
121 return Ok(0);
122 }
123 let mut b = [0u8; 4];
124 self.read_exact_at(entry_byte, &mut b)?;
125 Ok(u32::from_le_bytes(b))
126 }
127}