disk/qcow/
mod.rs

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
5mod qcow_raw_file;
6mod refcount;
7mod vec_cache;
8
9use std::cmp::max;
10use std::cmp::min;
11use std::fs::File;
12use std::io;
13use std::io::Read;
14use std::io::Seek;
15use std::io::SeekFrom;
16use std::io::Write;
17use std::mem::size_of;
18use std::path::PathBuf;
19use std::str;
20
21use base::error;
22use base::AsRawDescriptor;
23use base::AsRawDescriptors;
24use base::FileAllocate;
25use base::FileReadWriteAtVolatile;
26use base::FileSetLen;
27use base::FileSync;
28use base::PunchHole;
29use base::RawDescriptor;
30use base::VolatileMemory;
31use base::VolatileSlice;
32use base::WriteZeroesAt;
33use cros_async::Executor;
34use libc::EINVAL;
35use libc::ENOSPC;
36use libc::ENOTSUP;
37use remain::sorted;
38use sync::Mutex;
39use thiserror::Error;
40
41use crate::asynchronous::DiskFlush;
42use crate::qcow::qcow_raw_file::QcowRawFile;
43use crate::qcow::refcount::RefCount;
44use crate::qcow::vec_cache::CacheMap;
45use crate::qcow::vec_cache::Cacheable;
46use crate::qcow::vec_cache::VecCache;
47use crate::AsyncDisk;
48use crate::AsyncDiskFileWrapper;
49use crate::DiskFile;
50use crate::DiskFileParams;
51use crate::DiskGetLen;
52use crate::ToAsyncDisk;
53
54#[sorted]
55#[derive(Error, Debug)]
56pub enum Error {
57    #[error("backing file path escapes the first cluster")]
58    BackingFileEscapesFirstCluster,
59    #[error("backing file io error: {0}")]
60    BackingFileIo(io::Error),
61    #[error("backing file open error: {0}")]
62    BackingFileOpen(Box<crate::Error>),
63    #[error("backing file name is too long: {0} bytes over")]
64    BackingFileTooLong(usize),
65    #[error("compressed blocks not supported")]
66    CompressedBlocksNotSupported,
67    #[error("failed to evict cache: {0}")]
68    EvictingCache(io::Error),
69    #[error("file larger than max of {MAX_QCOW_FILE_SIZE}: {0}")]
70    FileTooBig(u64),
71    #[error("failed to get file size: {0}")]
72    GettingFileSize(io::Error),
73    #[error("failed to get refcount: {0}")]
74    GettingRefcount(refcount::Error),
75    #[error("failed to parse filename: {0}")]
76    InvalidBackingFileName(str::Utf8Error),
77    #[error("invalid cluster index")]
78    InvalidClusterIndex,
79    #[error("invalid cluster size")]
80    InvalidClusterSize,
81    #[error("failed to parse header extension")]
82    InvalidHeaderExtension,
83    #[error("invalid index")]
84    InvalidIndex,
85    #[error("invalid L1 table offset")]
86    InvalidL1TableOffset,
87    #[error("invalid L1 table size {0}")]
88    InvalidL1TableSize(u32),
89    #[error("invalid magic")]
90    InvalidMagic,
91    #[error("invalid offset")]
92    InvalidOffset(u64),
93    #[error("invalid refcount table offset")]
94    InvalidRefcountTableOffset,
95    #[error("invalid refcount table size: {0}")]
96    InvalidRefcountTableSize(u64),
97    #[error("backing file format extension is missing")]
98    MissingBackingFileFormat,
99    #[error("no free clusters")]
100    NoFreeClusters,
101    #[error("no refcount clusters")]
102    NoRefcountClusters,
103    #[error("not enough space for refcounts")]
104    NotEnoughSpaceForRefcounts,
105    #[error("failed to open file: {0}")]
106    OpeningFile(io::Error),
107    #[error("failed to open file: {0}")]
108    ReadingHeader(io::Error),
109    #[error("failed to read pointers: {0}")]
110    ReadingPointers(io::Error),
111    #[error("failed to read ref count block: {0}")]
112    ReadingRefCountBlock(refcount::Error),
113    #[error("failed to read ref counts: {0}")]
114    ReadingRefCounts(io::Error),
115    #[error("failed to rebuild ref counts: {0}")]
116    RebuildingRefCounts(io::Error),
117    #[error("refcount table offset past file end")]
118    RefcountTableOffEnd,
119    #[error("too many clusters specified for refcount table")]
120    RefcountTableTooLarge,
121    #[error("failed to seek file: {0}")]
122    SeekingFile(io::Error),
123    #[error("failed to set refcount refcount: {0}")]
124    SettingRefcountRefcount(io::Error),
125    #[error("size too small for number of clusters")]
126    SizeTooSmallForNumberOfClusters,
127    #[error("l1 entry table too large: {0}")]
128    TooManyL1Entries(u64),
129    #[error("ref count table too large: {0}")]
130    TooManyRefcounts(u64),
131    #[error("unsupported backing file format: {0}")]
132    UnsupportedBackingFileFormat(String),
133    #[error("unsupported refcount order")]
134    UnsupportedRefcountOrder,
135    #[error("unsupported version: {0}")]
136    UnsupportedVersion(u32),
137    #[error("failed to write header: {0}")]
138    WritingHeader(io::Error),
139}
140
141pub type Result<T> = std::result::Result<T, Error>;
142
143// Maximum data size supported.
144const MAX_QCOW_FILE_SIZE: u64 = 0x01 << 44; // 16 TB.
145
146// QCOW magic constant that starts the header.
147pub const QCOW_MAGIC: u32 = 0x5146_49fb;
148// Default to a cluster size of 2^DEFAULT_CLUSTER_BITS
149const DEFAULT_CLUSTER_BITS: u32 = 16;
150// Limit clusters to reasonable sizes. Choose the same limits as qemu. Making the clusters smaller
151// increases the amount of overhead for book keeping.
152const MIN_CLUSTER_BITS: u32 = 9;
153const MAX_CLUSTER_BITS: u32 = 21;
154// The L1 and RefCount table are kept in RAM, only handle files that require less than 35M entries.
155// This easily covers 1 TB files. When support for bigger files is needed the assumptions made to
156// keep these tables in RAM needs to be thrown out.
157const MAX_RAM_POINTER_TABLE_SIZE: u64 = 35_000_000;
158// Only support 2 byte refcounts, 2^refcount_order bits.
159const DEFAULT_REFCOUNT_ORDER: u32 = 4;
160
161const V3_BARE_HEADER_SIZE: u32 = 104;
162
163// bits 0-8 and 56-63 are reserved.
164const L1_TABLE_OFFSET_MASK: u64 = 0x00ff_ffff_ffff_fe00;
165const L2_TABLE_OFFSET_MASK: u64 = 0x00ff_ffff_ffff_fe00;
166// Flags
167const COMPRESSED_FLAG: u64 = 1 << 62;
168const CLUSTER_USED_FLAG: u64 = 1 << 63;
169const COMPATIBLE_FEATURES_LAZY_REFCOUNTS: u64 = 1 << 0;
170
171// The format supports a "header extension area".
172const QCOW2_EXT_MAGIC_BACKING_FORMAT: u32 = 0xe279_268f;
173
174// Defined by the specification
175const MAX_BACKING_FILE_SIZE: u32 = 1023;
176
177/// Contains the information from the header of a qcow file.
178#[derive(Clone, Debug)]
179pub struct QcowHeader {
180    pub magic: u32,
181    pub version: u32,
182
183    pub backing_file_offset: u64,
184    pub backing_file_size: u32,
185
186    pub cluster_bits: u32,
187    pub size: u64,
188    pub crypt_method: u32,
189
190    pub l1_size: u32,
191    pub l1_table_offset: u64,
192
193    pub refcount_table_offset: u64,
194    pub refcount_table_clusters: u32,
195
196    pub nb_snapshots: u32,
197    pub snapshots_offset: u64,
198
199    // v3 entries
200    pub incompatible_features: u64,
201    pub compatible_features: u64,
202    pub autoclear_features: u64,
203    pub refcount_order: u32,
204    pub header_size: u32,
205
206    // Post-header entries
207    pub backing_file_path: Option<String>,
208    pub backing_file_format: Option<crate::ImageType>,
209}
210
211// Reads the next u16 from the file.
212fn read_u16_from_file(mut f: &File) -> Result<u16> {
213    let mut value = [0u8; 2];
214    (&mut f)
215        .read_exact(&mut value)
216        .map_err(Error::ReadingHeader)?;
217    Ok(u16::from_be_bytes(value))
218}
219
220// Reads the next u32 from the file.
221fn read_u32_from_file(mut f: &File) -> Result<u32> {
222    let mut value = [0u8; 4];
223    (&mut f)
224        .read_exact(&mut value)
225        .map_err(Error::ReadingHeader)?;
226    Ok(u32::from_be_bytes(value))
227}
228
229// Reads the next u64 from the file.
230fn read_u64_from_file(mut f: &File) -> Result<u64> {
231    let mut value = [0u8; 8];
232    (&mut f)
233        .read_exact(&mut value)
234        .map_err(Error::ReadingHeader)?;
235    Ok(u64::from_be_bytes(value))
236}
237
238fn image_type_to_format_str(image_type: crate::ImageType) -> Result<&'static str> {
239    match image_type {
240        crate::ImageType::Raw => Ok("raw"),
241        crate::ImageType::Qcow2 => Ok("qcow2"),
242        crate::ImageType::CompositeDisk => Ok("composite"),
243        other => Err(Error::UnsupportedBackingFileFormat(format!("{other:?}"))),
244    }
245}
246
247fn format_str_to_image_type(s: &str) -> Result<crate::ImageType> {
248    match s {
249        "raw" => Ok(crate::ImageType::Raw),
250        "qcow2" => Ok(crate::ImageType::Qcow2),
251        "composite" => Ok(crate::ImageType::CompositeDisk),
252        other => Err(Error::UnsupportedBackingFileFormat(other.to_string())),
253    }
254}
255
256impl QcowHeader {
257    /// Creates a QcowHeader from a reference to a file.
258    pub fn new(f: &mut File) -> Result<QcowHeader> {
259        f.seek(SeekFrom::Start(0)).map_err(Error::ReadingHeader)?;
260
261        let magic = read_u32_from_file(f)?;
262        if magic != QCOW_MAGIC {
263            return Err(Error::InvalidMagic);
264        }
265
266        let mut header = QcowHeader {
267            magic,
268            version: read_u32_from_file(f)?,
269            backing_file_offset: read_u64_from_file(f)?,
270            backing_file_size: read_u32_from_file(f)?,
271            cluster_bits: read_u32_from_file(f)?,
272            size: read_u64_from_file(f)?,
273            crypt_method: read_u32_from_file(f)?,
274            l1_size: read_u32_from_file(f)?,
275            l1_table_offset: read_u64_from_file(f)?,
276            refcount_table_offset: read_u64_from_file(f)?,
277            refcount_table_clusters: read_u32_from_file(f)?,
278            nb_snapshots: read_u32_from_file(f)?,
279            snapshots_offset: read_u64_from_file(f)?,
280            incompatible_features: read_u64_from_file(f)?,
281            compatible_features: read_u64_from_file(f)?,
282            autoclear_features: read_u64_from_file(f)?,
283            refcount_order: read_u32_from_file(f)?,
284            header_size: read_u32_from_file(f)?,
285            backing_file_path: None,
286            backing_file_format: None,
287        };
288
289        if !(MIN_CLUSTER_BITS..=MAX_CLUSTER_BITS).contains(&header.cluster_bits) {
290            return Err(Error::InvalidClusterSize);
291        }
292
293        let cluster_size = 1u64 << header.cluster_bits;
294
295        if header.backing_file_offset != 0 {
296            let backing_file_end = header
297                .backing_file_offset
298                .checked_add(header.backing_file_size as u64)
299                .ok_or(Error::BackingFileEscapesFirstCluster)?;
300            if backing_file_end > cluster_size {
301                return Err(Error::BackingFileEscapesFirstCluster);
302            }
303        }
304
305        let (backing_file_format, backing_file_path) = Self::parse_backing_info(
306            f,
307            header.header_size,
308            cluster_size,
309            header.backing_file_offset,
310            header.backing_file_size,
311        )?;
312        header.backing_file_format = backing_file_format;
313        header.backing_file_path = backing_file_path;
314        Ok(header)
315    }
316
317    fn parse_backing_info(
318        f: &mut File,
319        header_size: u32,
320        cluster_size: u64,
321        backing_file_offset: u64,
322        backing_file_size: u32,
323    ) -> Result<(Option<crate::ImageType>, Option<String>)> {
324        let mut backing_file_format = None;
325        let mut ext_offset = (header_size as u64 + 7) & !7;
326
327        // Avoid reading past the first cluster or past backing_file_offset if it is set.
328        let limit = if backing_file_offset != 0 {
329            backing_file_offset
330        } else {
331            cluster_size
332        };
333
334        loop {
335            if ext_offset >= limit {
336                break;
337            }
338
339            let next_offset = ext_offset
340                .checked_add(8)
341                .ok_or(Error::InvalidHeaderExtension)?;
342            if next_offset > limit {
343                return Err(Error::InvalidHeaderExtension);
344            }
345
346            f.seek(SeekFrom::Start(ext_offset))
347                .map_err(Error::ReadingHeader)?;
348            let ext_type = read_u32_from_file(f)?;
349            let ext_len = read_u32_from_file(f)?;
350            if ext_type == 0 {
351                break;
352            }
353
354            let ext_end = next_offset
355                .checked_add(ext_len as u64)
356                .ok_or(Error::InvalidHeaderExtension)?;
357            if ext_end > limit {
358                return Err(Error::InvalidHeaderExtension);
359            }
360
361            if ext_type == QCOW2_EXT_MAGIC_BACKING_FORMAT {
362                let mut backing_format_bytes = vec![0u8; ext_len as usize];
363                f.read_exact(&mut backing_format_bytes)
364                    .map_err(Error::ReadingHeader)?;
365                let format_str = String::from_utf8(backing_format_bytes)
366                    .map_err(|_| Error::InvalidHeaderExtension)?;
367                let format = format_str_to_image_type(&format_str)?;
368                backing_file_format = Some(format);
369            }
370
371            let padded_len = (ext_len as u64 + 7) & !7;
372            let increment = padded_len
373                .checked_add(8)
374                .ok_or(Error::InvalidHeaderExtension)?;
375            ext_offset = ext_offset
376                .checked_add(increment)
377                .ok_or(Error::InvalidHeaderExtension)?;
378        }
379
380        if backing_file_size > MAX_BACKING_FILE_SIZE {
381            return Err(Error::BackingFileTooLong(backing_file_size as usize));
382        }
383        let backing_file_path = if backing_file_offset != 0 {
384            f.seek(SeekFrom::Start(backing_file_offset))
385                .map_err(Error::ReadingHeader)?;
386            let mut backing_file_name_bytes = vec![0u8; backing_file_size as usize];
387            f.read_exact(&mut backing_file_name_bytes)
388                .map_err(Error::ReadingHeader)?;
389            Some(
390                String::from_utf8(backing_file_name_bytes)
391                    .map_err(|err| Error::InvalidBackingFileName(err.utf8_error()))?,
392            )
393        } else {
394            None
395        };
396
397        Ok((backing_file_format, backing_file_path))
398    }
399
400    pub fn create_for_size_and_path(
401        size: u64,
402        backing: Option<(&str, crate::ImageType)>,
403    ) -> Result<QcowHeader> {
404        let cluster_bits: u32 = DEFAULT_CLUSTER_BITS;
405        let cluster_size: u32 = 0x01 << cluster_bits;
406        let mut ext_size = 8; // For end marker
407        let (backing_file, backing_file_format) = match backing {
408            Some((path, format)) => {
409                let format_str = image_type_to_format_str(format)?;
410                let format_len = format_str.len() as u32;
411                ext_size += 8 + ((format_len + 7) & !7);
412                (Some(path), Some(format))
413            }
414            None => (None, None),
415        };
416        let max_length: usize = (cluster_size - V3_BARE_HEADER_SIZE - ext_size) as usize;
417        if let Some(path) = backing_file {
418            if path.len() > max_length {
419                return Err(Error::BackingFileTooLong(path.len() - max_length));
420            }
421        }
422        if size > MAX_QCOW_FILE_SIZE {
423            return Err(Error::FileTooBig(size));
424        }
425        // L2 blocks are always one cluster long. They contain cluster_size/sizeof(u64) addresses.
426        let l2_size: u32 = cluster_size / size_of::<u64>() as u32;
427        let num_clusters: u32 = size.div_ceil(u64::from(cluster_size)) as u32;
428        let num_l2_clusters: u32 = num_clusters.div_ceil(l2_size);
429        let l1_clusters: u32 = num_l2_clusters.div_ceil(cluster_size);
430        let header_clusters = (size_of::<QcowHeader>() as u32).div_ceil(cluster_size);
431        Ok(QcowHeader {
432            magic: QCOW_MAGIC,
433            version: 3,
434            backing_file_offset: if backing_file.is_none() {
435                0
436            } else {
437                V3_BARE_HEADER_SIZE as u64 + ext_size as u64
438            },
439            backing_file_size: backing_file.map_or(0, |x| x.len()) as u32,
440            cluster_bits: DEFAULT_CLUSTER_BITS,
441            size,
442            crypt_method: 0,
443            l1_size: num_l2_clusters,
444            l1_table_offset: u64::from(cluster_size),
445            // The refcount table is after l1 + header.
446            refcount_table_offset: u64::from(cluster_size * (l1_clusters + 1)),
447            refcount_table_clusters: {
448                // Pre-allocate enough clusters for the entire refcount table as it must be
449                // continuous in the file. Allocate enough space to refcount all clusters, including
450                // the refcount clusters.
451                let max_refcount_clusters = max_refcount_clusters(
452                    DEFAULT_REFCOUNT_ORDER,
453                    cluster_size,
454                    num_clusters + l1_clusters + num_l2_clusters + header_clusters,
455                ) as u32;
456                // The refcount table needs to store the offset of each refcount cluster.
457                (max_refcount_clusters * size_of::<u64>() as u32).div_ceil(cluster_size)
458            },
459            nb_snapshots: 0,
460            snapshots_offset: 0,
461            incompatible_features: 0,
462            compatible_features: 0,
463            autoclear_features: 0,
464            refcount_order: DEFAULT_REFCOUNT_ORDER,
465            header_size: V3_BARE_HEADER_SIZE,
466            backing_file_path: backing_file.map(String::from),
467            backing_file_format,
468        })
469    }
470
471    /// Write the header to `file`.
472    pub fn write_to<F: Write + Seek>(&self, file: &mut F) -> Result<()> {
473        // Writes the next u32 to the file.
474        fn write_u32_to_file<F: Write>(f: &mut F, value: u32) -> Result<()> {
475            f.write_all(&value.to_be_bytes())
476                .map_err(Error::WritingHeader)
477        }
478
479        // Writes the next u64 to the file.
480        fn write_u64_to_file<F: Write>(f: &mut F, value: u64) -> Result<()> {
481            f.write_all(&value.to_be_bytes())
482                .map_err(Error::WritingHeader)
483        }
484
485        write_u32_to_file(file, self.magic)?;
486        write_u32_to_file(file, self.version)?;
487        write_u64_to_file(file, self.backing_file_offset)?;
488        write_u32_to_file(file, self.backing_file_size)?;
489        write_u32_to_file(file, self.cluster_bits)?;
490        write_u64_to_file(file, self.size)?;
491        write_u32_to_file(file, self.crypt_method)?;
492        write_u32_to_file(file, self.l1_size)?;
493        write_u64_to_file(file, self.l1_table_offset)?;
494        write_u64_to_file(file, self.refcount_table_offset)?;
495        write_u32_to_file(file, self.refcount_table_clusters)?;
496        write_u32_to_file(file, self.nb_snapshots)?;
497        write_u64_to_file(file, self.snapshots_offset)?;
498        write_u64_to_file(file, self.incompatible_features)?;
499        write_u64_to_file(file, self.compatible_features)?;
500        write_u64_to_file(file, self.autoclear_features)?;
501        write_u32_to_file(file, self.refcount_order)?;
502        write_u32_to_file(file, self.header_size)?;
503        if let Some(format) = self.backing_file_format {
504            let format_str = image_type_to_format_str(format)?;
505            write_u32_to_file(file, QCOW2_EXT_MAGIC_BACKING_FORMAT)?;
506            write_u32_to_file(file, format_str.len() as u32)?;
507            file.write_all(format_str.as_bytes())
508                .map_err(Error::WritingHeader)?;
509            // Pad to 8-byte boundary
510            let padding = ((format_str.len() + 7) & !7) - format_str.len();
511            if padding > 0 {
512                const ZEROES: [u8; 8] = [0u8; 8];
513                file.write_all(&ZEROES[..padding])
514                    .map_err(Error::WritingHeader)?;
515            }
516        }
517        write_u32_to_file(file, 0)?; // header extension type: end of header extension area
518        write_u32_to_file(file, 0)?; // length of header extension data: 0
519        if let Some(backing_file_path) = self.backing_file_path.as_ref() {
520            write!(file, "{backing_file_path}").map_err(Error::WritingHeader)?;
521        }
522
523        // Set the file length by seeking and writing a zero to the last byte. This avoids needing
524        // a `File` instead of anything that implements seek as the `file` argument.
525        // Zeros out the l1 and refcount table clusters.
526        let cluster_size = 0x01u64 << self.cluster_bits;
527        let refcount_blocks_size = u64::from(self.refcount_table_clusters) * cluster_size;
528        file.seek(SeekFrom::Start(
529            self.refcount_table_offset + refcount_blocks_size - 2,
530        ))
531        .map_err(Error::WritingHeader)?;
532        file.write(&[0u8]).map_err(Error::WritingHeader)?;
533
534        Ok(())
535    }
536}
537
538fn max_refcount_clusters(refcount_order: u32, cluster_size: u32, num_clusters: u32) -> u64 {
539    // Use u64 as the product of the u32 inputs can overflow.
540    let refcount_bytes = (0x01 << refcount_order as u64) / 8;
541    let for_data = (u64::from(num_clusters) * refcount_bytes).div_ceil(u64::from(cluster_size));
542    let for_refcounts = (for_data * refcount_bytes).div_ceil(u64::from(cluster_size));
543    for_data + for_refcounts
544}
545
546/// Represents a qcow2 file. This is a sparse file format maintained by the qemu project.
547/// Full documentation of the format can be found in the qemu repository.
548///
549/// # Example
550///
551/// ```
552/// # use std::path::PathBuf;
553/// # use base::FileReadWriteAtVolatile;
554/// # use disk::QcowFile;
555/// # use disk::DiskFileParams;
556/// # use base::VolatileSlice;
557/// # fn test(file: std::fs::File, path: PathBuf) -> std::io::Result<()> {
558///     let mut q = QcowFile::from(file, DiskFileParams {
559///         path,
560///         ..Default::default()
561///     }).expect("Can't open qcow file");
562///     let mut buf = [0u8; 12];
563///     let mut vslice = VolatileSlice::new(&mut buf);
564///     q.read_at_volatile(vslice, 10)?;
565/// #   Ok(())
566/// # }
567/// ```
568#[derive(Debug)]
569pub struct QcowFile {
570    inner: Mutex<QcowFileInner>,
571    // Copy of `inner.header.size` outside the mutex.
572    virtual_size: u64,
573}
574
575#[derive(Debug)]
576struct QcowFileInner {
577    raw_file: QcowRawFile,
578    header: QcowHeader,
579    l1_table: VecCache<u64>,
580    l2_entries: u64,
581    l2_cache: CacheMap<VecCache<u64>>,
582    refcounts: RefCount,
583    current_offset: u64,
584    unref_clusters: Vec<u64>, // List of freshly unreferenced clusters.
585    // List of unreferenced clusters available to be used. unref clusters become available once the
586    // removal of references to them have been synced to disk.
587    avail_clusters: Vec<u64>,
588    backing_file: Option<Box<dyn DiskFile>>,
589}
590
591impl DiskFile for QcowFile {}
592
593impl DiskFlush for QcowFile {
594    fn flush(&self) -> io::Result<()> {
595        // Using fsync is overkill here, but, the code for flushing state to file tangled up with
596        // the fsync, so it is best we can do for now.
597        self.fsync()
598    }
599}
600
601impl QcowFile {
602    /// Creates a QcowFile from `file`. File must be a valid qcow2 image.
603    pub fn from(mut file: File, params: DiskFileParams) -> Result<QcowFile> {
604        let header = QcowHeader::new(&mut file)?;
605
606        // Only v3 files are supported.
607        if header.version != 3 {
608            return Err(Error::UnsupportedVersion(header.version));
609        }
610
611        // Make sure that the L1 table fits in RAM.
612        if u64::from(header.l1_size) > MAX_RAM_POINTER_TABLE_SIZE {
613            return Err(Error::InvalidL1TableSize(header.l1_size));
614        }
615
616        let cluster_bits: u32 = header.cluster_bits;
617        if !(MIN_CLUSTER_BITS..=MAX_CLUSTER_BITS).contains(&cluster_bits) {
618            return Err(Error::InvalidClusterSize);
619        }
620        let cluster_size = 0x01u64 << cluster_bits;
621
622        // Limit the total size of the disk.
623        if header.size > MAX_QCOW_FILE_SIZE {
624            return Err(Error::FileTooBig(header.size));
625        }
626
627        let backing_file = if let Some(backing_file_path) = header.backing_file_path.as_ref() {
628            let backing_params = DiskFileParams {
629                path: PathBuf::from(backing_file_path),
630                // The backing file is only read from.
631                is_read_only: true,
632                // TODO: Should pass `params.is_overlapped` through here. Needs testing.
633                // is_overlapped: false,
634                is_direct: params.is_direct,
635                lock: params.lock,
636                depth: params.depth + 1,
637                ..Default::default()
638            };
639            let backing_image_type = match header.backing_file_format {
640                Some(format) => format,
641                None => return Err(Error::MissingBackingFileFormat),
642            };
643            let backing_disk_file = crate::open_disk_file_as(backing_params, backing_image_type)
644                .map_err(|e| Error::BackingFileOpen(Box::new(e)))?;
645            Some(backing_disk_file)
646        } else {
647            None
648        };
649
650        // Only support two byte refcounts.
651        let refcount_bits: u64 = 0x01u64
652            .checked_shl(header.refcount_order)
653            .ok_or(Error::UnsupportedRefcountOrder)?;
654        if refcount_bits != 16 {
655            return Err(Error::UnsupportedRefcountOrder);
656        }
657        let refcount_bytes = refcount_bits.div_ceil(8);
658
659        // Need at least one refcount cluster
660        if header.refcount_table_clusters == 0 {
661            return Err(Error::NoRefcountClusters);
662        }
663        offset_is_cluster_boundary(header.l1_table_offset, header.cluster_bits)?;
664        offset_is_cluster_boundary(header.snapshots_offset, header.cluster_bits)?;
665        // refcount table must be a cluster boundary, and within the file's virtual or actual size.
666        offset_is_cluster_boundary(header.refcount_table_offset, header.cluster_bits)?;
667        let file_size = file.metadata().map_err(Error::GettingFileSize)?.len();
668        if header.refcount_table_offset > max(file_size, header.size) {
669            return Err(Error::RefcountTableOffEnd);
670        }
671
672        // The first cluster should always have a non-zero refcount, so if it is 0,
673        // this is an old file with broken refcounts, which requires a rebuild.
674        let mut refcount_rebuild_required = true;
675        file.seek(SeekFrom::Start(header.refcount_table_offset))
676            .map_err(Error::SeekingFile)?;
677        let first_refblock_addr = read_u64_from_file(&file)?;
678        if first_refblock_addr != 0 {
679            file.seek(SeekFrom::Start(first_refblock_addr))
680                .map_err(Error::SeekingFile)?;
681            let first_cluster_refcount = read_u16_from_file(&file)?;
682            if first_cluster_refcount != 0 {
683                refcount_rebuild_required = false;
684            }
685        }
686
687        if (header.compatible_features & COMPATIBLE_FEATURES_LAZY_REFCOUNTS) != 0 {
688            refcount_rebuild_required = true;
689        }
690
691        let mut raw_file =
692            QcowRawFile::from(file, cluster_size).ok_or(Error::InvalidClusterSize)?;
693        if refcount_rebuild_required {
694            QcowFileInner::rebuild_refcounts(&mut raw_file, header.clone())?;
695        }
696
697        let l2_size = cluster_size / size_of::<u64>() as u64;
698        let num_clusters = header.size.div_ceil(cluster_size);
699        let num_l2_clusters = num_clusters.div_ceil(l2_size);
700        let l1_clusters = num_l2_clusters.div_ceil(cluster_size);
701        let header_clusters = (size_of::<QcowHeader>() as u64).div_ceil(cluster_size);
702        if num_l2_clusters > MAX_RAM_POINTER_TABLE_SIZE {
703            return Err(Error::TooManyL1Entries(num_l2_clusters));
704        }
705        let l1_table = VecCache::from_vec(
706            raw_file
707                .read_pointer_table(
708                    header.l1_table_offset,
709                    num_l2_clusters,
710                    Some(L1_TABLE_OFFSET_MASK),
711                )
712                .map_err(Error::ReadingHeader)?,
713        );
714
715        let num_clusters = header.size.div_ceil(cluster_size);
716        let refcount_clusters = max_refcount_clusters(
717            header.refcount_order,
718            cluster_size as u32,
719            (num_clusters + l1_clusters + num_l2_clusters + header_clusters) as u32,
720        );
721        // Check that the given header doesn't have a suspiciously sized refcount table.
722        if u64::from(header.refcount_table_clusters) > 2 * refcount_clusters {
723            return Err(Error::RefcountTableTooLarge);
724        }
725        if l1_clusters + refcount_clusters > MAX_RAM_POINTER_TABLE_SIZE {
726            return Err(Error::TooManyRefcounts(refcount_clusters));
727        }
728        let refcount_block_entries = cluster_size / refcount_bytes;
729        let refcounts = RefCount::new(
730            &mut raw_file,
731            header.refcount_table_offset,
732            refcount_clusters,
733            refcount_block_entries,
734            cluster_size,
735        )
736        .map_err(Error::ReadingRefCounts)?;
737
738        let l2_entries = cluster_size / size_of::<u64>() as u64;
739
740        let mut inner = QcowFileInner {
741            raw_file,
742            header,
743            l1_table,
744            l2_entries,
745            l2_cache: CacheMap::new(100),
746            refcounts,
747            current_offset: 0,
748            unref_clusters: Vec::new(),
749            avail_clusters: Vec::new(),
750            backing_file,
751        };
752
753        // Check that the L1 and refcount tables fit in a 64bit address space.
754        inner
755            .header
756            .l1_table_offset
757            .checked_add(inner.l1_address_offset(inner.virtual_size()))
758            .ok_or(Error::InvalidL1TableOffset)?;
759        inner
760            .header
761            .refcount_table_offset
762            .checked_add(u64::from(inner.header.refcount_table_clusters) * cluster_size)
763            .ok_or(Error::InvalidRefcountTableOffset)?;
764
765        inner.find_avail_clusters()?;
766
767        let virtual_size = inner.virtual_size();
768        Ok(QcowFile {
769            inner: Mutex::new(inner),
770            virtual_size,
771        })
772    }
773
774    /// Creates a new QcowFile at the given path.
775    pub fn new(file: File, params: DiskFileParams, virtual_size: u64) -> Result<QcowFile> {
776        let header = QcowHeader::create_for_size_and_path(virtual_size, None)?;
777        QcowFile::new_from_header(file, params, header)
778    }
779
780    /// Creates a new QcowFile at the given path.
781    pub fn new_from_backing(
782        file: File,
783        params: DiskFileParams,
784        backing_file_name: &str,
785    ) -> Result<QcowFile> {
786        // Open the backing file as a `DiskFile` to determine its size (which may not match the
787        // filesystem size).
788        let (size, backing_format) = {
789            let backing_params = DiskFileParams {
790                path: PathBuf::from(backing_file_name),
791                // The backing file is only read from.
792                is_read_only: true,
793                // TODO: Should pass `params.is_overlapped` through here. Needs testing.
794                // is_overlapped: false,
795                is_direct: params.is_direct,
796                lock: params.lock,
797                depth: params.depth + 1,
798                ..Default::default()
799            };
800            let backing_file = crate::sys::open_raw_disk_image(&backing_params)
801                .map_err(|e| Error::BackingFileOpen(Box::new(e)))?;
802            let backing_image_type = crate::detect_image_type(&backing_file, false)
803                .map_err(|e| Error::BackingFileOpen(Box::new(e)))?;
804            let backing_disk_file =
805                crate::disk_file_from_file(backing_file, backing_params, backing_image_type)
806                    .map_err(|e| Error::BackingFileOpen(Box::new(e)))?;
807            (
808                backing_disk_file.get_len().map_err(Error::BackingFileIo)?,
809                backing_image_type,
810            )
811        };
812        let header =
813            QcowHeader::create_for_size_and_path(size, Some((backing_file_name, backing_format)))?;
814        QcowFile::new_from_header(file, params, header)
815    }
816
817    fn new_from_header(
818        mut file: File,
819        params: DiskFileParams,
820        header: QcowHeader,
821    ) -> Result<QcowFile> {
822        file.seek(SeekFrom::Start(0)).map_err(Error::SeekingFile)?;
823        header.write_to(&mut file)?;
824
825        let mut qcow = Self::from(file, params)?;
826        let inner = qcow.inner.get_mut();
827
828        // Set the refcount for each refcount table cluster.
829        let cluster_size = 0x01u64 << inner.header.cluster_bits;
830        let refcount_table_base = inner.header.refcount_table_offset;
831        let end_cluster_addr =
832            refcount_table_base + u64::from(inner.header.refcount_table_clusters) * cluster_size;
833
834        let mut cluster_addr = 0;
835        while cluster_addr < end_cluster_addr {
836            let mut unref_clusters = inner
837                .set_cluster_refcount(cluster_addr, 1)
838                .map_err(Error::SettingRefcountRefcount)?;
839            inner.unref_clusters.append(&mut unref_clusters);
840            cluster_addr += cluster_size;
841        }
842
843        Ok(qcow)
844    }
845
846    pub fn set_backing_file(&mut self, backing: Option<Box<dyn DiskFile>>) {
847        self.inner.get_mut().backing_file = backing;
848    }
849}
850
851impl QcowFileInner {
852    /// Returns the first cluster in the file with a 0 refcount. Used for testing.
853    #[cfg(test)]
854    fn first_zero_refcount(&mut self) -> Result<Option<u64>> {
855        let file_size = self
856            .raw_file
857            .file_mut()
858            .metadata()
859            .map_err(Error::GettingFileSize)?
860            .len();
861        let cluster_size = 0x01u64 << self.header.cluster_bits;
862
863        let mut cluster_addr = 0;
864        while cluster_addr < file_size {
865            let cluster_refcount = self
866                .refcounts
867                .get_cluster_refcount(&mut self.raw_file, cluster_addr)
868                .map_err(Error::GettingRefcount)?;
869            if cluster_refcount == 0 {
870                return Ok(Some(cluster_addr));
871            }
872            cluster_addr += cluster_size;
873        }
874        Ok(None)
875    }
876
877    fn find_avail_clusters(&mut self) -> Result<()> {
878        let cluster_size = self.raw_file.cluster_size();
879
880        let file_size = self
881            .raw_file
882            .file_mut()
883            .metadata()
884            .map_err(Error::GettingFileSize)?
885            .len();
886
887        for i in (0..file_size).step_by(cluster_size as usize) {
888            let refcount = self
889                .refcounts
890                .get_cluster_refcount(&mut self.raw_file, i)
891                .map_err(Error::GettingRefcount)?;
892            if refcount == 0 {
893                self.avail_clusters.push(i);
894            }
895        }
896
897        Ok(())
898    }
899
900    /// Rebuild the reference count tables.
901    fn rebuild_refcounts(raw_file: &mut QcowRawFile, header: QcowHeader) -> Result<()> {
902        fn add_ref(refcounts: &mut [u16], cluster_size: u64, cluster_address: u64) -> Result<()> {
903            let idx = (cluster_address / cluster_size) as usize;
904            if idx >= refcounts.len() {
905                return Err(Error::InvalidClusterIndex);
906            }
907            refcounts[idx] += 1;
908            Ok(())
909        }
910
911        // Add a reference to the first cluster (header plus extensions).
912        fn set_header_refcount(refcounts: &mut [u16], cluster_size: u64) -> Result<()> {
913            add_ref(refcounts, cluster_size, 0)
914        }
915
916        // Add references to the L1 table clusters.
917        fn set_l1_refcounts(
918            refcounts: &mut [u16],
919            header: QcowHeader,
920            cluster_size: u64,
921        ) -> Result<()> {
922            let l1_clusters = u64::from(header.l1_size).div_ceil(cluster_size);
923            let l1_table_offset = header.l1_table_offset;
924            for i in 0..l1_clusters {
925                add_ref(refcounts, cluster_size, l1_table_offset + i * cluster_size)?;
926            }
927            Ok(())
928        }
929
930        // Traverse the L1 and L2 tables to find all reachable data clusters.
931        fn set_data_refcounts(
932            refcounts: &mut [u16],
933            header: QcowHeader,
934            cluster_size: u64,
935            raw_file: &mut QcowRawFile,
936        ) -> Result<()> {
937            let l1_table = raw_file
938                .read_pointer_table(
939                    header.l1_table_offset,
940                    header.l1_size as u64,
941                    Some(L1_TABLE_OFFSET_MASK),
942                )
943                .map_err(Error::ReadingPointers)?;
944            for l1_index in 0..header.l1_size as usize {
945                let l2_addr_disk = *l1_table.get(l1_index).ok_or(Error::InvalidIndex)?;
946                if l2_addr_disk != 0 {
947                    // Add a reference to the L2 table cluster itself.
948                    add_ref(refcounts, cluster_size, l2_addr_disk)?;
949
950                    // Read the L2 table and find all referenced data clusters.
951                    let l2_table = raw_file
952                        .read_pointer_table(
953                            l2_addr_disk,
954                            cluster_size / size_of::<u64>() as u64,
955                            Some(L2_TABLE_OFFSET_MASK),
956                        )
957                        .map_err(Error::ReadingPointers)?;
958                    for data_cluster_addr in l2_table {
959                        if data_cluster_addr != 0 {
960                            add_ref(refcounts, cluster_size, data_cluster_addr)?;
961                        }
962                    }
963                }
964            }
965
966            Ok(())
967        }
968
969        // Add references to the top-level refcount table clusters.
970        fn set_refcount_table_refcounts(
971            refcounts: &mut [u16],
972            header: QcowHeader,
973            cluster_size: u64,
974        ) -> Result<()> {
975            let refcount_table_offset = header.refcount_table_offset;
976            for i in 0..header.refcount_table_clusters as u64 {
977                add_ref(
978                    refcounts,
979                    cluster_size,
980                    refcount_table_offset + i * cluster_size,
981                )?;
982            }
983            Ok(())
984        }
985
986        // Allocate clusters for refblocks.
987        // This needs to be done last so that we have the correct refcounts for all other
988        // clusters.
989        fn alloc_refblocks(
990            refcounts: &mut [u16],
991            cluster_size: u64,
992            refblock_clusters: u64,
993            pointers_per_cluster: u64,
994        ) -> Result<Vec<u64>> {
995            let refcount_table_entries = refblock_clusters.div_ceil(pointers_per_cluster);
996            let mut ref_table = vec![0; refcount_table_entries as usize];
997            let mut first_free_cluster: u64 = 0;
998            for refblock_addr in &mut ref_table {
999                loop {
1000                    if first_free_cluster >= refcounts.len() as u64 {
1001                        return Err(Error::NotEnoughSpaceForRefcounts);
1002                    }
1003                    if refcounts[first_free_cluster as usize] == 0 {
1004                        break;
1005                    }
1006                    first_free_cluster += 1;
1007                }
1008
1009                *refblock_addr = first_free_cluster * cluster_size;
1010                add_ref(refcounts, cluster_size, *refblock_addr)?;
1011
1012                first_free_cluster += 1;
1013            }
1014
1015            Ok(ref_table)
1016        }
1017
1018        // Write the updated reference count blocks and reftable.
1019        fn write_refblocks(
1020            refcounts: &[u16],
1021            mut header: QcowHeader,
1022            ref_table: &[u64],
1023            raw_file: &mut QcowRawFile,
1024            refcount_block_entries: u64,
1025        ) -> Result<()> {
1026            // Rewrite the header with lazy refcounts enabled while we are rebuilding the tables.
1027            header.compatible_features |= COMPATIBLE_FEATURES_LAZY_REFCOUNTS;
1028            raw_file
1029                .file_mut()
1030                .seek(SeekFrom::Start(0))
1031                .map_err(Error::SeekingFile)?;
1032            header.write_to(raw_file.file_mut())?;
1033
1034            for (i, refblock_addr) in ref_table.iter().enumerate() {
1035                // Write a block of refcounts to the location indicated by refblock_addr.
1036                let refblock_start = i * (refcount_block_entries as usize);
1037                let refblock_end = min(
1038                    refcounts.len(),
1039                    refblock_start + refcount_block_entries as usize,
1040                );
1041                let refblock = &refcounts[refblock_start..refblock_end];
1042                raw_file
1043                    .write_refcount_block(*refblock_addr, refblock)
1044                    .map_err(Error::WritingHeader)?;
1045
1046                // If this is the last (partial) cluster, pad it out to a full refblock cluster.
1047                if refblock.len() < refcount_block_entries as usize {
1048                    let refblock_padding =
1049                        vec![0u16; refcount_block_entries as usize - refblock.len()];
1050                    raw_file
1051                        .write_refcount_block(
1052                            *refblock_addr + refblock.len() as u64 * 2,
1053                            &refblock_padding,
1054                        )
1055                        .map_err(Error::WritingHeader)?;
1056                }
1057            }
1058
1059            // Rewrite the top-level refcount table.
1060            raw_file
1061                .write_pointer_table(header.refcount_table_offset, ref_table, 0)
1062                .map_err(Error::WritingHeader)?;
1063
1064            // Rewrite the header again, now with lazy refcounts disabled.
1065            header.compatible_features &= !COMPATIBLE_FEATURES_LAZY_REFCOUNTS;
1066            raw_file
1067                .file_mut()
1068                .seek(SeekFrom::Start(0))
1069                .map_err(Error::SeekingFile)?;
1070            header.write_to(raw_file.file_mut())?;
1071
1072            Ok(())
1073        }
1074
1075        let cluster_size = raw_file.cluster_size();
1076
1077        let file_size = raw_file
1078            .file_mut()
1079            .metadata()
1080            .map_err(Error::GettingFileSize)?
1081            .len();
1082
1083        let refcount_bits = 1u64 << header.refcount_order;
1084        let refcount_bytes = refcount_bits.div_ceil(8);
1085        let refcount_block_entries = cluster_size / refcount_bytes;
1086        let pointers_per_cluster = cluster_size / size_of::<u64>() as u64;
1087        let data_clusters = header.size.div_ceil(cluster_size);
1088        let l2_clusters = data_clusters.div_ceil(pointers_per_cluster);
1089        let l1_clusters = l2_clusters.div_ceil(cluster_size);
1090        let header_clusters = (size_of::<QcowHeader>() as u64).div_ceil(cluster_size);
1091        let max_clusters = data_clusters + l2_clusters + l1_clusters + header_clusters;
1092        let mut max_valid_cluster_index = max_clusters;
1093        let refblock_clusters = max_valid_cluster_index.div_ceil(refcount_block_entries);
1094        let reftable_clusters = refblock_clusters.div_ceil(pointers_per_cluster);
1095        // Account for refblocks and the ref table size needed to address them.
1096        let refblocks_for_refs =
1097            (refblock_clusters + reftable_clusters).div_ceil(refcount_block_entries);
1098        let reftable_clusters_for_refs = refblocks_for_refs.div_ceil(refcount_block_entries);
1099        max_valid_cluster_index += refblock_clusters + reftable_clusters;
1100        max_valid_cluster_index += refblocks_for_refs + reftable_clusters_for_refs;
1101
1102        if max_valid_cluster_index > MAX_RAM_POINTER_TABLE_SIZE {
1103            return Err(Error::InvalidRefcountTableSize(max_valid_cluster_index));
1104        }
1105
1106        let max_valid_cluster_offset = max_valid_cluster_index * cluster_size;
1107        if max_valid_cluster_offset < file_size - cluster_size {
1108            return Err(Error::InvalidRefcountTableSize(max_valid_cluster_offset));
1109        }
1110
1111        let mut refcounts = vec![0; max_valid_cluster_index as usize];
1112
1113        // Find all references clusters and rebuild refcounts.
1114        set_header_refcount(&mut refcounts, cluster_size)?;
1115        set_l1_refcounts(&mut refcounts, header.clone(), cluster_size)?;
1116        set_data_refcounts(&mut refcounts, header.clone(), cluster_size, raw_file)?;
1117        set_refcount_table_refcounts(&mut refcounts, header.clone(), cluster_size)?;
1118
1119        // Allocate clusters to store the new reference count blocks.
1120        let ref_table = alloc_refblocks(
1121            &mut refcounts,
1122            cluster_size,
1123            refblock_clusters,
1124            pointers_per_cluster,
1125        )?;
1126
1127        // Write updated reference counts and point the reftable at them.
1128        write_refblocks(
1129            &refcounts,
1130            header,
1131            &ref_table,
1132            raw_file,
1133            refcount_block_entries,
1134        )
1135    }
1136
1137    // Limits the range so that it doesn't exceed the virtual size of the file.
1138    fn limit_range_file(&self, address: u64, count: usize) -> usize {
1139        if address.checked_add(count as u64).is_none() || address > self.virtual_size() {
1140            return 0;
1141        }
1142        min(count as u64, self.virtual_size() - address) as usize
1143    }
1144
1145    // Limits the range so that it doesn't overflow the end of a cluster.
1146    fn limit_range_cluster(&self, address: u64, count: usize) -> usize {
1147        let offset: u64 = self.raw_file.cluster_offset(address);
1148        let limit = self.raw_file.cluster_size() - offset;
1149        min(count as u64, limit) as usize
1150    }
1151
1152    // Gets the maximum virtual size of this image.
1153    fn virtual_size(&self) -> u64 {
1154        self.header.size
1155    }
1156
1157    // Gets the offset of `address` in the L1 table.
1158    fn l1_address_offset(&self, address: u64) -> u64 {
1159        let l1_index = self.l1_table_index(address);
1160        l1_index * size_of::<u64>() as u64
1161    }
1162
1163    // Gets the offset of `address` in the L1 table.
1164    fn l1_table_index(&self, address: u64) -> u64 {
1165        (address / self.raw_file.cluster_size()) / self.l2_entries
1166    }
1167
1168    // Gets the offset of `address` in the L2 table.
1169    fn l2_table_index(&self, address: u64) -> u64 {
1170        (address / self.raw_file.cluster_size()) % self.l2_entries
1171    }
1172
1173    // Gets the offset of the given guest address in the host file. If L1, L2, or data clusters have
1174    // yet to be allocated, return None.
1175    fn file_offset_read(&mut self, address: u64) -> std::io::Result<Option<u64>> {
1176        if address >= self.virtual_size() {
1177            return Err(std::io::Error::from_raw_os_error(EINVAL));
1178        }
1179
1180        let l1_index = self.l1_table_index(address) as usize;
1181        let l2_addr_disk = *self
1182            .l1_table
1183            .get(l1_index)
1184            .ok_or_else(|| std::io::Error::from_raw_os_error(EINVAL))?;
1185
1186        if l2_addr_disk == 0 {
1187            // Reading from an unallocated cluster will return zeros.
1188            return Ok(None);
1189        }
1190
1191        let l2_index = self.l2_table_index(address) as usize;
1192
1193        if !self.l2_cache.contains_key(&l1_index) {
1194            // Not in the cache.
1195            let table =
1196                VecCache::from_vec(Self::read_l2_cluster(&mut self.raw_file, l2_addr_disk)?);
1197
1198            let l1_table = &self.l1_table;
1199            let raw_file = &mut self.raw_file;
1200            self.l2_cache.insert(l1_index, table, |index, evicted| {
1201                raw_file.write_pointer_table(
1202                    l1_table[index],
1203                    evicted.get_values(),
1204                    CLUSTER_USED_FLAG,
1205                )
1206            })?;
1207        };
1208
1209        let cluster_addr = self.l2_cache.get(&l1_index).unwrap()[l2_index];
1210        if cluster_addr == 0 {
1211            return Ok(None);
1212        }
1213        Ok(Some(cluster_addr + self.raw_file.cluster_offset(address)))
1214    }
1215
1216    // Gets the offset of the given guest address in the host file. If L1, L2, or data clusters need
1217    // to be allocated, they will be.
1218    fn file_offset_write(&mut self, address: u64) -> std::io::Result<u64> {
1219        if address >= self.virtual_size() {
1220            return Err(std::io::Error::from_raw_os_error(EINVAL));
1221        }
1222
1223        let l1_index = self.l1_table_index(address) as usize;
1224        let l2_addr_disk = *self
1225            .l1_table
1226            .get(l1_index)
1227            .ok_or_else(|| std::io::Error::from_raw_os_error(EINVAL))?;
1228        let l2_index = self.l2_table_index(address) as usize;
1229
1230        let mut set_refcounts = Vec::new();
1231
1232        if !self.l2_cache.contains_key(&l1_index) {
1233            // Not in the cache.
1234            let l2_table = if l2_addr_disk == 0 {
1235                // Allocate a new cluster to store the L2 table and update the L1 table to point
1236                // to the new table.
1237                let new_addr: u64 = self.get_new_cluster(None)?;
1238                // The cluster refcount starts at one meaning it is used but doesn't need COW.
1239                set_refcounts.push((new_addr, 1));
1240                self.l1_table[l1_index] = new_addr;
1241                VecCache::new(self.l2_entries as usize)
1242            } else {
1243                VecCache::from_vec(Self::read_l2_cluster(&mut self.raw_file, l2_addr_disk)?)
1244            };
1245            let l1_table = &self.l1_table;
1246            let raw_file = &mut self.raw_file;
1247            self.l2_cache.insert(l1_index, l2_table, |index, evicted| {
1248                raw_file.write_pointer_table(
1249                    l1_table[index],
1250                    evicted.get_values(),
1251                    CLUSTER_USED_FLAG,
1252                )
1253            })?;
1254        }
1255
1256        let cluster_addr = match self.l2_cache.get(&l1_index).unwrap()[l2_index] {
1257            0 => {
1258                let initial_data = if let Some(backing) = self.backing_file.as_mut() {
1259                    let cluster_size = self.raw_file.cluster_size();
1260                    let cluster_begin = address - (address % cluster_size);
1261                    let mut cluster_data = vec![0u8; cluster_size as usize];
1262                    let volatile_slice = VolatileSlice::new(&mut cluster_data);
1263                    backing.read_exact_at_volatile(volatile_slice, cluster_begin)?;
1264                    Some(cluster_data)
1265                } else {
1266                    None
1267                };
1268                // Need to allocate a data cluster
1269                let cluster_addr = self.append_data_cluster(initial_data)?;
1270                self.update_cluster_addr(l1_index, l2_index, cluster_addr, &mut set_refcounts)?;
1271                cluster_addr
1272            }
1273            a => a,
1274        };
1275
1276        for (addr, count) in set_refcounts {
1277            let mut newly_unref = self.set_cluster_refcount(addr, count)?;
1278            self.unref_clusters.append(&mut newly_unref);
1279        }
1280
1281        Ok(cluster_addr + self.raw_file.cluster_offset(address))
1282    }
1283
1284    // Updates the l1 and l2 tables to point to the new `cluster_addr`.
1285    fn update_cluster_addr(
1286        &mut self,
1287        l1_index: usize,
1288        l2_index: usize,
1289        cluster_addr: u64,
1290        set_refcounts: &mut Vec<(u64, u16)>,
1291    ) -> io::Result<()> {
1292        if !self.l2_cache.get(&l1_index).unwrap().dirty() {
1293            // Free the previously used cluster if one exists. Modified tables are always
1294            // witten to new clusters so the L1 table can be committed to disk after they
1295            // are and L1 never points at an invalid table.
1296            // The index must be valid from when it was insterted.
1297            let addr = self.l1_table[l1_index];
1298            if addr != 0 {
1299                self.unref_clusters.push(addr);
1300                set_refcounts.push((addr, 0));
1301            }
1302
1303            // Allocate a new cluster to store the L2 table and update the L1 table to point
1304            // to the new table. The cluster will be written when the cache is flushed, no
1305            // need to copy the data now.
1306            let new_addr: u64 = self.get_new_cluster(None)?;
1307            // The cluster refcount starts at one indicating it is used but doesn't need
1308            // COW.
1309            set_refcounts.push((new_addr, 1));
1310            self.l1_table[l1_index] = new_addr;
1311        }
1312        // 'unwrap' is OK because it was just added.
1313        self.l2_cache.get_mut(&l1_index).unwrap()[l2_index] = cluster_addr;
1314        Ok(())
1315    }
1316
1317    // Allocate a new cluster and return its offset within the raw file.
1318    fn get_new_cluster(&mut self, initial_data: Option<Vec<u8>>) -> std::io::Result<u64> {
1319        // First use a pre allocated cluster if one is available.
1320        if let Some(free_cluster) = self.avail_clusters.pop() {
1321            if let Some(initial_data) = initial_data {
1322                self.raw_file.write_cluster(free_cluster, initial_data)?;
1323            } else {
1324                self.raw_file.zero_cluster(free_cluster)?;
1325            }
1326            return Ok(free_cluster);
1327        }
1328
1329        let max_valid_cluster_offset = self.refcounts.max_valid_cluster_offset();
1330        if let Some(new_cluster) = self.raw_file.add_cluster_end(max_valid_cluster_offset)? {
1331            if let Some(initial_data) = initial_data {
1332                self.raw_file.write_cluster(new_cluster, initial_data)?;
1333            }
1334            Ok(new_cluster)
1335        } else {
1336            error!("No free clusters in get_new_cluster()");
1337            Err(std::io::Error::from_raw_os_error(ENOSPC))
1338        }
1339    }
1340
1341    // Allocate and initialize a new data cluster. Returns the offset of the
1342    // cluster in to the file on success.
1343    fn append_data_cluster(&mut self, initial_data: Option<Vec<u8>>) -> std::io::Result<u64> {
1344        let new_addr: u64 = self.get_new_cluster(initial_data)?;
1345        // The cluster refcount starts at one indicating it is used but doesn't need COW.
1346        let mut newly_unref = self.set_cluster_refcount(new_addr, 1)?;
1347        self.unref_clusters.append(&mut newly_unref);
1348        Ok(new_addr)
1349    }
1350
1351    // Deallocate the storage for the cluster starting at `address`.
1352    // Any future reads of this cluster will return all zeroes (or the backing file, if in use).
1353    fn deallocate_cluster(&mut self, address: u64) -> std::io::Result<()> {
1354        if address >= self.virtual_size() {
1355            return Err(std::io::Error::from_raw_os_error(EINVAL));
1356        }
1357
1358        let l1_index = self.l1_table_index(address) as usize;
1359        let l2_addr_disk = *self
1360            .l1_table
1361            .get(l1_index)
1362            .ok_or_else(|| std::io::Error::from_raw_os_error(EINVAL))?;
1363        let l2_index = self.l2_table_index(address) as usize;
1364
1365        if l2_addr_disk == 0 {
1366            // The whole L2 table for this address is not allocated yet,
1367            // so the cluster must also be unallocated.
1368            return Ok(());
1369        }
1370
1371        if !self.l2_cache.contains_key(&l1_index) {
1372            // Not in the cache.
1373            let table =
1374                VecCache::from_vec(Self::read_l2_cluster(&mut self.raw_file, l2_addr_disk)?);
1375            let l1_table = &self.l1_table;
1376            let raw_file = &mut self.raw_file;
1377            self.l2_cache.insert(l1_index, table, |index, evicted| {
1378                raw_file.write_pointer_table(
1379                    l1_table[index],
1380                    evicted.get_values(),
1381                    CLUSTER_USED_FLAG,
1382                )
1383            })?;
1384        }
1385
1386        let cluster_addr = self.l2_cache.get(&l1_index).unwrap()[l2_index];
1387        if cluster_addr == 0 {
1388            // This cluster is already unallocated; nothing to do.
1389            return Ok(());
1390        }
1391
1392        // Decrement the refcount.
1393        let refcount = self
1394            .refcounts
1395            .get_cluster_refcount(&mut self.raw_file, cluster_addr)
1396            .map_err(|_| std::io::Error::from_raw_os_error(EINVAL))?;
1397        if refcount == 0 {
1398            return Err(std::io::Error::from_raw_os_error(EINVAL));
1399        }
1400
1401        let new_refcount = refcount - 1;
1402        let mut newly_unref = self.set_cluster_refcount(cluster_addr, new_refcount)?;
1403        self.unref_clusters.append(&mut newly_unref);
1404
1405        // Rewrite the L2 entry to remove the cluster mapping.
1406        // unwrap is safe as we just checked/inserted this entry.
1407        self.l2_cache.get_mut(&l1_index).unwrap()[l2_index] = 0;
1408
1409        if new_refcount == 0 {
1410            let cluster_size = self.raw_file.cluster_size();
1411            // This cluster is no longer in use; deallocate the storage.
1412            // The underlying FS may not support FALLOC_FL_PUNCH_HOLE,
1413            // so don't treat an error as fatal.  Future reads will return zeros anyways.
1414            let _ = self.raw_file.file().punch_hole(cluster_addr, cluster_size);
1415            self.unref_clusters.push(cluster_addr);
1416        }
1417        Ok(())
1418    }
1419
1420    // Fill a range of `length` bytes starting at `address` with zeroes.
1421    // Any future reads of this range will return all zeroes.
1422    // If there is no backing file, this will deallocate cluster storage when possible.
1423    fn zero_bytes(&mut self, address: u64, length: usize) -> std::io::Result<()> {
1424        let write_count: usize = self.limit_range_file(address, length);
1425
1426        let mut nwritten: usize = 0;
1427        while nwritten < write_count {
1428            let curr_addr = address + nwritten as u64;
1429            let count = self.limit_range_cluster(curr_addr, write_count - nwritten);
1430
1431            if self.backing_file.is_none() && count == self.raw_file.cluster_size() as usize {
1432                // Full cluster and no backing file in use - deallocate the storage.
1433                self.deallocate_cluster(curr_addr)?;
1434            } else {
1435                // Partial cluster - zero out the relevant bytes.
1436                let offset = if self.backing_file.is_some() {
1437                    // There is a backing file, so we need to allocate a cluster in order to
1438                    // zero out the hole-punched bytes such that the backing file contents do not
1439                    // show through.
1440                    Some(self.file_offset_write(curr_addr)?)
1441                } else {
1442                    // Any space in unallocated clusters can be left alone, since
1443                    // unallocated clusters already read back as zeroes.
1444                    self.file_offset_read(curr_addr)?
1445                };
1446                if let Some(offset) = offset {
1447                    // Partial cluster - zero it out.
1448                    self.raw_file.file().write_zeroes_all_at(offset, count)?;
1449                }
1450            }
1451
1452            nwritten += count;
1453        }
1454        Ok(())
1455    }
1456
1457    // Reads an L2 cluster from the disk, returning an error if the file can't be read or if any
1458    // cluster is compressed.
1459    fn read_l2_cluster(raw_file: &mut QcowRawFile, cluster_addr: u64) -> std::io::Result<Vec<u64>> {
1460        let file_values = raw_file.read_pointer_cluster(cluster_addr, None)?;
1461        if file_values.iter().any(|entry| entry & COMPRESSED_FLAG != 0) {
1462            return Err(std::io::Error::from_raw_os_error(ENOTSUP));
1463        }
1464        Ok(file_values
1465            .iter()
1466            .map(|entry| *entry & L2_TABLE_OFFSET_MASK)
1467            .collect())
1468    }
1469
1470    // Set the refcount for a cluster with the given address.
1471    // Returns a list of any refblocks that can be reused, this happens when a refblock is moved,
1472    // the old location can be reused.
1473    fn set_cluster_refcount(&mut self, address: u64, refcount: u16) -> std::io::Result<Vec<u64>> {
1474        let mut added_clusters = Vec::new();
1475        let mut unref_clusters = Vec::new();
1476        let mut refcount_set = false;
1477        let mut new_cluster = None;
1478
1479        while !refcount_set {
1480            match self.refcounts.set_cluster_refcount(
1481                &mut self.raw_file,
1482                address,
1483                refcount,
1484                new_cluster.take(),
1485            ) {
1486                Ok(None) => {
1487                    refcount_set = true;
1488                }
1489                Ok(Some(freed_cluster)) => {
1490                    unref_clusters.push(freed_cluster);
1491                    refcount_set = true;
1492                }
1493                Err(refcount::Error::EvictingRefCounts(e)) => {
1494                    return Err(e);
1495                }
1496                Err(refcount::Error::InvalidIndex) => {
1497                    return Err(std::io::Error::from_raw_os_error(EINVAL));
1498                }
1499                Err(refcount::Error::NeedCluster(addr)) => {
1500                    // Read the address and call set_cluster_refcount again.
1501                    new_cluster = Some((
1502                        addr,
1503                        VecCache::from_vec(self.raw_file.read_refcount_block(addr)?),
1504                    ));
1505                }
1506                Err(refcount::Error::NeedNewCluster) => {
1507                    // Allocate the cluster and call set_cluster_refcount again.
1508                    let addr = self.get_new_cluster(None)?;
1509                    added_clusters.push(addr);
1510                    new_cluster = Some((
1511                        addr,
1512                        VecCache::new(self.refcounts.refcounts_per_block() as usize),
1513                    ));
1514                }
1515                Err(refcount::Error::ReadingRefCounts(e)) => {
1516                    return Err(e);
1517                }
1518            }
1519        }
1520
1521        for addr in added_clusters {
1522            self.set_cluster_refcount(addr, 1)?;
1523        }
1524        Ok(unref_clusters)
1525    }
1526
1527    fn sync_caches(&mut self) -> std::io::Result<()> {
1528        // Write out all dirty L2 tables.
1529        for (l1_index, l2_table) in self.l2_cache.iter_mut().filter(|(_k, v)| v.dirty()) {
1530            // The index must be valid from when we insterted it.
1531            let addr = self.l1_table[*l1_index];
1532            if addr != 0 {
1533                self.raw_file.write_pointer_table(
1534                    addr,
1535                    l2_table.get_values(),
1536                    CLUSTER_USED_FLAG,
1537                )?;
1538            } else {
1539                return Err(std::io::Error::from_raw_os_error(EINVAL));
1540            }
1541            l2_table.mark_clean();
1542        }
1543        // Write the modified refcount blocks.
1544        self.refcounts.flush_blocks(&mut self.raw_file)?;
1545        // Make sure metadata(file len) and all data clusters are written.
1546        self.raw_file.file_mut().sync_all()?;
1547
1548        // Push L1 table and refcount table last as all the clusters they point to are now
1549        // guaranteed to be valid.
1550        let mut sync_required = false;
1551        if self.l1_table.dirty() {
1552            self.raw_file.write_pointer_table(
1553                self.header.l1_table_offset,
1554                self.l1_table.get_values(),
1555                0,
1556            )?;
1557            self.l1_table.mark_clean();
1558            sync_required = true;
1559        }
1560        sync_required |= self.refcounts.flush_table(&mut self.raw_file)?;
1561        if sync_required {
1562            self.raw_file.file_mut().sync_data()?;
1563        }
1564        Ok(())
1565    }
1566
1567    // Reads `count` bytes starting at `address`, calling `cb` repeatedly with the data source,
1568    // number of bytes read so far, offset to read from, and number of bytes to read from the file
1569    // in that invocation. If None is given to `cb` in place of the backing file, the `cb` should
1570    // infer zeros would have been read.
1571    fn read_cb<F>(&mut self, address: u64, count: usize, mut cb: F) -> std::io::Result<usize>
1572    where
1573        F: FnMut(Option<&mut dyn DiskFile>, usize, u64, usize) -> std::io::Result<()>,
1574    {
1575        let read_count: usize = self.limit_range_file(address, count);
1576
1577        let mut nread: usize = 0;
1578        while nread < read_count {
1579            let curr_addr = address + nread as u64;
1580            let file_offset = self.file_offset_read(curr_addr)?;
1581            let count = self.limit_range_cluster(curr_addr, read_count - nread);
1582
1583            if let Some(offset) = file_offset {
1584                cb(Some(self.raw_file.file_mut()), nread, offset, count)?;
1585            } else if let Some(backing) = self.backing_file.as_mut() {
1586                cb(Some(backing.as_mut()), nread, curr_addr, count)?;
1587            } else {
1588                cb(None, nread, 0, count)?;
1589            }
1590
1591            nread += count;
1592        }
1593        Ok(read_count)
1594    }
1595
1596    // Writes `count` bytes starting at `address`, calling `cb` repeatedly with the backing file,
1597    // number of bytes written so far, raw file offset, and number of bytes to write to the file in
1598    // that invocation.
1599    fn write_cb<F>(&mut self, address: u64, count: usize, mut cb: F) -> std::io::Result<usize>
1600    where
1601        F: FnMut(&mut File, usize, u64, usize) -> std::io::Result<()>,
1602    {
1603        let write_count: usize = self.limit_range_file(address, count);
1604
1605        let mut nwritten: usize = 0;
1606        while nwritten < write_count {
1607            let curr_addr = address + nwritten as u64;
1608            let offset = self.file_offset_write(curr_addr)?;
1609            let count = self.limit_range_cluster(curr_addr, write_count - nwritten);
1610
1611            cb(self.raw_file.file_mut(), nwritten, offset, count)?;
1612
1613            nwritten += count;
1614        }
1615        Ok(write_count)
1616    }
1617}
1618
1619impl Drop for QcowFile {
1620    fn drop(&mut self) {
1621        let _ = self.inner.get_mut().sync_caches();
1622    }
1623}
1624
1625impl AsRawDescriptors for QcowFile {
1626    fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
1627        // Taking a lock here feels wrong, but this method is generally only used during
1628        // sandboxing, so it should be OK.
1629        let inner = self.inner.lock();
1630        let mut descriptors = vec![inner.raw_file.file().as_raw_descriptor()];
1631        if let Some(backing) = &inner.backing_file {
1632            descriptors.append(&mut backing.as_raw_descriptors());
1633        }
1634        descriptors
1635    }
1636}
1637
1638impl Read for QcowFile {
1639    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1640        let inner = self.inner.get_mut();
1641        let len = buf.len();
1642        let slice = VolatileSlice::new(buf);
1643        let read_count = inner.read_cb(
1644            inner.current_offset,
1645            len,
1646            |file, already_read, offset, count| {
1647                let sub_slice = slice.get_slice(already_read, count).unwrap();
1648                match file {
1649                    Some(f) => f.read_exact_at_volatile(sub_slice, offset),
1650                    None => {
1651                        sub_slice.write_bytes(0);
1652                        Ok(())
1653                    }
1654                }
1655            },
1656        )?;
1657        inner.current_offset += read_count as u64;
1658        Ok(read_count)
1659    }
1660}
1661
1662impl Seek for QcowFile {
1663    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
1664        let inner = self.inner.get_mut();
1665        let new_offset: Option<u64> = match pos {
1666            SeekFrom::Start(off) => Some(off),
1667            SeekFrom::End(off) => {
1668                if off < 0 {
1669                    0i64.checked_sub(off)
1670                        .and_then(|increment| inner.virtual_size().checked_sub(increment as u64))
1671                } else {
1672                    inner.virtual_size().checked_add(off as u64)
1673                }
1674            }
1675            SeekFrom::Current(off) => {
1676                if off < 0 {
1677                    0i64.checked_sub(off)
1678                        .and_then(|increment| inner.current_offset.checked_sub(increment as u64))
1679                } else {
1680                    inner.current_offset.checked_add(off as u64)
1681                }
1682            }
1683        };
1684
1685        if let Some(o) = new_offset {
1686            if o <= inner.virtual_size() {
1687                inner.current_offset = o;
1688                return Ok(o);
1689            }
1690        }
1691        Err(std::io::Error::from_raw_os_error(EINVAL))
1692    }
1693}
1694
1695impl Write for QcowFile {
1696    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1697        let inner = self.inner.get_mut();
1698        let write_count = inner.write_cb(
1699            inner.current_offset,
1700            buf.len(),
1701            |file, offset, raw_offset, count| {
1702                file.seek(SeekFrom::Start(raw_offset))?;
1703                file.write_all(&buf[offset..(offset + count)])
1704            },
1705        )?;
1706        inner.current_offset += write_count as u64;
1707        Ok(write_count)
1708    }
1709
1710    fn flush(&mut self) -> std::io::Result<()> {
1711        self.fsync()
1712    }
1713}
1714
1715impl FileReadWriteAtVolatile for QcowFile {
1716    fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> io::Result<usize> {
1717        let mut inner = self.inner.lock();
1718        inner.read_cb(offset, slice.size(), |file, read, offset, count| {
1719            let sub_slice = slice.get_slice(read, count).unwrap();
1720            match file {
1721                Some(f) => f.read_exact_at_volatile(sub_slice, offset),
1722                None => {
1723                    sub_slice.write_bytes(0);
1724                    Ok(())
1725                }
1726            }
1727        })
1728    }
1729
1730    fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> io::Result<usize> {
1731        let mut inner = self.inner.lock();
1732        inner.write_cb(offset, slice.size(), |file, offset, raw_offset, count| {
1733            let sub_slice = slice.get_slice(offset, count).unwrap();
1734            file.write_all_at_volatile(sub_slice, raw_offset)
1735        })
1736    }
1737}
1738
1739impl FileSync for QcowFile {
1740    fn fsync(&self) -> std::io::Result<()> {
1741        let mut inner = self.inner.lock();
1742        inner.sync_caches()?;
1743        let unref_clusters = std::mem::take(&mut inner.unref_clusters);
1744        inner.avail_clusters.extend(unref_clusters);
1745        Ok(())
1746    }
1747
1748    fn fdatasync(&self) -> io::Result<()> {
1749        // QcowFile does not implement fdatasync. Just fall back to fsync.
1750        self.fsync()
1751    }
1752}
1753
1754impl FileSetLen for QcowFile {
1755    fn set_len(&self, _len: u64) -> std::io::Result<()> {
1756        Err(std::io::Error::other(
1757            "set_len() not supported for QcowFile",
1758        ))
1759    }
1760}
1761
1762impl DiskGetLen for QcowFile {
1763    fn get_len(&self) -> io::Result<u64> {
1764        Ok(self.virtual_size)
1765    }
1766}
1767
1768impl FileAllocate for QcowFile {
1769    fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
1770        let mut inner = self.inner.lock();
1771        // Call write_cb with a do-nothing callback, which will have the effect
1772        // of allocating all clusters in the specified range.
1773        inner.write_cb(
1774            offset,
1775            len as usize,
1776            |_file, _offset, _raw_offset, _count| Ok(()),
1777        )?;
1778        Ok(())
1779    }
1780}
1781
1782impl PunchHole for QcowFile {
1783    fn punch_hole(&self, offset: u64, length: u64) -> std::io::Result<()> {
1784        let mut inner = self.inner.lock();
1785        let mut remaining = length;
1786        let mut offset = offset;
1787        while remaining > 0 {
1788            let chunk_length = min(remaining, usize::MAX as u64) as usize;
1789            inner.zero_bytes(offset, chunk_length)?;
1790            remaining -= chunk_length as u64;
1791            offset += chunk_length as u64;
1792        }
1793        Ok(())
1794    }
1795}
1796
1797impl WriteZeroesAt for QcowFile {
1798    fn write_zeroes_at(&self, offset: u64, length: usize) -> io::Result<usize> {
1799        self.punch_hole(offset, length as u64)?;
1800        Ok(length)
1801    }
1802}
1803
1804impl ToAsyncDisk for QcowFile {
1805    fn to_async_disk(self: Box<Self>, ex: &Executor) -> crate::Result<Box<dyn AsyncDisk>> {
1806        Ok(Box::new(AsyncDiskFileWrapper::new(*self, ex)))
1807    }
1808}
1809
1810// Returns an Error if the given offset doesn't align to a cluster boundary.
1811fn offset_is_cluster_boundary(offset: u64, cluster_bits: u32) -> Result<()> {
1812    if offset & ((0x01 << cluster_bits) - 1) != 0 {
1813        return Err(Error::InvalidOffset(offset));
1814    }
1815    Ok(())
1816}
1817
1818#[cfg(test)]
1819mod tests {
1820    use std::fs::OpenOptions;
1821    use std::io::Read;
1822    use std::io::Seek;
1823    use std::io::SeekFrom;
1824    use std::io::Write;
1825
1826    use tempfile::tempfile;
1827    use tempfile::TempDir;
1828
1829    use super::*;
1830
1831    fn valid_header() -> Vec<u8> {
1832        vec![
1833            0x51u8, 0x46, 0x49, 0xfb, // magic
1834            0x00, 0x00, 0x00, 0x03, // version
1835            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // backing file offset
1836            0x00, 0x00, 0x00, 0x00, // backing file size
1837            0x00, 0x00, 0x00, 0x10, // cluster_bits
1838            0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, // size
1839            0x00, 0x00, 0x00, 0x00, // crypt method
1840            0x00, 0x00, 0x01, 0x00, // L1 size
1841            0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, // L1 table offset
1842            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // refcount table offset
1843            0x00, 0x00, 0x00, 0x03, // refcount table clusters
1844            0x00, 0x00, 0x00, 0x00, // nb snapshots
1845            0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, // snapshots offset
1846            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // incompatible_features
1847            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // compatible_features
1848            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // autoclear_features
1849            0x00, 0x00, 0x00, 0x04, // refcount_order
1850            0x00, 0x00, 0x00, 0x68, // header_length
1851        ]
1852    }
1853
1854    // Test case found by clusterfuzz to allocate excessive memory.
1855    fn test_huge_header() -> Vec<u8> {
1856        vec![
1857            0x51, 0x46, 0x49, 0xfb, // magic
1858            0x00, 0x00, 0x00, 0x03, // version
1859            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // backing file offset
1860            0x00, 0x00, 0x00, 0x00, // backing file size
1861            0x00, 0x00, 0x00, 0x09, // cluster_bits
1862            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // size
1863            0x00, 0x00, 0x00, 0x00, // crypt method
1864            0x00, 0x00, 0x01, 0x00, // L1 size
1865            0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, // L1 table offset
1866            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // refcount table offset
1867            0x00, 0x00, 0x00, 0x03, // refcount table clusters
1868            0x00, 0x00, 0x00, 0x00, // nb snapshots
1869            0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, // snapshots offset
1870            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // incompatible_features
1871            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // compatible_features
1872            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // autoclear_features
1873            0x00, 0x00, 0x00, 0x04, // refcount_order
1874            0x00, 0x00, 0x00, 0x68, // header_length
1875        ]
1876    }
1877
1878    fn test_params() -> DiskFileParams {
1879        DiskFileParams {
1880            path: PathBuf::from("/foo"),
1881            ..Default::default()
1882        }
1883    }
1884
1885    fn basic_file(header: &[u8]) -> File {
1886        let mut disk_file = tempfile().expect("failed to create temp file");
1887        disk_file.write_all(header).unwrap();
1888        disk_file.set_len(0x8000_0000).unwrap();
1889        disk_file.seek(SeekFrom::Start(0)).unwrap();
1890        disk_file
1891    }
1892
1893    fn with_basic_file<F>(header: &[u8], mut testfn: F)
1894    where
1895        F: FnMut(File),
1896    {
1897        testfn(basic_file(header)); // File closed when the function exits.
1898    }
1899
1900    fn with_default_file<F>(file_size: u64, mut testfn: F)
1901    where
1902        F: FnMut(QcowFile),
1903    {
1904        let file = tempfile().expect("failed to create temp file");
1905        let qcow_file = QcowFile::new(file, test_params(), file_size).unwrap();
1906
1907        testfn(qcow_file); // File closed when the function exits.
1908    }
1909
1910    // Test helper function to convert a normal slice to a VolatileSlice and write it.
1911    fn write_all_at(qcow: &mut QcowFile, data: &[u8], offset: u64) -> std::io::Result<()> {
1912        let mut mem = data.to_owned();
1913        let vslice = VolatileSlice::new(&mut mem);
1914        qcow.write_all_at_volatile(vslice, offset)
1915    }
1916
1917    // Test helper function to read to a VolatileSlice and copy it to a normal slice.
1918    fn read_exact_at(qcow: &mut QcowFile, data: &mut [u8], offset: u64) -> std::io::Result<()> {
1919        let mut mem = data.to_owned();
1920        let vslice = VolatileSlice::new(&mut mem);
1921        qcow.read_exact_at_volatile(vslice, offset)?;
1922        vslice.copy_to(data);
1923        Ok(())
1924    }
1925
1926    #[test]
1927    fn default_header() {
1928        let header = QcowHeader::create_for_size_and_path(0x10_0000, None);
1929        let mut disk_file = tempfile().expect("failed to create temp file");
1930        header
1931            .expect("Failed to create header.")
1932            .write_to(&mut disk_file)
1933            .expect("Failed to write header to shm.");
1934        disk_file.seek(SeekFrom::Start(0)).unwrap();
1935        QcowFile::from(disk_file, test_params())
1936            .expect("Failed to create Qcow from default Header");
1937    }
1938
1939    #[test]
1940    fn header_read() {
1941        with_basic_file(&valid_header(), |mut disk_file: File| {
1942            QcowHeader::new(&mut disk_file).expect("Failed to create Header.");
1943        });
1944    }
1945
1946    #[test]
1947    fn invalid_magic() {
1948        let invalid_header = vec![0x51u8, 0x46, 0x4a, 0xfb];
1949        with_basic_file(&invalid_header, |mut disk_file: File| {
1950            QcowHeader::new(&mut disk_file).expect_err("Invalid header worked.");
1951        });
1952    }
1953
1954    #[test]
1955    fn invalid_refcount_order() {
1956        let mut header = valid_header();
1957        header[99] = 2;
1958        with_basic_file(&header, |disk_file: File| {
1959            QcowFile::from(disk_file, test_params()).expect_err("Invalid refcount order worked.");
1960        });
1961    }
1962
1963    #[test]
1964    fn invalid_cluster_bits() {
1965        let mut header = valid_header();
1966        header[23] = 3;
1967        with_basic_file(&header, |disk_file: File| {
1968            QcowFile::from(disk_file, test_params()).expect_err("Failed to create file.");
1969        });
1970    }
1971
1972    #[test]
1973    fn test_header_huge_file() {
1974        let header = test_huge_header();
1975        with_basic_file(&header, |disk_file: File| {
1976            QcowFile::from(disk_file, test_params()).expect_err("Failed to create file.");
1977        });
1978    }
1979
1980    #[test]
1981    fn test_header_excessive_file_size_rejected() {
1982        let mut header = valid_header();
1983        header[24..32].copy_from_slice(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1e]);
1984        with_basic_file(&header, |disk_file: File| {
1985            QcowFile::from(disk_file, test_params()).expect_err("Failed to create file.");
1986        });
1987    }
1988
1989    #[test]
1990    fn test_huge_l1_table() {
1991        let mut header = valid_header();
1992        header[36] = 0x12;
1993        with_basic_file(&header, |disk_file: File| {
1994            QcowFile::from(disk_file, test_params()).expect_err("Failed to create file.");
1995        });
1996    }
1997
1998    #[test]
1999    fn test_header_1_tb_file_min_cluster() {
2000        let mut header = test_huge_header();
2001        header[24] = 0;
2002        header[26] = 1;
2003        header[31] = 0;
2004        // 1 TB with the min cluster size makes the arrays too big, it should fail.
2005        with_basic_file(&header, |disk_file: File| {
2006            QcowFile::from(disk_file, test_params()).expect_err("Failed to create file.");
2007        });
2008    }
2009
2010    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2011    #[test]
2012    fn test_header_1_tb_file() {
2013        let mut header = test_huge_header();
2014        // reset to 1 TB size.
2015        header[24] = 0;
2016        header[26] = 1;
2017        header[31] = 0;
2018        // set cluster_bits
2019        header[23] = 16;
2020        with_basic_file(&header, |disk_file: File| {
2021            let mut qcow =
2022                QcowFile::from(disk_file, test_params()).expect("Failed to create file.");
2023            let value = 0x0000_0040_3f00_ffffu64;
2024            write_all_at(&mut qcow, &value.to_le_bytes(), 0x100_0000_0000 - 8)
2025                .expect("failed to write data");
2026        });
2027    }
2028
2029    #[test]
2030    fn test_header_huge_num_refcounts() {
2031        let mut header = valid_header();
2032        header[56..60].copy_from_slice(&[0x02, 0x00, 0xe8, 0xff]);
2033        with_basic_file(&header, |disk_file: File| {
2034            QcowFile::from(disk_file, test_params())
2035                .expect_err("Created disk with excessive refcount clusters");
2036        });
2037    }
2038
2039    #[test]
2040    fn test_header_huge_refcount_offset() {
2041        let mut header = valid_header();
2042        header[48..56].copy_from_slice(&[0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00]);
2043        with_basic_file(&header, |disk_file: File| {
2044            QcowFile::from(disk_file, test_params())
2045                .expect_err("Created disk with excessive refcount offset");
2046        });
2047    }
2048
2049    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2050    #[test]
2051    fn write_read_start() {
2052        with_basic_file(&valid_header(), |disk_file: File| {
2053            let mut q = QcowFile::from(disk_file, test_params()).unwrap();
2054            write_all_at(&mut q, b"test first bytes", 0).expect("Failed to write test string.");
2055            let mut buf = [0u8; 4];
2056            read_exact_at(&mut q, &mut buf, 0).expect("Failed to read.");
2057            assert_eq!(&buf, b"test");
2058        });
2059    }
2060
2061    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2062    #[test]
2063    fn write_read_start_backing() {
2064        let disk_file = basic_file(&valid_header());
2065        let mut backing = QcowFile::from(disk_file, test_params()).unwrap();
2066        write_all_at(&mut backing, b"test first bytes", 0).expect("Failed to write test string.");
2067        let mut buf = [0u8; 4];
2068        let wrapping_disk_file = basic_file(&valid_header());
2069        let mut wrapping = QcowFile::from(wrapping_disk_file, test_params()).unwrap();
2070        wrapping.set_backing_file(Some(Box::new(backing)));
2071        read_exact_at(&mut wrapping, &mut buf, 0).expect("Failed to read.");
2072        assert_eq!(&buf, b"test");
2073    }
2074
2075    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2076    #[test]
2077    fn write_read_start_backing_overlap() {
2078        let disk_file = basic_file(&valid_header());
2079        let mut backing = QcowFile::from(disk_file, test_params()).unwrap();
2080        write_all_at(&mut backing, b"test first bytes", 0).expect("Failed to write test string.");
2081        let wrapping_disk_file = basic_file(&valid_header());
2082        let mut wrapping = QcowFile::from(wrapping_disk_file, test_params()).unwrap();
2083        wrapping.set_backing_file(Some(Box::new(backing)));
2084        write_all_at(&mut wrapping, b"TEST", 0).expect("Failed to write second test string.");
2085        let mut buf = [0u8; 10];
2086        read_exact_at(&mut wrapping, &mut buf, 0).expect("Failed to read.");
2087        assert_eq!(&buf, b"TEST first");
2088    }
2089
2090    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2091    #[test]
2092    fn offset_write_read() {
2093        with_basic_file(&valid_header(), |disk_file: File| {
2094            let mut q = QcowFile::from(disk_file, test_params()).unwrap();
2095            let b = [0x55u8; 0x1000];
2096            write_all_at(&mut q, &b, 0xfff2000).expect("Failed to write test string.");
2097            let mut buf = [0u8; 4];
2098            read_exact_at(&mut q, &mut buf, 0xfff2000).expect("Failed to read.");
2099            assert_eq!(buf[0], 0x55);
2100        });
2101    }
2102
2103    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2104    #[test]
2105    fn write_zeroes_read() {
2106        with_basic_file(&valid_header(), |disk_file: File| {
2107            let mut q = QcowFile::from(disk_file, test_params()).unwrap();
2108            // Write some test data.
2109            let b = [0x55u8; 0x1000];
2110            write_all_at(&mut q, &b, 0xfff2000).expect("Failed to write test string.");
2111            // Overwrite the test data with zeroes.
2112            q.write_zeroes_all_at(0xfff2000, 0x200)
2113                .expect("Failed to write zeroes.");
2114            // Verify that the correct part of the data was zeroed out.
2115            let mut buf = [0u8; 0x1000];
2116            read_exact_at(&mut q, &mut buf, 0xfff2000).expect("Failed to read.");
2117            assert_eq!(buf[0], 0);
2118            assert_eq!(buf[0x1FF], 0);
2119            assert_eq!(buf[0x200], 0x55);
2120            assert_eq!(buf[0xFFF], 0x55);
2121        });
2122    }
2123
2124    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2125    #[test]
2126    fn write_zeroes_full_cluster() {
2127        // Choose a size that is larger than a cluster.
2128        // valid_header uses cluster_bits = 12, which corresponds to a cluster size of 4096.
2129        const CHUNK_SIZE: usize = 4096 * 2 + 512;
2130        with_basic_file(&valid_header(), |disk_file: File| {
2131            let mut q = QcowFile::from(disk_file, test_params()).unwrap();
2132            // Write some test data.
2133            let b = [0x55u8; CHUNK_SIZE];
2134            write_all_at(&mut q, &b, 0).expect("Failed to write test string.");
2135            // Overwrite the full cluster with zeroes.
2136            q.write_zeroes_all_at(0, CHUNK_SIZE)
2137                .expect("Failed to write zeroes.");
2138            // Verify that the data was zeroed out.
2139            let mut buf = [0u8; CHUNK_SIZE];
2140            read_exact_at(&mut q, &mut buf, 0).expect("Failed to read.");
2141            assert_eq!(buf[0], 0);
2142            assert_eq!(buf[CHUNK_SIZE - 1], 0);
2143        });
2144    }
2145
2146    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2147    #[test]
2148    fn write_zeroes_backing() {
2149        let disk_file = basic_file(&valid_header());
2150        let mut backing = QcowFile::from(disk_file, test_params()).unwrap();
2151        // Write some test data.
2152        let b = [0x55u8; 0x1000];
2153        write_all_at(&mut backing, &b, 0xfff2000).expect("Failed to write test string.");
2154        let wrapping_disk_file = basic_file(&valid_header());
2155        let mut wrapping = QcowFile::from(wrapping_disk_file, test_params()).unwrap();
2156        wrapping.set_backing_file(Some(Box::new(backing)));
2157        // Overwrite the test data with zeroes.
2158        // This should allocate new clusters in the wrapping file so that they can be zeroed.
2159        wrapping
2160            .write_zeroes_all_at(0xfff2000, 0x200)
2161            .expect("Failed to write zeroes.");
2162        // Verify that the correct part of the data was zeroed out.
2163        let mut buf = [0u8; 0x1000];
2164        read_exact_at(&mut wrapping, &mut buf, 0xfff2000).expect("Failed to read.");
2165        assert_eq!(buf[0], 0);
2166        assert_eq!(buf[0x1FF], 0);
2167        assert_eq!(buf[0x200], 0x55);
2168        assert_eq!(buf[0xFFF], 0x55);
2169    }
2170    #[test]
2171    fn test_header() {
2172        with_basic_file(&valid_header(), |disk_file: File| {
2173            let mut q = QcowFile::from(disk_file, test_params()).unwrap();
2174            assert_eq!(q.inner.get_mut().virtual_size(), 0x20_0000_0000);
2175        });
2176    }
2177
2178    #[test]
2179    fn read_small_buffer() {
2180        with_basic_file(&valid_header(), |disk_file: File| {
2181            let mut q = QcowFile::from(disk_file, test_params()).unwrap();
2182            let mut b = [5u8; 16];
2183            read_exact_at(&mut q, &mut b, 1000).expect("Failed to read.");
2184            assert_eq!(0, b[0]);
2185            assert_eq!(0, b[15]);
2186        });
2187    }
2188
2189    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2190    #[test]
2191    fn replay_ext4() {
2192        with_basic_file(&valid_header(), |disk_file: File| {
2193            let mut q = QcowFile::from(disk_file, test_params()).unwrap();
2194            const BUF_SIZE: usize = 0x1000;
2195            let mut b = [0u8; BUF_SIZE];
2196
2197            struct Transfer {
2198                pub write: bool,
2199                pub addr: u64,
2200            }
2201
2202            // Write transactions from mkfs.ext4.
2203            let xfers: Vec<Transfer> = vec![
2204                Transfer {
2205                    write: false,
2206                    addr: 0xfff0000,
2207                },
2208                Transfer {
2209                    write: false,
2210                    addr: 0xfffe000,
2211                },
2212                Transfer {
2213                    write: false,
2214                    addr: 0x0,
2215                },
2216                Transfer {
2217                    write: false,
2218                    addr: 0x1000,
2219                },
2220                Transfer {
2221                    write: false,
2222                    addr: 0xffff000,
2223                },
2224                Transfer {
2225                    write: false,
2226                    addr: 0xffdf000,
2227                },
2228                Transfer {
2229                    write: false,
2230                    addr: 0xfff8000,
2231                },
2232                Transfer {
2233                    write: false,
2234                    addr: 0xffe0000,
2235                },
2236                Transfer {
2237                    write: false,
2238                    addr: 0xffce000,
2239                },
2240                Transfer {
2241                    write: false,
2242                    addr: 0xffb6000,
2243                },
2244                Transfer {
2245                    write: false,
2246                    addr: 0xffab000,
2247                },
2248                Transfer {
2249                    write: false,
2250                    addr: 0xffa4000,
2251                },
2252                Transfer {
2253                    write: false,
2254                    addr: 0xff8e000,
2255                },
2256                Transfer {
2257                    write: false,
2258                    addr: 0xff86000,
2259                },
2260                Transfer {
2261                    write: false,
2262                    addr: 0xff84000,
2263                },
2264                Transfer {
2265                    write: false,
2266                    addr: 0xff89000,
2267                },
2268                Transfer {
2269                    write: false,
2270                    addr: 0xfe7e000,
2271                },
2272                Transfer {
2273                    write: false,
2274                    addr: 0x100000,
2275                },
2276                Transfer {
2277                    write: false,
2278                    addr: 0x3000,
2279                },
2280                Transfer {
2281                    write: false,
2282                    addr: 0x7000,
2283                },
2284                Transfer {
2285                    write: false,
2286                    addr: 0xf000,
2287                },
2288                Transfer {
2289                    write: false,
2290                    addr: 0x2000,
2291                },
2292                Transfer {
2293                    write: false,
2294                    addr: 0x4000,
2295                },
2296                Transfer {
2297                    write: false,
2298                    addr: 0x5000,
2299                },
2300                Transfer {
2301                    write: false,
2302                    addr: 0x6000,
2303                },
2304                Transfer {
2305                    write: false,
2306                    addr: 0x8000,
2307                },
2308                Transfer {
2309                    write: false,
2310                    addr: 0x9000,
2311                },
2312                Transfer {
2313                    write: false,
2314                    addr: 0xa000,
2315                },
2316                Transfer {
2317                    write: false,
2318                    addr: 0xb000,
2319                },
2320                Transfer {
2321                    write: false,
2322                    addr: 0xc000,
2323                },
2324                Transfer {
2325                    write: false,
2326                    addr: 0xd000,
2327                },
2328                Transfer {
2329                    write: false,
2330                    addr: 0xe000,
2331                },
2332                Transfer {
2333                    write: false,
2334                    addr: 0x10000,
2335                },
2336                Transfer {
2337                    write: false,
2338                    addr: 0x11000,
2339                },
2340                Transfer {
2341                    write: false,
2342                    addr: 0x12000,
2343                },
2344                Transfer {
2345                    write: false,
2346                    addr: 0x13000,
2347                },
2348                Transfer {
2349                    write: false,
2350                    addr: 0x14000,
2351                },
2352                Transfer {
2353                    write: false,
2354                    addr: 0x15000,
2355                },
2356                Transfer {
2357                    write: false,
2358                    addr: 0x16000,
2359                },
2360                Transfer {
2361                    write: false,
2362                    addr: 0x17000,
2363                },
2364                Transfer {
2365                    write: false,
2366                    addr: 0x18000,
2367                },
2368                Transfer {
2369                    write: false,
2370                    addr: 0x19000,
2371                },
2372                Transfer {
2373                    write: false,
2374                    addr: 0x1a000,
2375                },
2376                Transfer {
2377                    write: false,
2378                    addr: 0x1b000,
2379                },
2380                Transfer {
2381                    write: false,
2382                    addr: 0x1c000,
2383                },
2384                Transfer {
2385                    write: false,
2386                    addr: 0x1d000,
2387                },
2388                Transfer {
2389                    write: false,
2390                    addr: 0x1e000,
2391                },
2392                Transfer {
2393                    write: false,
2394                    addr: 0x1f000,
2395                },
2396                Transfer {
2397                    write: false,
2398                    addr: 0x21000,
2399                },
2400                Transfer {
2401                    write: false,
2402                    addr: 0x22000,
2403                },
2404                Transfer {
2405                    write: false,
2406                    addr: 0x24000,
2407                },
2408                Transfer {
2409                    write: false,
2410                    addr: 0x40000,
2411                },
2412                Transfer {
2413                    write: false,
2414                    addr: 0x0,
2415                },
2416                Transfer {
2417                    write: false,
2418                    addr: 0x3000,
2419                },
2420                Transfer {
2421                    write: false,
2422                    addr: 0x7000,
2423                },
2424                Transfer {
2425                    write: false,
2426                    addr: 0x0,
2427                },
2428                Transfer {
2429                    write: false,
2430                    addr: 0x1000,
2431                },
2432                Transfer {
2433                    write: false,
2434                    addr: 0x2000,
2435                },
2436                Transfer {
2437                    write: false,
2438                    addr: 0x3000,
2439                },
2440                Transfer {
2441                    write: false,
2442                    addr: 0x0,
2443                },
2444                Transfer {
2445                    write: false,
2446                    addr: 0x449000,
2447                },
2448                Transfer {
2449                    write: false,
2450                    addr: 0x48000,
2451                },
2452                Transfer {
2453                    write: false,
2454                    addr: 0x48000,
2455                },
2456                Transfer {
2457                    write: false,
2458                    addr: 0x448000,
2459                },
2460                Transfer {
2461                    write: false,
2462                    addr: 0x44a000,
2463                },
2464                Transfer {
2465                    write: false,
2466                    addr: 0x48000,
2467                },
2468                Transfer {
2469                    write: false,
2470                    addr: 0x48000,
2471                },
2472                Transfer {
2473                    write: true,
2474                    addr: 0x0,
2475                },
2476                Transfer {
2477                    write: true,
2478                    addr: 0x448000,
2479                },
2480                Transfer {
2481                    write: true,
2482                    addr: 0x449000,
2483                },
2484                Transfer {
2485                    write: true,
2486                    addr: 0x44a000,
2487                },
2488                Transfer {
2489                    write: true,
2490                    addr: 0xfff0000,
2491                },
2492                Transfer {
2493                    write: true,
2494                    addr: 0xfff1000,
2495                },
2496                Transfer {
2497                    write: true,
2498                    addr: 0xfff2000,
2499                },
2500                Transfer {
2501                    write: true,
2502                    addr: 0xfff3000,
2503                },
2504                Transfer {
2505                    write: true,
2506                    addr: 0xfff4000,
2507                },
2508                Transfer {
2509                    write: true,
2510                    addr: 0xfff5000,
2511                },
2512                Transfer {
2513                    write: true,
2514                    addr: 0xfff6000,
2515                },
2516                Transfer {
2517                    write: true,
2518                    addr: 0xfff7000,
2519                },
2520                Transfer {
2521                    write: true,
2522                    addr: 0xfff8000,
2523                },
2524                Transfer {
2525                    write: true,
2526                    addr: 0xfff9000,
2527                },
2528                Transfer {
2529                    write: true,
2530                    addr: 0xfffa000,
2531                },
2532                Transfer {
2533                    write: true,
2534                    addr: 0xfffb000,
2535                },
2536                Transfer {
2537                    write: true,
2538                    addr: 0xfffc000,
2539                },
2540                Transfer {
2541                    write: true,
2542                    addr: 0xfffd000,
2543                },
2544                Transfer {
2545                    write: true,
2546                    addr: 0xfffe000,
2547                },
2548                Transfer {
2549                    write: true,
2550                    addr: 0xffff000,
2551                },
2552            ];
2553
2554            for xfer in &xfers {
2555                if xfer.write {
2556                    write_all_at(&mut q, &b, xfer.addr).expect("Failed to write.");
2557                } else {
2558                    read_exact_at(&mut q, &mut b, xfer.addr).expect("Failed to read.");
2559                }
2560            }
2561        });
2562    }
2563
2564    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2565    #[test]
2566    fn combo_write_read() {
2567        with_default_file(1024 * 1024 * 1024 * 256, |mut qcow_file| {
2568            const NUM_BLOCKS: usize = 55;
2569            const BLOCK_SIZE: usize = 0x1_0000;
2570            const OFFSET: u64 = 0x1_0000_0020;
2571            let data = [0x55u8; BLOCK_SIZE];
2572            let mut readback = [0u8; BLOCK_SIZE];
2573            for i in 0..NUM_BLOCKS {
2574                let seek_offset = OFFSET + (i as u64) * (BLOCK_SIZE as u64);
2575                write_all_at(&mut qcow_file, &data, seek_offset)
2576                    .expect("Failed to write test data.");
2577                // Read back the data to check it was written correctly.
2578                read_exact_at(&mut qcow_file, &mut readback, seek_offset).expect("Failed to read.");
2579                for (orig, read) in data.iter().zip(readback.iter()) {
2580                    assert_eq!(orig, read);
2581                }
2582            }
2583            // Check that address 0 is still zeros.
2584            read_exact_at(&mut qcow_file, &mut readback, 0).expect("Failed to read.");
2585            for read in readback.iter() {
2586                assert_eq!(*read, 0);
2587            }
2588            // Check the data again after the writes have happened.
2589            for i in 0..NUM_BLOCKS {
2590                let seek_offset = OFFSET + (i as u64) * (BLOCK_SIZE as u64);
2591                read_exact_at(&mut qcow_file, &mut readback, seek_offset).expect("Failed to read.");
2592                for (orig, read) in data.iter().zip(readback.iter()) {
2593                    assert_eq!(orig, read);
2594                }
2595            }
2596
2597            assert_eq!(
2598                qcow_file.inner.get_mut().first_zero_refcount().unwrap(),
2599                None
2600            );
2601        });
2602    }
2603
2604    #[test]
2605    fn rebuild_refcounts() {
2606        with_basic_file(&valid_header(), |mut disk_file: File| {
2607            let header = QcowHeader::new(&mut disk_file).expect("Failed to create Header.");
2608            let cluster_size = 65536;
2609            let mut raw_file =
2610                QcowRawFile::from(disk_file, cluster_size).expect("Failed to create QcowRawFile.");
2611            QcowFileInner::rebuild_refcounts(&mut raw_file, header)
2612                .expect("Failed to rebuild recounts.");
2613        });
2614    }
2615
2616    #[cfg_attr(windows, ignore = "TODO(b/257958782): Enable large test on windows")]
2617    #[test]
2618    fn nested_qcow() {
2619        let tmp_dir = TempDir::new().unwrap();
2620
2621        // A file `backing` is backing a qcow file `qcow.l1`, which in turn is backing another
2622        // qcow file.
2623        let backing_file_path = tmp_dir.path().join("backing");
2624        let _backing_file = OpenOptions::new()
2625            .read(true)
2626            .write(true)
2627            .create_new(true)
2628            .open(&backing_file_path)
2629            .unwrap();
2630
2631        let level1_qcow_file_path = tmp_dir.path().join("qcow.l1");
2632        let level1_qcow_file = OpenOptions::new()
2633            .read(true)
2634            .write(true)
2635            .create_new(true)
2636            .open(&level1_qcow_file_path)
2637            .unwrap();
2638        let _level1_qcow_file = QcowFile::new_from_backing(
2639            level1_qcow_file,
2640            test_params(),
2641            backing_file_path.to_str().unwrap(),
2642        )
2643        .unwrap();
2644
2645        let level2_qcow_file = tempfile().unwrap();
2646        let _level2_qcow_file = QcowFile::new_from_backing(
2647            level2_qcow_file,
2648            test_params(),
2649            level1_qcow_file_path.to_str().unwrap(),
2650        )
2651        .expect("failed to create level2 qcow file");
2652    }
2653
2654    #[test]
2655    fn io_seek() {
2656        with_default_file(1024 * 1024 * 10, |mut qcow_file| {
2657            // Cursor should start at 0.
2658            assert_eq!(qcow_file.stream_position().unwrap(), 0);
2659
2660            // Seek 1 MB from start.
2661            assert_eq!(
2662                qcow_file.seek(SeekFrom::Start(1024 * 1024)).unwrap(),
2663                1024 * 1024
2664            );
2665
2666            // Rewind 1 MB + 1 byte (past beginning) - seeking to a negative offset is an error and
2667            // should not move the cursor.
2668            qcow_file
2669                .seek(SeekFrom::Current(-(1024 * 1024 + 1)))
2670                .expect_err("negative offset seek should fail");
2671            assert_eq!(qcow_file.stream_position().unwrap(), 1024 * 1024);
2672
2673            // Seek to last byte.
2674            assert_eq!(
2675                qcow_file.seek(SeekFrom::End(-1)).unwrap(),
2676                1024 * 1024 * 10 - 1
2677            );
2678
2679            // Seek to EOF.
2680            assert_eq!(qcow_file.seek(SeekFrom::End(0)).unwrap(), 1024 * 1024 * 10);
2681
2682            // Seek past EOF is not allowed.
2683            qcow_file
2684                .seek(SeekFrom::End(1))
2685                .expect_err("seek past EOF should fail");
2686        });
2687    }
2688
2689    #[test]
2690    fn io_write_read() {
2691        with_default_file(1024 * 1024 * 10, |mut qcow_file| {
2692            const BLOCK_SIZE: usize = 0x1_0000;
2693            let data_55 = [0x55u8; BLOCK_SIZE];
2694            let data_aa = [0xaau8; BLOCK_SIZE];
2695            let mut readback = [0u8; BLOCK_SIZE];
2696
2697            qcow_file.write_all(&data_55).unwrap();
2698            assert_eq!(qcow_file.stream_position().unwrap(), BLOCK_SIZE as u64);
2699
2700            qcow_file.write_all(&data_aa).unwrap();
2701            assert_eq!(qcow_file.stream_position().unwrap(), BLOCK_SIZE as u64 * 2);
2702
2703            // Read BLOCK_SIZE of just 0xaa.
2704            assert_eq!(
2705                qcow_file
2706                    .seek(SeekFrom::Current(-(BLOCK_SIZE as i64)))
2707                    .unwrap(),
2708                BLOCK_SIZE as u64
2709            );
2710            qcow_file.read_exact(&mut readback).unwrap();
2711            assert_eq!(qcow_file.stream_position().unwrap(), BLOCK_SIZE as u64 * 2);
2712            for (orig, read) in data_aa.iter().zip(readback.iter()) {
2713                assert_eq!(orig, read);
2714            }
2715
2716            // Read BLOCK_SIZE of just 0x55.
2717            qcow_file.rewind().unwrap();
2718            qcow_file.read_exact(&mut readback).unwrap();
2719            for (orig, read) in data_55.iter().zip(readback.iter()) {
2720                assert_eq!(orig, read);
2721            }
2722
2723            // Read BLOCK_SIZE crossing between the block of 0x55 and 0xaa.
2724            qcow_file
2725                .seek(SeekFrom::Start(BLOCK_SIZE as u64 / 2))
2726                .unwrap();
2727            qcow_file.read_exact(&mut readback).unwrap();
2728            for (orig, read) in data_55[BLOCK_SIZE / 2..]
2729                .iter()
2730                .chain(data_aa[..BLOCK_SIZE / 2].iter())
2731                .zip(readback.iter())
2732            {
2733                assert_eq!(orig, read);
2734            }
2735        });
2736    }
2737
2738    #[test]
2739    fn header_with_backing_format() {
2740        let header = QcowHeader::create_for_size_and_path(
2741            0x10_0000,
2742            Some(("/my/path/to/a/file", crate::ImageType::Raw)),
2743        )
2744        .expect("Failed to create header.");
2745        let mut disk_file = tempfile().expect("failed to create temp file");
2746        header
2747            .write_to(&mut disk_file)
2748            .expect("Failed to write header.");
2749        disk_file.seek(SeekFrom::Start(0)).unwrap();
2750        let read_header = QcowHeader::new(&mut disk_file).expect("Failed to create header.");
2751        assert_eq!(
2752            header.backing_file_path,
2753            Some(String::from("/my/path/to/a/file"))
2754        );
2755        assert_eq!(read_header.backing_file_path, header.backing_file_path);
2756        assert_eq!(read_header.backing_file_format, Some(crate::ImageType::Raw));
2757    }
2758
2759    #[test]
2760    fn test_backing_format_respected() {
2761        let temp_dir = TempDir::new().expect("failed to create temp dir");
2762        let backing_path = temp_dir.path().join("backing.raw");
2763        let parent_path = temp_dir.path().join("parent.qcow2");
2764
2765        // Create backing file with fake Qcow2 magic
2766        let mut backing_file = File::create(&backing_path).unwrap();
2767        backing_file.write_all(&QCOW_MAGIC.to_be_bytes()).unwrap();
2768        backing_file.set_len(1024 * 1024).unwrap();
2769        drop(backing_file);
2770
2771        // Create parent Qcow2 header specifying backing file and backing format = RAW
2772        let header_raw = QcowHeader::create_for_size_and_path(
2773            1024 * 1024 * 10,
2774            Some((backing_path.to_str().unwrap(), crate::ImageType::Raw)),
2775        )
2776        .expect("Failed to create header.");
2777
2778        let mut parent_file = File::create(&parent_path).unwrap();
2779        header_raw.write_to(&mut parent_file).unwrap();
2780        drop(parent_file);
2781
2782        // Open parent. It should succeed because backing is opened as raw.
2783        let parent_file = OpenOptions::new()
2784            .read(true)
2785            .write(true)
2786            .open(&parent_path)
2787            .unwrap();
2788        let mut params = test_params();
2789        params.path = parent_path.clone();
2790        let qcow = QcowFile::from(parent_file, params);
2791        assert!(
2792            qcow.is_ok(),
2793            "Failed to open with explicit raw backing: {:?}",
2794            qcow.err()
2795        );
2796
2797        // Create parent Qcow2 header WITHOUT backing format extension
2798        let mut header_auto = QcowHeader::create_for_size_and_path(
2799            1024 * 1024 * 10,
2800            Some((backing_path.to_str().unwrap(), crate::ImageType::Raw)),
2801        )
2802        .expect("Failed to create header.");
2803        header_auto.backing_file_format = None;
2804        header_auto.backing_file_offset = V3_BARE_HEADER_SIZE as u64 + 8;
2805
2806        let mut parent_file_auto = File::create(&parent_path).unwrap();
2807        header_auto.write_to(&mut parent_file_auto).unwrap();
2808        drop(parent_file_auto);
2809
2810        // Open parent. It should fail because backing format extension is missing.
2811        let parent_file_auto = OpenOptions::new()
2812            .read(true)
2813            .write(true)
2814            .open(&parent_path)
2815            .unwrap();
2816        let mut params = test_params();
2817        params.path = parent_path.clone();
2818        let qcow_auto = QcowFile::from(parent_file_auto, params);
2819        assert!(
2820            matches!(
2821                qcow_auto.as_ref().err(),
2822                Some(&Error::MissingBackingFileFormat)
2823            ),
2824            "Expected Error::MissingBackingFileFormat, got: {qcow_auto:?}"
2825        );
2826    }
2827
2828    #[test]
2829    fn test_unsupported_backing_format() {
2830        // 1. Creation time rejection of AndroidSparse
2831        let header_err = QcowHeader::create_for_size_and_path(
2832            1024 * 1024 * 10,
2833            Some(("backing.img", crate::ImageType::AndroidSparse)),
2834        );
2835        assert!(
2836            matches!(
2837                header_err.as_ref().err(),
2838                Some(&Error::UnsupportedBackingFileFormat(_))
2839            ),
2840            "Expected Error::UnsupportedBackingFileFormat, got: {header_err:?}"
2841        );
2842
2843        // 2. Open time rejection of unknown format string
2844        let header = QcowHeader::create_for_size_and_path(
2845            1024 * 1024 * 10,
2846            Some(("backing.raw", crate::ImageType::Raw)),
2847        )
2848        .unwrap();
2849
2850        let mut file = tempfile().unwrap();
2851        header.write_to(&mut file).unwrap();
2852
2853        // Overwrite the format extension with "invalid" (len 7, fits in same 8-byte pad block)
2854        file.seek(SeekFrom::Start(108)).unwrap();
2855        file.write_all(&7u32.to_be_bytes()).unwrap(); // New length: 7
2856        file.write_all(b"invalid\0").unwrap(); // New format string + 1 byte padding to 8 bytes
2857
2858        // Try to read it back. It should fail during header parsing.
2859        file.seek(SeekFrom::Start(0)).unwrap();
2860        let read_result = QcowHeader::new(&mut file);
2861        match &read_result {
2862            Err(Error::UnsupportedBackingFileFormat(fmt)) => {
2863                assert_eq!(fmt, "invalid");
2864            }
2865            other => {
2866                panic!("Expected Error::UnsupportedBackingFileFormat(\"invalid\"), got: {other:?}")
2867            }
2868        }
2869    }
2870
2871    #[test]
2872    fn test_create_excessive_size_rejected() {
2873        let header = QcowHeader::create_for_size_and_path(MAX_QCOW_FILE_SIZE + 1, None);
2874        assert!(matches!(header.err(), Some(Error::FileTooBig(_))));
2875    }
2876
2877    #[cfg(feature = "composite-disk")]
2878    #[test]
2879    fn test_composite_backing() {
2880        use protobuf::Message;
2881        use protos::cdisk_spec;
2882
2883        use crate::composite::CDISK_MAGIC;
2884
2885        let temp_dir = TempDir::new().expect("failed to create temp dir");
2886        let component_path = temp_dir.path().join("component.raw");
2887        let spec_path = temp_dir.path().join("backing.cdisk");
2888        let parent_path = temp_dir.path().join("parent.qcow2");
2889
2890        // Create component file (raw)
2891        let component_file = File::create(&component_path).unwrap();
2892        component_file.set_len(1024 * 1024).unwrap(); // 1MB
2893        drop(component_file);
2894
2895        // Create composite spec
2896        let mut proto = cdisk_spec::CompositeDisk::new();
2897        proto.version = 2;
2898        proto.length = 1024 * 1024;
2899        let mut component = cdisk_spec::ComponentDisk::new();
2900        // Use relative path for component
2901        component.file_path = String::from("component.raw");
2902        component.offset = 0;
2903        component.file_offset = 0;
2904        component.read_write_capability = cdisk_spec::ReadWriteCapability::READ_WRITE.into();
2905        proto.component_disks.push(component);
2906
2907        let mut spec_file = File::create(&spec_path).unwrap();
2908        spec_file.write_all(CDISK_MAGIC.as_bytes()).unwrap();
2909        proto.write_to_writer(&mut spec_file).unwrap();
2910        drop(spec_file);
2911
2912        // Create parent Qcow2 header specifying composite backing file
2913        let header = QcowHeader::create_for_size_and_path(
2914            1024 * 1024 * 10,
2915            Some((spec_path.to_str().unwrap(), crate::ImageType::CompositeDisk)),
2916        )
2917        .expect("Failed to create header.");
2918
2919        let mut parent_file = File::create(&parent_path).unwrap();
2920        header.write_to(&mut parent_file).unwrap();
2921        drop(parent_file);
2922
2923        // Open parent. It should succeed and open backing as composite.
2924        let parent_file = OpenOptions::new()
2925            .read(true)
2926            .write(true)
2927            .open(&parent_path)
2928            .unwrap();
2929        let mut params = test_params();
2930        params.path = parent_path.clone();
2931        let qcow = QcowFile::from(parent_file, params);
2932        assert!(
2933            qcow.is_ok(),
2934            "Failed to open with composite backing: {:?}",
2935            qcow.err()
2936        );
2937    }
2938
2939    #[test]
2940    fn test_backing_file_escapes_first_cluster() {
2941        // Create a header with backing file
2942        let mut header = QcowHeader::create_for_size_and_path(
2943            1024 * 1024 * 10,
2944            Some(("backing.raw", crate::ImageType::Raw)),
2945        )
2946        .unwrap();
2947
2948        // Default cluster size is 65536.
2949        // Manually set backing_file_offset to be outside the first cluster.
2950        header.backing_file_offset = 70000;
2951
2952        let mut file = tempfile().unwrap();
2953        header.write_to(&mut file).unwrap();
2954
2955        // Try to read it back. It should fail because backing_file_offset escapes first cluster.
2956        let read_result = QcowHeader::new(&mut file);
2957        match &read_result {
2958            Err(Error::BackingFileEscapesFirstCluster) => {}
2959            other => panic!("Expected Error::BackingFileEscapesFirstCluster, got: {other:?}"),
2960        }
2961    }
2962}