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 use zerocopy::AsBytes; 19 20 /// A qcow file. Allows reading/writing clusters and appending clusters. 21 #[derive(Debug)] 22 pub struct QcowRawFile { 23 file: File, 24 cluster_size: u64, 25 cluster_mask: u64, 26 } 27 28 impl QcowRawFile { 29 /// Creates a `QcowRawFile` from the given `File`, `None` is returned if `cluster_size` is not 30 /// a power of two. from(file: File, cluster_size: u64) -> Option<Self>31 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 /// Reads `count` 64 bit offsets and returns them as a vector. 43 /// `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>>44 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_bytes_mut())?; 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 /// 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 buffer.flush()?; 87 Ok(()) 88 } 89 90 /// Read a refcount block from the file and returns a Vec containing the block. 91 /// Always returns a cluster's worth of data. read_refcount_block(&mut self, offset: u64) -> io::Result<Vec<u16>>92 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_bytes_mut())?; 97 for refcount in &mut table { 98 *refcount = u16::from_be(*refcount); 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 buffer.flush()?; 111 Ok(()) 112 } 113 114 /// 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>>115 pub fn add_cluster_end(&mut self, max_valid_cluster_offset: u64) -> io::Result<Option<u64>> { 116 // Determine where the new end of the file should be and set_len, which 117 // translates to truncate(2). 118 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 /// Returns a reference to the underlying file. file(&self) -> &File131 pub fn file(&self) -> &File { 132 &self.file 133 } 134 135 /// Returns a mutable reference to the underlying file. file_mut(&mut self) -> &mut File136 pub fn file_mut(&mut self) -> &mut File { 137 &mut self.file 138 } 139 140 /// Returns the size of the file's clusters. cluster_size(&self) -> u64141 pub fn cluster_size(&self) -> u64 { 142 self.cluster_size 143 } 144 145 /// Returns the offset of `address` within a cluster. cluster_offset(&self, address: u64) -> u64146 pub fn cluster_offset(&self, address: u64) -> u64 { 147 address & self.cluster_mask 148 } 149 150 /// Zeros out a cluster in the file. zero_cluster(&mut self, address: u64) -> io::Result<()>151 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 /// Writes write_cluster(&mut self, address: u64, mut initial_data: Vec<u8>) -> io::Result<()>158 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 } 169