1 // Copyright 2018 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::fs::File; 6 use std::io; 7 use std::io::BufWriter; 8 use std::io::Read; 9 use std::io::Seek; 10 use std::io::SeekFrom; 11 use std::io::Write; 12 use std::mem::size_of; 13 use std::mem::size_of_val; 14 15 use base::FileReadWriteAtVolatile; 16 use base::VolatileSlice; 17 use base::WriteZeroesAt; 18 19 /// A qcow file. Allows reading/writing clusters and appending clusters. 20 #[derive(Debug)] 21 pub struct QcowRawFile { 22 file: File, 23 cluster_size: u64, 24 cluster_mask: u64, 25 } 26 27 impl QcowRawFile { 28 /// Creates a `QcowRawFile` from the given `File`, `None` is returned if `cluster_size` is not 29 /// a power of two. from(file: File, cluster_size: u64) -> Option<Self>30 pub fn from(file: File, cluster_size: u64) -> Option<Self> { 31 if cluster_size.count_ones() != 1 { 32 return None; 33 } 34 Some(QcowRawFile { 35 file, 36 cluster_size, 37 cluster_mask: cluster_size - 1, 38 }) 39 } 40 41 /// Reads `count` 64 bit offsets and returns them as a vector. 42 /// `mask` optionally ands out some of the bits on the file. read_pointer_table( &mut self, offset: u64, count: u64, mask: Option<u64>, ) -> io::Result<Vec<u64>>43 pub fn read_pointer_table( 44 &mut self, 45 offset: u64, 46 count: u64, 47 mask: Option<u64>, 48 ) -> io::Result<Vec<u64>> { 49 let mut table = vec![0; count as usize]; 50 self.file.seek(SeekFrom::Start(offset))?; 51 let mask = mask.unwrap_or(u64::max_value()); 52 for ptr in &mut table { 53 let mut value = [0u8; 8]; 54 self.file.read_exact(&mut value)?; 55 *ptr = u64::from_be_bytes(value) & mask; 56 } 57 Ok(table) 58 } 59 60 /// Reads a cluster's worth of 64 bit offsets and returns them as a vector. 61 /// `mask` optionally ands out some of the bits on the file. read_pointer_cluster(&mut self, offset: u64, mask: Option<u64>) -> io::Result<Vec<u64>>62 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 /// Writes `table` of u64 pointers to `offset` in the file. 68 /// `non_zero_flags` will be ORed with all non-zero values in `table`. 69 /// writing. write_pointer_table( &mut self, offset: u64, table: &[u64], non_zero_flags: u64, ) -> io::Result<()>70 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 Ok(()) 87 } 88 89 /// Read a refcount block from the file and returns a Vec containing the block. 90 /// Always returns a cluster's worth of data. read_refcount_block(&mut self, offset: u64) -> io::Result<Vec<u16>>91 pub fn read_refcount_block(&mut self, offset: u64) -> io::Result<Vec<u16>> { 92 let count = self.cluster_size / size_of::<u16>() as u64; 93 let mut table = vec![0; count as usize]; 94 self.file.seek(SeekFrom::Start(offset))?; 95 for refcount in &mut table { 96 let mut value = [0u8; 2]; 97 self.file.read_exact(&mut value)?; 98 *refcount = u16::from_be_bytes(value); 99 } 100 Ok(table) 101 } 102 103 /// Writes a refcount block to the file. write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()>104 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 Ok(()) 111 } 112 113 /// Allocates a new cluster at the end of the current file, return the address. add_cluster_end(&mut self, max_valid_cluster_offset: u64) -> io::Result<Option<u64>>114 pub fn add_cluster_end(&mut self, max_valid_cluster_offset: u64) -> io::Result<Option<u64>> { 115 // Determine where the new end of the file should be and set_len, which 116 // translates to truncate(2). 117 let file_end: u64 = self.file.seek(SeekFrom::End(0))?; 118 let new_cluster_address: u64 = (file_end + self.cluster_size - 1) & !self.cluster_mask; 119 120 if new_cluster_address > max_valid_cluster_offset { 121 return Ok(None); 122 } 123 124 self.file.set_len(new_cluster_address + self.cluster_size)?; 125 126 Ok(Some(new_cluster_address)) 127 } 128 129 /// Returns a reference to the underlying file. file(&self) -> &File130 pub fn file(&self) -> &File { 131 &self.file 132 } 133 134 /// Returns a mutable reference to the underlying file. file_mut(&mut self) -> &mut File135 pub fn file_mut(&mut self) -> &mut File { 136 &mut self.file 137 } 138 139 /// Returns the size of the file's clusters. cluster_size(&self) -> u64140 pub fn cluster_size(&self) -> u64 { 141 self.cluster_size 142 } 143 144 /// Returns the offset of `address` within a cluster. cluster_offset(&self, address: u64) -> u64145 pub fn cluster_offset(&self, address: u64) -> u64 { 146 address & self.cluster_mask 147 } 148 149 /// Zeros out a cluster in the file. zero_cluster(&mut self, address: u64) -> io::Result<()>150 pub fn zero_cluster(&mut self, address: u64) -> io::Result<()> { 151 let cluster_size = self.cluster_size as usize; 152 self.file.write_zeroes_all_at(address, cluster_size)?; 153 Ok(()) 154 } 155 156 /// Writes write_cluster(&mut self, address: u64, mut initial_data: Vec<u8>) -> io::Result<()>157 pub fn write_cluster(&mut self, address: u64, mut initial_data: Vec<u8>) -> io::Result<()> { 158 if (initial_data.len() as u64) < self.cluster_size { 159 return Err(io::Error::new( 160 io::ErrorKind::InvalidInput, 161 "`initial_data` is too small", 162 )); 163 } 164 let volatile_slice = VolatileSlice::new(&mut initial_data[..self.cluster_size as usize]); 165 self.file.write_all_at_volatile(volatile_slice, address) 166 } 167 } 168