hvlite_helpers/
disk.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Guest disk helpers.
5
6use std::path::Path;
7use vm_resource::Resource;
8use vm_resource::kind::DiskHandleKind;
9
10/// Opens the resources needed for using a disk from a file at `path`.
11///
12/// If the file ends with .vhd and is a fixed VHD1, it will be opened using
13/// the user-mode VHD parser. Otherwise, if the file ends with .vhd or
14/// .vhdx, the file will be opened using the kernel-mode VHD parser.
15pub fn open_disk_type(path: &Path, read_only: bool) -> anyhow::Result<Resource<DiskHandleKind>> {
16    Ok(match path.extension().and_then(|s| s.to_str()) {
17        Some("vhd") => {
18            let file = std::fs::OpenOptions::new()
19                .read(true)
20                .write(!read_only)
21                .open(path)?;
22
23            match disk_vhd1::Vhd1Disk::open_fixed(file, read_only) {
24                Ok(vhd) => Resource::new(disk_backend_resources::FixedVhd1DiskHandle(
25                    vhd.into_inner(),
26                )),
27                Err(disk_vhd1::OpenError::NotFixed) => {
28                    #[cfg(windows)]
29                    {
30                        Resource::new(disk_vhdmp::OpenVhdmpDiskConfig(
31                            disk_vhdmp::VhdmpDisk::open_vhd(path, read_only)?,
32                        ))
33                    }
34                    #[cfg(not(windows))]
35                    anyhow::bail!("non-fixed VHD not supported on Linux");
36                }
37                Err(err) => return Err(err.into()),
38            }
39        }
40        Some("vhdx") => {
41            #[cfg(windows)]
42            {
43                Resource::new(disk_vhdmp::OpenVhdmpDiskConfig(
44                    disk_vhdmp::VhdmpDisk::open_vhd(path, read_only)?,
45                ))
46            }
47            #[cfg(not(windows))]
48            anyhow::bail!("VHDX not supported on Linux");
49        }
50        Some("iso") if !read_only => {
51            anyhow::bail!("iso file cannot be opened as read/write")
52        }
53        Some("vmgs") => {
54            // VMGS files are fixed VHD1s. Don't bother to validate the footer
55            // here; let the resource resolver do that later.
56            let file = std::fs::OpenOptions::new()
57                .read(true)
58                .write(!read_only)
59                .open(path)?;
60
61            Resource::new(disk_backend_resources::FixedVhd1DiskHandle(file))
62        }
63        _ => {
64            let file = std::fs::OpenOptions::new()
65                .read(true)
66                .write(!read_only)
67                .open(path)?;
68
69            Resource::new(disk_backend_resources::FileDiskHandle(file))
70        }
71    })
72}
73
74/// Create and open the resources needed for using a disk from a file at `path`.
75pub fn create_disk_type(path: &Path, size: u64) -> anyhow::Result<Resource<DiskHandleKind>> {
76    Ok(match path.extension().and_then(|s| s.to_str()) {
77        Some("vhd") | Some("vmgs") => {
78            let file = std::fs::OpenOptions::new()
79                .create(true)
80                .truncate(true)
81                .read(true)
82                .write(true)
83                .open(path)?;
84
85            file.set_len(size)?;
86            disk_vhd1::Vhd1Disk::make_fixed(&file)?;
87            Resource::new(disk_backend_resources::FixedVhd1DiskHandle(file))
88        }
89        Some("vhdx") => {
90            anyhow::bail!("creating vhdx not supported")
91        }
92        Some("iso") => {
93            anyhow::bail!("creating iso not supported")
94        }
95        _ => {
96            let file = std::fs::OpenOptions::new()
97                .create(true)
98                .truncate(true)
99                .read(true)
100                .write(true)
101                .open(path)?;
102
103            file.set_len(size)?;
104            Resource::new(disk_backend_resources::FileDiskHandle(file))
105        }
106    })
107}