• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
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::{self, BufWriter, Read, Seek, SeekFrom, Write};
7 use std::mem::size_of;
8 
9 use base::{FileReadWriteAtVolatile, WriteZeroes};
10 use data_model::VolatileSlice;
11 
12 /// A qcow file. Allows reading/writing clusters and appending clusters.
13 #[derive(Debug)]
14 pub struct QcowRawFile {
15     file: File,
16     cluster_size: u64,
17     cluster_mask: u64,
18 }
19 
20 impl QcowRawFile {
21     /// Creates a `QcowRawFile` from the given `File`, `None` is returned if `cluster_size` is not
22     /// a power of two.
from(file: File, cluster_size: u64) -> Option<Self>23     pub fn from(file: File, cluster_size: u64) -> Option<Self> {
24         if cluster_size.count_ones() != 1 {
25             return None;
26         }
27         Some(QcowRawFile {
28             file,
29             cluster_size,
30             cluster_mask: cluster_size - 1,
31         })
32     }
33 
34     /// Reads `count` 64 bit offsets and returns them as a vector.
35     /// `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>>36     pub fn read_pointer_table(
37         &mut self,
38         offset: u64,
39         count: u64,
40         mask: Option<u64>,
41     ) -> io::Result<Vec<u64>> {
42         let mut table = vec![0; count as usize];
43         self.file.seek(SeekFrom::Start(offset))?;
44         let mask = mask.unwrap_or(u64::max_value());
45         for ptr in &mut table {
46             let mut value = [0u8; 8];
47             self.file.read_exact(&mut value)?;
48             *ptr = u64::from_be_bytes(value) & mask;
49         }
50         Ok(table)
51     }
52 
53     /// Reads a cluster's worth of 64 bit offsets and returns them as a vector.
54     /// `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>>55     pub fn read_pointer_cluster(&mut self, offset: u64, mask: Option<u64>) -> io::Result<Vec<u64>> {
56         let count = self.cluster_size / size_of::<u64>() as u64;
57         self.read_pointer_table(offset, count, mask)
58     }
59 
60     /// Writes `table` of u64 pointers to `offset` in the file.
61     /// `non_zero_flags` will be ORed with all non-zero values in `table`.
62     /// writing.
write_pointer_table( &mut self, offset: u64, table: &[u64], non_zero_flags: u64, ) -> io::Result<()>63     pub fn write_pointer_table(
64         &mut self,
65         offset: u64,
66         table: &[u64],
67         non_zero_flags: u64,
68     ) -> io::Result<()> {
69         self.file.seek(SeekFrom::Start(offset))?;
70         let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u64>(), &self.file);
71         for addr in table {
72             let val = if *addr == 0 {
73                 0
74             } else {
75                 *addr | non_zero_flags
76             };
77             buffer.write_all(&val.to_be_bytes())?;
78         }
79         Ok(())
80     }
81 
82     /// Read a refcount block from the file and returns a Vec containing the block.
83     /// Always returns a cluster's worth of data.
read_refcount_block(&mut self, offset: u64) -> io::Result<Vec<u16>>84     pub fn read_refcount_block(&mut self, offset: u64) -> io::Result<Vec<u16>> {
85         let count = self.cluster_size / size_of::<u16>() as u64;
86         let mut table = vec![0; count as usize];
87         self.file.seek(SeekFrom::Start(offset))?;
88         for refcount in &mut table {
89             let mut value = [0u8; 2];
90             self.file.read_exact(&mut value)?;
91             *refcount = u16::from_be_bytes(value);
92         }
93         Ok(table)
94     }
95 
96     /// Writes a refcount block to the file.
write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()>97     pub fn write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()> {
98         self.file.seek(SeekFrom::Start(offset))?;
99         let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u16>(), &self.file);
100         for count in table {
101             buffer.write_all(&count.to_be_bytes())?;
102         }
103         Ok(())
104     }
105 
106     /// 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>>107     pub fn add_cluster_end(&mut self, max_valid_cluster_offset: u64) -> io::Result<Option<u64>> {
108         // Determine where the new end of the file should be and set_len, which
109         // translates to truncate(2).
110         let file_end: u64 = self.file.seek(SeekFrom::End(0))?;
111         let new_cluster_address: u64 = (file_end + self.cluster_size - 1) & !self.cluster_mask;
112 
113         if new_cluster_address > max_valid_cluster_offset {
114             return Ok(None);
115         }
116 
117         self.file.set_len(new_cluster_address + self.cluster_size)?;
118 
119         Ok(Some(new_cluster_address))
120     }
121 
122     /// Returns a reference to the underlying file.
file(&self) -> &File123     pub fn file(&self) -> &File {
124         &self.file
125     }
126 
127     /// Returns a mutable reference to the underlying file.
file_mut(&mut self) -> &mut File128     pub fn file_mut(&mut self) -> &mut File {
129         &mut self.file
130     }
131 
132     /// Returns the size of the file's clusters.
cluster_size(&self) -> u64133     pub fn cluster_size(&self) -> u64 {
134         self.cluster_size
135     }
136 
137     /// Returns the offset of `address` within a cluster.
cluster_offset(&self, address: u64) -> u64138     pub fn cluster_offset(&self, address: u64) -> u64 {
139         address & self.cluster_mask
140     }
141 
142     /// Zeros out a cluster in the file.
zero_cluster(&mut self, address: u64) -> io::Result<()>143     pub fn zero_cluster(&mut self, address: u64) -> io::Result<()> {
144         let cluster_size = self.cluster_size as usize;
145         self.file.seek(SeekFrom::Start(address))?;
146         self.file.write_zeroes_all(cluster_size)?;
147         Ok(())
148     }
149 
150     /// Writes
write_cluster(&mut self, address: u64, mut initial_data: Vec<u8>) -> io::Result<()>151     pub fn write_cluster(&mut self, address: u64, mut initial_data: Vec<u8>) -> io::Result<()> {
152         if (initial_data.len() as u64) < self.cluster_size {
153             return Err(io::Error::new(
154                 io::ErrorKind::InvalidInput,
155                 "`initial_data` is too small",
156             ));
157         }
158         let volatile_slice = VolatileSlice::new(&mut initial_data[..self.cluster_size as usize]);
159         self.file.write_all_at_volatile(volatile_slice, address)
160     }
161 }
162