ext4_mkfs/
block_device.rs1use crate::{Error, Result};
4use std::io::{Read, Seek, SeekFrom, Write};
5
6pub trait BlockDevice: Send {
11 fn block_size(&self) -> u32;
13
14 fn block_count(&self) -> u64;
16
17 fn read_blocks(&mut self, buf: &mut [u8], block_id: u64, block_count: u32) -> Result<()>;
24
25 fn write_blocks(&mut self, buf: &[u8], block_id: u64, block_count: u32) -> Result<()>;
32
33 fn open(&mut self) -> Result<()> {
35 Ok(())
36 }
37
38 fn close(&mut self) -> Result<()> {
40 Ok(())
41 }
42}
43
44pub struct IoBlockDevice<T> {
48 inner: T,
49 block_size: u32,
50 block_count: u64,
51}
52
53impl<T> IoBlockDevice<T>
54where
55 T: Read + Write + Seek,
56{
57 pub fn new(inner: T, block_size: u32, total_size: u64) -> Self {
64 let block_count = total_size / block_size as u64;
65 Self {
66 inner,
67 block_size,
68 block_count,
69 }
70 }
71
72 pub fn inner(&self) -> &T {
74 &self.inner
75 }
76
77 pub fn inner_mut(&mut self) -> &mut T {
79 &mut self.inner
80 }
81
82 pub fn into_inner(self) -> T {
84 self.inner
85 }
86}
87
88impl<T> BlockDevice for IoBlockDevice<T>
89where
90 T: Read + Write + Seek + Send,
91{
92 fn block_size(&self) -> u32 {
93 self.block_size
94 }
95
96 fn block_count(&self) -> u64 {
97 self.block_count
98 }
99
100 fn read_blocks(&mut self, buf: &mut [u8], block_id: u64, block_count: u32) -> Result<()> {
101 let offset = block_id * self.block_size as u64;
102 let size = block_count as usize * self.block_size as usize;
103
104 if buf.len() < size {
105 return Err(Error::InvalidConfig(format!(
106 "buffer too small: need {} bytes, got {}",
107 size,
108 buf.len()
109 )));
110 }
111
112 self.inner.seek(SeekFrom::Start(offset))?;
113 self.inner.read_exact(&mut buf[..size])?;
114 Ok(())
115 }
116
117 fn write_blocks(&mut self, buf: &[u8], block_id: u64, block_count: u32) -> Result<()> {
118 let offset = block_id * self.block_size as u64;
119 let size = block_count as usize * self.block_size as usize;
120
121 if buf.len() < size {
122 return Err(Error::InvalidConfig(format!(
123 "buffer too small: need {} bytes, got {}",
124 size,
125 buf.len()
126 )));
127 }
128
129 self.inner.seek(SeekFrom::Start(offset))?;
130 self.inner.write_all(&buf[..size])?;
131 Ok(())
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use std::io::Cursor;
139
140 #[test]
141 fn test_io_block_device_creation() {
142 let data = vec![0u8; 4096];
143 let cursor = Cursor::new(data);
144 let device = IoBlockDevice::new(cursor, 512, 4096);
145
146 assert_eq!(device.block_size(), 512);
147 assert_eq!(device.block_count(), 8); }
149
150 #[test]
151 fn test_io_block_device_write_read() {
152 let data = vec![0u8; 4096];
153 let cursor = Cursor::new(data);
154 let mut device = IoBlockDevice::new(cursor, 512, 4096);
155
156 let write_buf = vec![0xAB; 512];
158 device.write_blocks(&write_buf, 0, 1).unwrap();
159
160 let mut read_buf = vec![0u8; 512];
162 device.read_blocks(&mut read_buf, 0, 1).unwrap();
163
164 assert_eq!(read_buf, write_buf);
165 }
166
167 #[test]
168 fn test_io_block_device_write_read_multiple_blocks() {
169 let data = vec![0u8; 4096];
170 let cursor = Cursor::new(data);
171 let mut device = IoBlockDevice::new(cursor, 512, 4096);
172
173 let write_buf = vec![0xCD; 1024];
175 device.write_blocks(&write_buf, 2, 2).unwrap();
176
177 let mut read_buf = vec![0u8; 1024];
179 device.read_blocks(&mut read_buf, 2, 2).unwrap();
180
181 assert_eq!(read_buf, write_buf);
182
183 let mut zero_buf = vec![0u8; 512];
185 device.read_blocks(&mut zero_buf, 0, 1).unwrap();
186 assert_eq!(zero_buf, vec![0u8; 512]);
187 }
188
189 #[test]
190 fn test_io_block_device_buffer_too_small() {
191 let data = vec![0u8; 4096];
192 let cursor = Cursor::new(data);
193 let mut device = IoBlockDevice::new(cursor, 512, 4096);
194
195 let mut small_buf = vec![0u8; 512];
197 let result = device.read_blocks(&mut small_buf, 0, 2);
198 assert!(result.is_err());
199
200 let small_write_buf = vec![0u8; 512];
202 let result = device.write_blocks(&small_write_buf, 0, 2);
203 assert!(result.is_err());
204 }
205
206 #[test]
207 fn test_io_block_device_into_inner() {
208 let data = vec![0u8; 1024];
209 let cursor = Cursor::new(data);
210 let device = IoBlockDevice::new(cursor, 512, 1024);
211
212 let recovered = device.into_inner();
213 assert_eq!(recovered.into_inner().len(), 1024);
214 }
215
216 #[test]
217 fn test_block_device_open_close_default() {
218 let data = vec![0u8; 1024];
219 let cursor = Cursor::new(data);
220 let mut device = IoBlockDevice::new(cursor, 512, 1024);
221
222 assert!(device.open().is_ok());
224 assert!(device.close().is_ok());
225 }
226}