file_system/devices/
partition_device.rs1use core::fmt;
9
10use shared::AnyByLayout;
11
12use crate::{
13 BaseOperations, ControlCommand, ControlCommandIdentifier, DirectBaseOperations,
14 DirectBlockDevice, Error, MountOperations, Position, Result, Size,
15 block_device::{self, GET_BLOCK_COUNT, GET_BLOCK_SIZE},
16};
17
18pub struct PartitionDevice<'a, D> {
47 base_device: &'a D,
49 block_size: u32,
51 offset: Size,
53 size: Size,
55}
56
57impl<'a, D: BaseOperations> PartitionDevice<'a, D> {
58 pub fn new(base_device: &'a D, start_block: Size, block_count: Size, block_size: u32) -> Self {
78 Self {
79 base_device,
80 block_size,
81 offset: start_block * (block_size as Size),
82 size: block_count * (block_size as Size),
83 }
84 }
85 pub const fn get_block_count(&self) -> u32 {
103 self.size as u32 / self.block_size
104 }
105
106 pub const fn get_start_lba(&self) -> Size {
107 self.offset / (self.block_size as Size)
108 }
109
110 pub const fn get_base_device(&self) -> &D {
112 self.base_device
113 }
114
115 pub const fn is_valid(&self) -> bool {
117 self.size > 0
118 }
119
120 const fn get_device_position(&self, absolute_position: Size) -> Option<Size> {
121 if absolute_position >= self.size {
122 return None;
123 }
124
125 let device_position = match self.offset.checked_add(absolute_position) {
126 Some(pos) => pos,
127 None => return None,
128 };
129
130 Some(device_position)
131 }
132
133 const fn get_total_buffer_length(
134 &self,
135 absolute_position: Size,
136 buffer_length: usize,
137 ) -> usize {
138 let remaining_size = self.size.saturating_sub(absolute_position) as usize;
139
140 if buffer_length > remaining_size {
141 remaining_size
142 } else {
143 buffer_length
144 }
145 }
146}
147
148impl<'a, D: DirectBaseOperations> DirectBaseOperations for PartitionDevice<'a, D> {
149 fn read(&self, buffer: &mut [u8], absolute_position: Size) -> Result<usize> {
150 let device_position = match self.get_device_position(absolute_position) {
151 Some(pos) => pos,
152 None => return Ok(0),
153 };
154
155 let read_size = self.get_total_buffer_length(absolute_position, buffer.len());
156
157 let bytes_read = self
159 .base_device
160 .read(&mut buffer[..read_size], device_position)?;
161
162 Ok(bytes_read)
163 }
164
165 fn write(&self, buffer: &[u8], absolute_position: Size) -> Result<usize> {
166 let device_position = match self.get_device_position(absolute_position) {
167 Some(pos) => pos,
168 None => return Ok(0),
169 };
170
171 let write_size = self.get_total_buffer_length(absolute_position, buffer.len());
172
173 let bytes_written = self
175 .base_device
176 .write(&buffer[..write_size], device_position)?;
177
178 Ok(bytes_written)
179 }
180
181 fn write_pattern(
182 &self,
183 pattern: &[u8],
184 count: usize,
185 absolute_position: Size,
186 ) -> Result<usize> {
187 let device_position = match self.get_device_position(absolute_position) {
188 Some(pos) => pos,
189 None => return Ok(0),
190 };
191
192 let total_write_size = pattern.len() * count;
193 let maximum_write_size = self.get_total_buffer_length(absolute_position, total_write_size);
194
195 let adjusted_count = if total_write_size > maximum_write_size {
196 maximum_write_size / pattern.len()
198 } else {
199 count
200 };
201
202 self.base_device
203 .write_pattern(pattern, adjusted_count, device_position)
204 }
205
206 fn set_position(&self, current_position: Size, position: &Position) -> Result<Size> {
207 let position = block_device::set_position(current_position, position, self.size)?;
208
209 let device_position = self
210 .get_device_position(position)
211 .ok_or(Error::InvalidParameter)?;
212
213 self.base_device
214 .set_position(device_position, &Position::Start(0))?;
215
216 Ok(position)
217 }
218
219 fn flush(&self) -> Result<()> {
220 self.base_device.flush()
221 }
222
223 fn control(
224 &self,
225 command: ControlCommandIdentifier,
226 input: &AnyByLayout,
227 output: &mut AnyByLayout,
228 ) -> Result<()> {
229 match command {
230 GET_BLOCK_SIZE::IDENTIFIER => {
231 let output = GET_BLOCK_SIZE::cast_output(output)?;
232
233 *output = self.block_size;
234 }
235 GET_BLOCK_COUNT::IDENTIFIER => {
236 *output
237 .cast_mutable::<Size>()
238 .ok_or(Error::InvalidParameter)? = self.get_block_count() as Size;
239 }
240 _ => return self.base_device.control(command, input, output),
241 }
242
243 Ok(())
244 }
245}
246
247impl<'a, D: MountOperations> MountOperations for PartitionDevice<'a, D> {}
248
249impl<'a, D: DirectBlockDevice> DirectBlockDevice for PartitionDevice<'a, D> {}
250
251impl<'a, D> fmt::Debug for PartitionDevice<'a, D> {
252 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
253 formatter
254 .debug_struct("PartitionDevice")
255 .field("block_size", &self.block_size)
256 .field("offset", &self.offset)
257 .field("size", &self.size)
258 .finish()
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use alloc::boxed::Box;
265
266 use crate::{MemoryDevice, implement_block_device_tests};
267
268 use super::*;
269
270 implement_block_device_tests!(PartitionDevice::new(
271 Box::leak(Box::new(MemoryDevice::<512>::new(1024 * 1024))),
272 0,
273 1024 * 512,
274 512
275 ));
276}