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