1use core::ops::Deref;
2
3use alloc::sync::Arc;
4pub fn write_zeroes<T>(f: &mut T, size: u64, offset: u64) -> Result<(), T::Err>
6where
7 T: WriteSeek,
8{
9 let buffer = [0u8; 4 * crate::KB as usize];
10
11 f.seek(SeekFrom::Start(offset))?;
13
14 let mut remaining = size;
15 while remaining > 0 {
16 let iter_size = remaining.min(buffer.len() as u64);
17 if f.write(&buffer[..iter_size as usize])? != iter_size as usize {
19 return Err(f.failed_to_write());
20 }
21 remaining -= iter_size;
22 }
23 Ok(())
24}
25
26pub trait WriteSeek {
27 type Err;
28 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Err>;
29 fn failed_to_write(&self) -> Self::Err;
30 fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Err>;
31 fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Err>;
32 fn stream_position(&mut self) -> Result<u64, Self::Err>;
33}
34#[cfg(feature = "std")]
35impl<T> WriteSeek for T
36where
37 T: std::io::Write + std::io::Seek,
38{
39 type Err = std::io::Error;
40
41 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Err> {
42 std::io::Write::write(self, buf)
43 }
44 fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Err> {
45 std::io::Write::write_all(self, buf)
46 }
47 fn failed_to_write(&self) -> Self::Err {
48 Self::Err::new(std::io::ErrorKind::WriteZero, "Failed to write 0s")
49 }
50 fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Err> {
51 std::io::Seek::seek(self, pos.into())
52 }
53 fn stream_position(&mut self) -> Result<u64, Self::Err> {
54 std::io::Seek::stream_position(self)
55 }
56}
57
58pub enum SeekFrom {
59 Start(u64),
60 End(i64),
61 Current(i64),
62}
63
64#[cfg(feature = "std")]
65impl From<SeekFrom> for std::io::SeekFrom {
66 fn from(value: SeekFrom) -> Self {
67 match value {
68 SeekFrom::Start(x) => std::io::SeekFrom::Start(x),
69 SeekFrom::End(x) => std::io::SeekFrom::End(x),
70 SeekFrom::Current(x) => std::io::SeekFrom::Current(x),
71 }
72 }
73}
74
75pub trait PartitionError: core::fmt::Debug {
76 fn unexpected_eop() -> Self;
77
78 fn cluster_not_found(cluster: u32) -> Self;
79}
80
81pub trait ReadOffset {
82 type Err: PartitionError + 'static;
83
84 fn read_at(&self, offset: u64, buffer: &mut [u8]) -> Result<usize, Self::Err>;
85
86 fn read_exact(&self, mut offset: u64, mut buffer: &mut [u8]) -> Result<(), Self::Err> {
87 while !buffer.is_empty() {
88 match self.read_at(offset, buffer) {
89 Ok(0) => break,
90 Ok(n) => {
91 buffer = &mut buffer[n..];
92 offset = offset
93 .checked_add(n as u64)
94 .ok_or(PartitionError::unexpected_eop())?;
95 }
96 Err(e) => return Err(e),
97 }
98 }
99 Ok(())
100 }
101}
102
103#[cfg(feature = "std")]
104impl PartitionError for std::io::Error {
105 fn unexpected_eop() -> Self {
106 std::io::Error::from(std::io::ErrorKind::UnexpectedEof)
107 }
108
109 fn cluster_not_found(cluster: u32) -> Self {
110 std::io::Error::new(
111 std::io::ErrorKind::Other,
112 format!("cluster #{cluster} is not available"),
113 )
114 }
115}
116
117impl<T: ReadOffset> ReadOffset for &T {
118 type Err = T::Err;
119
120 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize, Self::Err> {
121 (*self).read_at(offset, buf)
122 }
123}
124impl<T: ReadOffset> ReadOffset for Arc<T> {
125 type Err = T::Err;
126
127 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize, Self::Err> {
128 self.deref().read_at(offset, buf)
129 }
130}
131#[cfg(feature = "std")]
132impl ReadOffset for std::fs::File {
133 type Err = std::io::Error;
134
135 #[cfg(unix)]
136 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize, Self::Err> {
137 std::os::unix::fs::FileExt::read_at(self, buf, offset)
138 }
139
140 #[cfg(windows)]
141 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize, Self::Err> {
142 std::os::windows::fs::FileExt::seek_read(self, buf, offset)
143 }
144}