disk/qcow/
qcow_raw_file.rs1use std::fs::File;
6use std::io;
7use std::io::BufWriter;
8use std::io::Read;
9use std::io::Seek;
10use std::io::SeekFrom;
11use std::io::Write;
12use std::mem::size_of;
13use std::mem::size_of_val;
14
15use base::FileReadWriteAtVolatile;
16use base::VolatileSlice;
17use base::WriteZeroesAt;
18use zerocopy::IntoBytes;
19
20#[derive(Debug)]
22pub struct QcowRawFile {
23 file: File,
24 cluster_size: u64,
25 cluster_mask: u64,
26}
27
28impl QcowRawFile {
29 pub fn from(file: File, cluster_size: u64) -> Option<Self> {
32 if cluster_size.count_ones() != 1 {
33 return None;
34 }
35 Some(QcowRawFile {
36 file,
37 cluster_size,
38 cluster_mask: cluster_size - 1,
39 })
40 }
41
42 pub fn read_pointer_table(
45 &mut self,
46 offset: u64,
47 count: u64,
48 mask: Option<u64>,
49 ) -> io::Result<Vec<u64>> {
50 let mut table = vec![0; count as usize];
51 self.file.seek(SeekFrom::Start(offset))?;
52 self.file.read_exact(table.as_mut_bytes())?;
53 let mask = mask.unwrap_or(u64::MAX);
54 for ptr in &mut table {
55 *ptr = u64::from_be(*ptr) & mask;
56 }
57 Ok(table)
58 }
59
60 pub fn read_pointer_cluster(&mut self, offset: u64, mask: Option<u64>) -> io::Result<Vec<u64>> {
63 let count = self.cluster_size / size_of::<u64>() as u64;
64 self.read_pointer_table(offset, count, mask)
65 }
66
67 pub fn write_pointer_table(
71 &mut self,
72 offset: u64,
73 table: &[u64],
74 non_zero_flags: u64,
75 ) -> io::Result<()> {
76 self.file.seek(SeekFrom::Start(offset))?;
77 let mut buffer = BufWriter::with_capacity(size_of_val(table), &self.file);
78 for addr in table {
79 let val = if *addr == 0 {
80 0
81 } else {
82 *addr | non_zero_flags
83 };
84 buffer.write_all(&val.to_be_bytes())?;
85 }
86 buffer.flush()?;
87 Ok(())
88 }
89
90 pub fn read_refcount_block(&mut self, offset: u64) -> io::Result<Vec<u16>> {
93 let count = self.cluster_size / size_of::<u16>() as u64;
94 let mut table = vec![0; count as usize];
95 self.file.seek(SeekFrom::Start(offset))?;
96 self.file.read_exact(table.as_mut_bytes())?;
97 for refcount in &mut table {
98 *refcount = u16::from_be(*refcount);
99 }
100 Ok(table)
101 }
102
103 pub fn write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()> {
105 self.file.seek(SeekFrom::Start(offset))?;
106 let mut buffer = BufWriter::with_capacity(size_of_val(table), &self.file);
107 for count in table {
108 buffer.write_all(&count.to_be_bytes())?;
109 }
110 buffer.flush()?;
111 Ok(())
112 }
113
114 pub fn add_cluster_end(&mut self, max_valid_cluster_offset: u64) -> io::Result<Option<u64>> {
116 let file_end: u64 = self.file.seek(SeekFrom::End(0))?;
119 let new_cluster_address: u64 = (file_end + self.cluster_size - 1) & !self.cluster_mask;
120
121 if new_cluster_address > max_valid_cluster_offset {
122 return Ok(None);
123 }
124
125 self.file.set_len(new_cluster_address + self.cluster_size)?;
126
127 Ok(Some(new_cluster_address))
128 }
129
130 pub fn file(&self) -> &File {
132 &self.file
133 }
134
135 pub fn file_mut(&mut self) -> &mut File {
137 &mut self.file
138 }
139
140 pub fn cluster_size(&self) -> u64 {
142 self.cluster_size
143 }
144
145 pub fn cluster_offset(&self, address: u64) -> u64 {
147 address & self.cluster_mask
148 }
149
150 pub fn zero_cluster(&mut self, address: u64) -> io::Result<()> {
152 let cluster_size = self.cluster_size as usize;
153 self.file.write_zeroes_all_at(address, cluster_size)?;
154 Ok(())
155 }
156
157 pub fn write_cluster(&mut self, address: u64, mut initial_data: Vec<u8>) -> io::Result<()> {
159 if (initial_data.len() as u64) < self.cluster_size {
160 return Err(io::Error::new(
161 io::ErrorKind::InvalidInput,
162 "`initial_data` is too small",
163 ));
164 }
165 let volatile_slice = VolatileSlice::new(&mut initial_data[..self.cluster_size as usize]);
166 self.file.write_all_at_volatile(volatile_slice, address)
167 }
168}