1use super::*;
4use crate::format::builder::{
5 FormatCreateBuilderBase, FormatDriverBuilderBase, FormatOrBuilder, StorageOrPath,
6};
7use crate::DenyImplicitOpenGate;
8use std::marker::PhantomData;
9use std::path::PathBuf;
10
11pub struct Qcow2OpenBuilder<S: Storage + 'static, F: WrappedFormat<S> + 'static = FormatAccess<S>> {
15 base: FormatDriverBuilderBase<S>,
17
18 backing: Option<Option<FormatOrBuilder<S, F>>>,
23
24 data_file: Option<Option<StorageOrPath<S>>>,
29}
30
31pub struct Qcow2CreateBuilder<S: Storage + 'static, F: WrappedFormat<S> + 'static = FormatAccess<S>>
35{
36 base: FormatCreateBuilderBase<S>,
38
39 backing: Option<(String, String)>,
41
42 data_file: Option<(String, S)>,
44
45 cluster_size: usize,
47
48 refcount_width: usize,
50
51 _wrapped_format: PhantomData<F>,
53}
54
55impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2OpenBuilder<S, F> {
56 fn with_base(base: FormatDriverBuilderBase<S>) -> Self {
58 Qcow2OpenBuilder {
59 base,
60 backing: None,
61 data_file: None,
62 }
63 }
64
65 pub fn backing(mut self, backing: Option<F>) -> Self {
71 self.backing = Some(backing.map(FormatOrBuilder::Format));
72 self
73 }
74
75 pub fn backing_path<P: AsRef<Path>>(mut self, backing: P, format: Format) -> Self {
83 self.backing = Some(Some(FormatOrBuilder::new_builder(format, backing)));
84 self
85 }
86
87 pub fn data_file(mut self, data_file: Option<S>) -> Self {
106 self.data_file = Some(data_file.map(StorageOrPath::Storage));
107 self
108 }
109}
110
111impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> FormatDriverBuilder<S>
112 for Qcow2OpenBuilder<S, F>
113{
114 type Format = Qcow2<S, F>;
115 const FORMAT: Format = Format::Qcow2;
116
117 fn new(image: S) -> Self {
118 Self::with_base(FormatDriverBuilderBase::new(image))
119 }
120
121 fn new_path<P: AsRef<Path>>(path: P) -> Self {
122 Self::with_base(FormatDriverBuilderBase::new_path(path))
123 }
124
125 fn write(mut self, write: bool) -> Self {
126 self.base.set_write(write);
127 self
128 }
129
130 fn storage_open_options(mut self, options: StorageOpenOptions) -> Self {
131 self.base.set_storage_open_options(options);
132 self
133 }
134
135 async fn open<G: ImplicitOpenGate<S>>(self, mut gate: G) -> io::Result<Self::Format> {
136 let writable = self.base.get_writable();
137 let storage_opts = self.base.make_storage_opts();
138 let metadata = self.base.open_image(&mut gate).await?;
139
140 let mut qcow2 = Qcow2::<S, F>::do_open(metadata, writable, storage_opts.clone()).await?;
141
142 if let Some(backing) = self.backing {
143 let backing = match backing {
144 None => None,
145 Some(backing) => Some(
146 backing
147 .open_format(storage_opts.clone().write(false), &mut gate)
148 .await
149 .err_context(|| "Backing file")?,
150 ),
151 };
152 qcow2.set_backing(backing);
153 }
154
155 if let Some(data_file) = self.data_file {
156 let data_file = match data_file {
157 None => None,
158 Some(data_file) => Some(
159 data_file
160 .open_storage(storage_opts, &mut gate)
161 .await
162 .err_context(|| "External data file")?,
163 ),
164 };
165 qcow2.set_data_file(data_file);
166 }
167
168 qcow2.open_implicit_dependencies_gated(gate).await?;
169
170 Ok(qcow2)
171 }
172
173 fn get_image_path(&self) -> Option<PathBuf> {
174 self.base.get_image_path()
175 }
176
177 fn get_writable(&self) -> bool {
178 self.base.get_writable()
179 }
180
181 fn get_storage_open_options(&self) -> Option<&StorageOpenOptions> {
182 self.base.get_storage_opts()
183 }
184}
185
186impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2CreateBuilder<S, F> {
187 pub fn backing(mut self, backing_filename: String, backing_format: String) -> Self {
196 self.backing = Some((backing_filename, backing_format));
197 self
198 }
199
200 pub fn data_file(mut self, filename: String, file: S) -> Self {
209 self.data_file = Some((filename, file));
210 self
211 }
212
213 pub fn cluster_size(mut self, size: usize) -> Self {
223 self.cluster_size = size;
224 self
225 }
226
227 pub fn refcount_width(mut self, bits: usize) -> Self {
239 self.refcount_width = bits;
240 self
241 }
242}
243
244impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> FormatCreateBuilder<S>
245 for Qcow2CreateBuilder<S, F>
246{
247 const FORMAT: Format = Format::Qcow2;
248 type DriverBuilder = Qcow2OpenBuilder<S, F>;
249
250 fn new(image: S) -> Self {
251 Qcow2CreateBuilder {
252 base: FormatCreateBuilderBase::new(image),
253 backing: None,
254 data_file: None,
255 cluster_size: 65536,
256 refcount_width: 16,
257 _wrapped_format: PhantomData,
258 }
259 }
260
261 fn size(mut self, size: u64) -> Self {
262 self.base.set_size(size);
263 self
264 }
265
266 fn preallocate(mut self, prealloc_mode: PreallocateMode) -> Self {
267 self.base.set_preallocate(prealloc_mode);
268 self
269 }
270
271 fn get_size(&self) -> u64 {
272 self.base.get_size()
273 }
274
275 fn get_preallocate(&self) -> PreallocateMode {
276 self.base.get_preallocate()
277 }
278
279 async fn create(self) -> io::Result<()> {
280 self.create_open(DenyImplicitOpenGate::default(), |image| {
281 Ok(Qcow2::<S, F>::builder(image).backing(None).write(true))
283 })
284 .await?
285 .flush()
286 .await?;
287
288 Ok(())
289 }
290
291 async fn create_open<
292 G: ImplicitOpenGate<S>,
293 OBF: FnOnce(S) -> io::Result<Qcow2OpenBuilder<S, F>>,
294 >(
295 self,
296 open_gate: G,
297 open_builder_fn: OBF,
298 ) -> io::Result<Qcow2<S, F>> {
299 let size = self.base.get_size();
300 let prealloc = self.base.get_preallocate();
301 let image = self.base.get_image();
302
303 let cluster_size = self.cluster_size;
304 if !cluster_size.is_power_of_two() {
305 return Err(io::Error::new(
306 io::ErrorKind::InvalidInput,
307 format!("Cluster size {cluster_size} is not a power of two"),
308 ));
309 }
310
311 let cs_range = MIN_CLUSTER_SIZE..=MAX_CLUSTER_SIZE;
312 if !cs_range.contains(&cluster_size) {
313 return Err(io::Error::new(
314 io::ErrorKind::InvalidInput,
315 format!("Cluster size {cluster_size} not in {cs_range:?}"),
316 ));
317 }
318
319 let cluster_bits = cluster_size.trailing_zeros();
320 assert!(1 << cluster_bits == cluster_size);
321
322 let refcount_width = self.refcount_width;
323 if !refcount_width.is_power_of_two() {
324 return Err(io::Error::new(
325 io::ErrorKind::InvalidInput,
326 format!("Refcount width {refcount_width} is not a power of two"),
327 ));
328 }
329
330 let rw_range = MIN_REFCOUNT_WIDTH..=MAX_REFCOUNT_WIDTH;
331 if !rw_range.contains(&refcount_width) {
332 return Err(io::Error::new(
333 io::ErrorKind::InvalidInput,
334 format!("Refcount width {refcount_width} not in {rw_range:?}"),
335 ));
336 }
337
338 let refcount_order = refcount_width.trailing_zeros();
339 assert!(1 << refcount_order == refcount_width);
340
341 if image.size()? > 0 {
343 image.resize(size, storage::PreallocateMode::None).await?;
344 }
345
346 let (backing_fname, backing_format) = match self.backing {
359 Some((fname, fmt)) => (Some(fname), Some(fmt)),
360 None => (None, None),
361 };
362
363 let (data_file_name, data_file) = match self.data_file {
364 Some((fname, file)) => (Some(fname), Some(file)),
365 None => (None, None),
366 };
367
368 let mut header = Header::new(
369 cluster_bits,
370 refcount_order,
371 backing_fname,
372 backing_format,
373 data_file_name,
374 );
375
376 let mut rb = RefBlock::new_cleared(&image, &header)?;
377 rb.set_cluster(HostCluster(2));
378 {
379 let mut rb_locked = rb.lock_write().await;
380 rb_locked.increment(0)?; rb_locked.increment(1)?; rb_locked.increment(2)?; }
384 rb.write(&image).await?;
385
386 let mut rt = RefTable::from_data(Box::new([]), &header).clone_and_grow(&header, 0)?;
387 rt.set_cluster(HostCluster(1));
388 rt.enter_refblock(0, &rb)?;
389 rt.write(&image).await?;
390
391 header.set_reftable(&rt)?;
392 header.write(&image).await?;
393
394 let img = open_builder_fn(image)?
395 .write(true)
396 .data_file(data_file)
397 .open(open_gate)
398 .await?;
399 if size > 0 {
400 img.resize_grow(size, prealloc).await?;
401 }
402
403 Ok(img)
404 }
405}