1io_transform! {
2
3#[cfg(feature = "read")]
4use super::super::Read;
5#[cfg(any(feature = "read", feature = "write"))]
6use super::super::{Seek, SeekFrom};
7#[cfg(feature = "write")]
8use super::super::Write;
9#[cfg(any(feature = "read", feature = "write"))]
10use crate::gpt::{GptHeader, GptHeaderRaw};
11
12#[cfg(feature = "read")]
16#[cfg_attr(docsrs, doc(cfg(feature = "read")))]
17pub trait GptHeaderReadExt: Sized {
18 async fn read_from<R: Read>(reader: &mut R) -> crate::error::Result<Self>;
26
27 async fn read_from_lba<R: Read + Seek>(
33 reader: &mut R,
34 lba: u64,
35 block_size: u32,
36 ) -> crate::error::Result<Self>;
37}
38
39#[cfg(feature = "read")]
40impl GptHeaderReadExt for GptHeader {
41 async fn read_from<R: Read>(reader: &mut R) -> crate::error::Result<Self> {
42 let mut buf = [0u8; GptHeaderRaw::SIZE];
43 reader
44 .read_exact(&mut buf)
45 .await
46 .map_err(crate::error::Error::from)?;
47 let raw: GptHeaderRaw = bytemuck::cast(buf);
48 let header = Self::from_raw(&raw);
49
50 if !header.has_valid_signature() {
51 return Err(crate::error::Error::InvalidGptSignature {
52 found: header.signature,
53 });
54 }
55
56 Ok(header)
57 }
58
59 async fn read_from_lba<R: Read + Seek>(
60 reader: &mut R,
61 lba: u64,
62 block_size: u32,
63 ) -> crate::error::Result<Self> {
64 reader
67 .seek(SeekFrom::Start(lba.saturating_mul(u64::from(block_size))))
68 .await
69 .map_err(crate::error::Error::from)?;
70 Self::read_from(reader).await
71 }
72}
73
74#[cfg(feature = "write")]
76#[cfg_attr(docsrs, doc(cfg(feature = "write")))]
77pub trait GptHeaderWriteExt {
78 async fn write_to<W: Write>(&self, writer: &mut W) -> crate::error::Result<()>;
86
87 async fn write_to_lba<W: Write + Seek>(
93 &self,
94 writer: &mut W,
95 lba: u64,
96 block_size: u32,
97 ) -> crate::error::Result<()>;
98}
99
100#[cfg(feature = "write")]
101impl GptHeaderWriteExt for GptHeader {
102 async fn write_to<W: Write>(&self, writer: &mut W) -> crate::error::Result<()> {
103 let raw = self.to_raw();
104 writer
105 .write_all(bytemuck::bytes_of(&raw))
106 .await
107 .map_err(crate::error::Error::from)
108 }
109
110 async fn write_to_lba<W: Write + Seek>(
111 &self,
112 writer: &mut W,
113 lba: u64,
114 block_size: u32,
115 ) -> crate::error::Result<()> {
116 if block_size < GptHeaderRaw::SIZE as u32 {
117 return Err(crate::error::Error::InvalidBlockSize {
118 size: block_size,
119 minimum: GptHeaderRaw::SIZE as u32,
120 });
121 }
122 let Some(offset) = lba.checked_mul(u64::from(block_size)) else {
123 return Err(crate::error::Error::lba_offset_overflow());
124 };
125 writer
126 .seek(SeekFrom::Start(offset))
127 .await
128 .map_err(crate::error::Error::from)?;
129
130 let raw = self.to_raw();
131 writer
132 .write_all(bytemuck::bytes_of(&raw))
133 .await
134 .map_err(crate::error::Error::from)?;
135
136 let mut padding_size = block_size as usize - GptHeaderRaw::SIZE;
138 let padding = [0u8; 512];
139 while padding_size > 0 {
140 let chunk = padding_size.min(padding.len());
141 writer
142 .write_all(&padding[..chunk])
143 .await
144 .map_err(crate::error::Error::from)?;
145 padding_size -= chunk;
146 }
147
148 Ok(())
149 }
150}
151
152}