1use anyhow::Context;
7use std::path::Path;
8use vm_resource::Resource;
9use vm_resource::kind::DiskHandleKind;
10
11fn disk_open_error(path: &Path, verb: &str) -> String {
12 let mut msg = format!("{verb} '{}'", path.display());
13
14 if cfg!(windows) && std::env::var_os("WSLENV").is_some() {
17 msg += ". Linux paths are not supported when running Windows executables \
18 under WSL, make sure the path is a valid Windows path \
19 (use `wslpath -w` to convert)";
20 }
21
22 msg
23}
24
25pub fn open_disk_type(path: &Path, read_only: bool) -> anyhow::Result<Resource<DiskHandleKind>> {
31 Ok(match path.extension().and_then(|s| s.to_str()) {
32 Some("vhd") => {
33 let file = std::fs::OpenOptions::new()
34 .read(true)
35 .write(!read_only)
36 .open(path)
37 .with_context(|| disk_open_error(path, "failed to open"))?;
38
39 match disk_vhd1::Vhd1Disk::open_fixed(file, read_only) {
40 Ok(vhd) => Resource::new(disk_backend_resources::FixedVhd1DiskHandle(
41 vhd.into_inner(),
42 )),
43 Err(disk_vhd1::OpenError::NotFixed) => {
44 #[cfg(windows)]
45 {
46 Resource::new(disk_vhdmp::OpenVhdmpDiskConfig(
47 disk_vhdmp::VhdmpDisk::open_vhd(path, read_only)
48 .with_context(|| disk_open_error(path, "failed to open"))?,
49 ))
50 }
51 #[cfg(not(windows))]
52 anyhow::bail!("non-fixed VHD not supported on Linux");
53 }
54 Err(err) => return Err(err.into()),
55 }
56 }
57 Some("vhdx") => {
58 #[cfg(windows)]
59 {
60 Resource::new(disk_vhdmp::OpenVhdmpDiskConfig(
61 disk_vhdmp::VhdmpDisk::open_vhd(path, read_only)
62 .with_context(|| disk_open_error(path, "failed to open"))?,
63 ))
64 }
65 #[cfg(not(windows))]
66 anyhow::bail!("VHDX not supported on Linux");
67 }
68 Some("iso") if !read_only => {
69 anyhow::bail!("iso file cannot be opened as read/write")
70 }
71 Some("vmgs") => {
72 let file = std::fs::OpenOptions::new()
75 .read(true)
76 .write(!read_only)
77 .open(path)
78 .with_context(|| disk_open_error(path, "failed to open"))?;
79
80 Resource::new(disk_backend_resources::FixedVhd1DiskHandle(file))
81 }
82 _ => {
83 let file = std::fs::OpenOptions::new()
84 .read(true)
85 .write(!read_only)
86 .open(path)
87 .with_context(|| disk_open_error(path, "failed to open"))?;
88
89 Resource::new(disk_backend_resources::FileDiskHandle(file))
90 }
91 })
92}
93
94pub fn create_disk_type(path: &Path, size: u64) -> anyhow::Result<Resource<DiskHandleKind>> {
96 Ok(match path.extension().and_then(|s| s.to_str()) {
97 Some("vhd") | Some("vmgs") => {
98 let file = std::fs::OpenOptions::new()
99 .create(true)
100 .truncate(true)
101 .read(true)
102 .write(true)
103 .open(path)
104 .with_context(|| disk_open_error(path, "failed to create"))?;
105
106 file.set_len(size)?;
107 disk_vhd1::Vhd1Disk::make_fixed(&file)?;
108 Resource::new(disk_backend_resources::FixedVhd1DiskHandle(file))
109 }
110 Some("vhdx") => {
111 anyhow::bail!("creating vhdx not supported")
112 }
113 Some("iso") => {
114 anyhow::bail!("creating iso not supported")
115 }
116 _ => {
117 let file = std::fs::OpenOptions::new()
118 .create(true)
119 .truncate(true)
120 .read(true)
121 .write(true)
122 .open(path)
123 .with_context(|| disk_open_error(path, "failed to create"))?;
124
125 file.set_len(size)?;
126 Resource::new(disk_backend_resources::FileDiskHandle(file))
127 }
128 })
129}