1use super::*;
8use crate::io_buffers::IoBuffer;
9
10#[maybe_async]
11impl<S: Storage, F: WrappedFormat<S>> Qcow2<S, F> {
12 pub(super) async fn do_readv_special<'a>(
20 &self,
21 mut bufv: IoVectorMut<'a>,
22 mut offset: GuestOffset,
23 ) -> io::Result<Option<(IoVectorMut<'a>, u64)>> {
24 let mut saved_l2_table: Option<Arc<L2Table>> = None;
25 let cb = self.header.cluster_bits();
26
27 while !bufv.is_empty() {
29 let l2_table = if let Some(saved) = saved_l2_table.as_ref() {
30 saved
31 } else {
32 let Some(new_l2) = self.get_l2(offset, false).await? else {
33 return Ok(Some((bufv, offset.0)));
35 };
36 saved_l2_table.get_or_insert(new_l2)
37 };
38
39 let guest_cluster = offset.cluster(cb);
43 let Some(compressed_guard) = l2_table.lock_compressed_read(guest_cluster).await? else {
44 return Ok(Some((bufv, offset.0)));
45 };
46
47 let chunk_length = offset.remaining_in_cluster(cb);
48 let (chunk, remainder) = bufv.split_at(chunk_length);
49 bufv = remainder;
50
51 let mut bounce_buffer_and_chunk = None;
52 let need_bounce_buffer = chunk.buffer_count() != 1
53 || offset.in_cluster_offset(cb) != 0
54 || chunk.len() != self.header.cluster_size() as u64;
55
56 let slice = if need_bounce_buffer {
57 let bounce_buffer = IoBuffer::new(self.header.cluster_size(), 1)?;
58 bounce_buffer_and_chunk = Some((bounce_buffer, chunk));
59 bounce_buffer_and_chunk.as_mut().unwrap().0.as_mut()
60 } else {
61 chunk.into_inner().pop().unwrap().into()
62 };
63
64 compressed_guard
65 .read_compressed(self.storage(), slice.into_slice())
66 .await?;
67 drop(compressed_guard);
68
69 if let Some((bounce_buffer, mut chunk)) = bounce_buffer_and_chunk {
70 let ofs = offset.in_cluster_offset(cb);
71 let end = ofs + chunk.len() as usize;
72 chunk.copy_from_slice(bounce_buffer.as_ref_range(ofs..end).into_slice());
73 }
74
75 let next_cluster = if let Some(next) = guest_cluster.next_in_l2(cb) {
76 next
77 } else {
78 saved_l2_table.take();
79 guest_cluster.first_in_next_l2(cb)
80 };
81 offset = next_cluster.offset(cb);
82 }
83
84 Ok(None)
85 }
86}