file_system/operations/
block_device.rs

1use crate::{
2    BaseOperations, ControlCommand, DirectBaseOperations, Error, MountOperations, Position, Result,
3    Size, define_command,
4};
5use shared::AnyByLayout;
6
7define_command!(GET_BLOCK_SIZE, Read, b'B', 0, (), u32);
8define_command!(GET_BLOCK_COUNT, Read, b'B', 1, (), u32);
9
10pub trait BlockDevice: BaseOperations + MountOperations {}
11
12pub trait DirectBlockDevice: DirectBaseOperations + MountOperations {
13    fn get_block_size(&self) -> Result<u32> {
14        let mut block_size: u32 = 0;
15
16        self.control(
17            GET_BLOCK_SIZE::IDENTIFIER,
18            AnyByLayout::NONE,
19            AnyByLayout::from_mutable(&mut block_size),
20        )?;
21        Ok(block_size)
22    }
23
24    fn get_block_count(&self) -> Result<Size> {
25        let mut total_size: Size = 0;
26
27        self.control(
28            GET_BLOCK_COUNT::IDENTIFIER,
29            AnyByLayout::NONE,
30            AnyByLayout::from_mutable(&mut total_size),
31        )?;
32        Ok(total_size)
33    }
34}
35
36pub fn set_position(current_position: Size, position: &Position, size: Size) -> Result<Size> {
37    let new_position = match position {
38        Position::Start(position) => (*position)
39            .try_into()
40            .map_err(|_| Error::InvalidParameter)?,
41        Position::Current(offset) => (current_position as i64).wrapping_add(*offset),
42        Position::End(offset) => (size as i64).saturating_add(*offset),
43    };
44
45    if new_position < 0 || (new_position as u64) > size {
46        return Err(Error::InvalidParameter);
47    }
48
49    Ok(new_position as Size)
50}
51
52impl<T> BlockDevice for T where T: DirectBlockDevice + MountOperations {}
53
54pub mod tests {
55    use alloc::vec;
56
57    use crate::{Context, Position};
58
59    use super::*;
60
61    /// Generic test for open and close operations.
62    pub fn test_open_and_close<T: BlockDevice>(device: &T) {
63        let mut context = Context::new_empty();
64        device.open(&mut context).unwrap();
65        device.close(&mut context).unwrap();
66    }
67
68    /// Generic test for basic read and write operations.
69    pub fn test_basic_read_write<T: BlockDevice>(device: &T) {
70        let mut context = Context::new_empty();
71
72        let write_data = b"Hello, Context!";
73        let bytes_written = device.write(&mut context, write_data, 0).unwrap();
74        assert_eq!(bytes_written, write_data.len());
75
76        let mut read_buffer = vec![0u8; write_data.len()];
77        let bytes_read = device.read(&mut context, &mut read_buffer, 0).unwrap();
78        assert_eq!(bytes_read, write_data.len());
79        assert_eq!(&read_buffer[..], write_data);
80    }
81
82    /// Generic test for writing at a specific offset.
83    pub fn test_write_at_offset<T: BlockDevice>(device: &T) {
84        let mut context = Context::new_empty();
85
86        let data = b"Xila";
87        let offset = 100;
88        let bytes_written = device.write(&mut context, data, offset).unwrap();
89        assert_eq!(bytes_written, data.len());
90
91        let mut read_buffer = vec![0u8; data.len()];
92        let bytes_read = device.read(&mut context, &mut read_buffer, offset).unwrap();
93        assert_eq!(bytes_read, data.len());
94        assert_eq!(&read_buffer[..], data);
95    }
96
97    /// Generic test for position management.
98    pub fn test_position_management<T: BlockDevice>(device: &T) {
99        let mut context = Context::new_empty();
100
101        let position = 80;
102
103        let position = device
104            .set_position(&mut context, position, &Position::Start(50))
105            .unwrap();
106        assert_eq!(position, 50);
107
108        let position = device
109            .set_position(&mut context, position, &Position::Current(25))
110            .unwrap();
111        assert_eq!(position, 75);
112    }
113
114    /// Generic test for write pattern functionality.
115    pub fn test_write_pattern<T: BlockDevice>(device: &T) {
116        let mut context = Context::new_empty();
117
118        let pattern = b"XY";
119        let pattern_count = 4;
120        let position = 200;
121        let bytes_written = device
122            .write_pattern(&mut context, pattern, pattern_count, position)
123            .unwrap();
124        assert_eq!(bytes_written, pattern.len() * pattern_count);
125
126        let mut read_buffer = vec![0u8; pattern.len() * pattern_count];
127        let bytes_read = device
128            .read(&mut context, &mut read_buffer, position)
129            .unwrap();
130        assert_eq!(bytes_read, pattern.len() * pattern_count);
131        assert_eq!(&read_buffer[..], b"XYXYXYXY");
132    }
133
134    /// Generic test for vectored write operations.
135    pub fn test_write_vectored<T: BlockDevice>(device: &T) {
136        let mut context = Context::new_empty();
137
138        let buffers = [b"Alpha".as_slice(), b"Beta".as_slice()];
139        let position = 300;
140        let total_written = device
141            .write_vectored(&mut context, &buffers, position)
142            .unwrap();
143        assert_eq!(total_written, 9); // 5 + 4
144
145        let mut read_buffer = vec![0u8; 9];
146        let bytes_read = device
147            .read(&mut context, &mut read_buffer, position)
148            .unwrap();
149        assert_eq!(bytes_read, 9);
150        assert_eq!(&read_buffer[..], b"AlphaBeta");
151    }
152
153    /// Generic test for read until delimiter.
154    pub fn test_read_until_delimiter<T: BlockDevice>(device: &T) {
155        let mut context = Context::new_empty();
156
157        let test_data = b"Start|Middle|End";
158        device.write(&mut context, test_data, 400).unwrap();
159
160        let mut read_buffer = vec![0u8; 20];
161        let bytes_read = device
162            .read_until(&mut context, &mut read_buffer, 400, b"|")
163            .unwrap();
164        assert_eq!(&read_buffer[..bytes_read], b"Start|");
165    }
166
167    /// Generic test for flush operation.
168    pub fn test_flush<T: BlockDevice>(device: &T) {
169        let mut context = Context::new_empty();
170        device.flush(&mut context).unwrap();
171    }
172
173    /// Generic test for context cloning.
174    pub fn test_clone_context<T: BlockDevice>(device: &T) {
175        let context = Context::new_empty();
176        let cloned_context = device.clone_context(&context).unwrap();
177        drop(cloned_context);
178    }
179
180    /// Generic test for control command.
181    pub fn test_control_commands<T: BlockDevice>(device: &T) {
182        let mut context = Context::new_empty();
183        let mut block_count: Size = 0;
184        device
185            .control(
186                &mut context,
187                GET_BLOCK_COUNT::IDENTIFIER,
188                AnyByLayout::NONE,
189                AnyByLayout::from_mutable(&mut block_count),
190            )
191            .unwrap();
192
193        assert!(block_count > 0);
194
195        let mut block_size: usize = 0;
196        device
197            .control(
198                &mut context,
199                GET_BLOCK_SIZE::IDENTIFIER,
200                AnyByLayout::NONE,
201                AnyByLayout::from_mutable(&mut block_size),
202            )
203            .unwrap();
204
205        assert!(block_size > 0);
206    }
207
208    /// Generic test for read until boundary conditions.
209    pub fn test_read_until_boundary_conditions<T: BlockDevice>(device: &T) {
210        let mut context = Context::new_empty();
211
212        // Test: delimiter not found
213        let test_data = b"NoDelimiterHere";
214        device.write(&mut context, test_data, 0).unwrap();
215
216        let mut read_buffer = vec![0u8; test_data.len()];
217        let bytes_read = device
218            .read_until(&mut context, &mut read_buffer, 0, b"|")
219            .unwrap();
220        assert_eq!(bytes_read, test_data.len());
221        assert_eq!(&read_buffer[..], test_data);
222
223        // Test: delimiter at start
224        let test_data = b"|Start";
225        device.write(&mut context, test_data, 100).unwrap();
226
227        let mut read_buffer = vec![0u8; 10];
228        let bytes_read = device
229            .read_until(&mut context, &mut read_buffer, 100, b"|")
230            .unwrap();
231        assert_eq!(&read_buffer[..bytes_read], b"|");
232
233        // Test: partial delimiter match followed by different character
234        let test_data = b"ABACD";
235        device.write(&mut context, test_data, 200).unwrap();
236
237        let mut read_buffer = vec![0u8; test_data.len()];
238        let bytes_read = device
239            .read_until(&mut context, &mut read_buffer, 200, b"ABC")
240            .unwrap();
241        assert_eq!(bytes_read, test_data.len());
242        assert_eq!(&read_buffer[..], test_data);
243    }
244
245    /// Generic test for write pattern edge cases.
246    pub fn test_write_pattern_edge_cases<T: BlockDevice>(device: &T) {
247        let mut context = Context::new_empty();
248
249        // Test: zero count
250        let pattern = b"XYZ";
251        let bytes_written = device.write_pattern(&mut context, pattern, 0, 0).unwrap();
252        assert_eq!(bytes_written, 0);
253
254        // Test: single byte pattern
255        let pattern = b"A";
256        let bytes_written = device.write_pattern(&mut context, pattern, 10, 0).unwrap();
257        assert_eq!(bytes_written, 10);
258
259        let mut read_buffer = vec![0u8; 10];
260        device.read(&mut context, &mut read_buffer, 0).unwrap();
261        assert_eq!(&read_buffer[..], b"AAAAAAAAAA");
262    }
263
264    /// Generic test for write vectored edge cases.
265    pub fn test_write_vectored_edge_cases<T: BlockDevice>(device: &T) {
266        let mut context = Context::new_empty();
267
268        // Test: empty buffers array
269        let buffers: [&[u8]; 0] = [];
270        let bytes_written = device.write_vectored(&mut context, &buffers, 0).unwrap();
271        assert_eq!(bytes_written, 0);
272
273        // Test: buffers with empty slices
274        let buffers = [b"First".as_slice(), b"".as_slice(), b"Third".as_slice()];
275        let bytes_written = device.write_vectored(&mut context, &buffers, 0).unwrap();
276        assert_eq!(bytes_written, buffers.into_iter().map(|b| b.len()).sum());
277
278        let mut read_buffer = vec![0u8; 10];
279        device.read(&mut context, &mut read_buffer, 0).unwrap();
280        assert_eq!(&read_buffer[..], b"FirstThird");
281    }
282
283    /// Generic test for position wraparound scenarios.
284    pub fn test_position_wraparound<T: BlockDevice>(device: &T, device_size: Size) {
285        let mut context = Context::new_empty();
286
287        let position = 0;
288        // Set to near end
289        let near_end = device_size.saturating_sub(100);
290        let position = device
291            .set_position(&mut context, position, &Position::Start(near_end))
292            .unwrap();
293        assert_eq!(position, near_end);
294
295        // Move forward from current
296        let position = device
297            .set_position(&mut context, position, &Position::Current(50))
298            .unwrap();
299        assert_eq!(position, near_end + 50);
300
301        // Move backward from current
302        let position = device
303            .set_position(&mut context, position, &Position::Current(-100))
304            .unwrap();
305        assert_eq!(position, near_end.saturating_sub(50));
306
307        // Position from end
308        let position = device
309            .set_position(&mut context, position, &Position::End(-50))
310            .unwrap();
311        assert_eq!(position, device_size - 50);
312
313        // Position exactly at end
314        let position = device
315            .set_position(&mut context, position, &Position::End(0))
316            .unwrap();
317        assert_eq!(position, device_size);
318    }
319
320    /// Generic test for concurrent operations.
321    pub fn test_concurrent_operations<T: BlockDevice + Sync>(device: &T) {
322        let mut context = Context::new_empty();
323        let mut context_clone = Context::new_empty();
324
325        // Write from one context
326        let write_data = b"Concurrent Write Test";
327        device.write(&mut context, write_data, 0).unwrap();
328
329        // Read from another context
330        let mut read_buffer = vec![0u8; write_data.len()];
331        device
332            .read(&mut context_clone, &mut read_buffer, 0)
333            .unwrap();
334        assert_eq!(&read_buffer[..], write_data);
335    }
336
337    /// Generic test for large read/write operations.
338    pub fn test_large_read_write<T: BlockDevice>(device: &T) {
339        let mut context = Context::new_empty();
340
341        // Test with a large buffer
342        let large_data = vec![0x42u8; 4096];
343        let bytes_written = device.write(&mut context, &large_data, 0).unwrap();
344        assert_eq!(bytes_written, large_data.len());
345
346        let mut read_buffer = vec![0u8; 4096];
347        let bytes_read = device.read(&mut context, &mut read_buffer, 0).unwrap();
348        assert_eq!(bytes_read, large_data.len());
349        assert_eq!(read_buffer, large_data);
350    }
351
352    /// Tests for the set_position function.
353    #[cfg(test)]
354    mod set_position_tests {
355        use super::*;
356
357        #[test]
358        fn test_position_start_valid() {
359            let result = set_position(100, &Position::Start(50), 1000);
360            assert_eq!(result.unwrap(), 50);
361        }
362
363        #[test]
364        fn test_position_start_at_zero() {
365            let result = set_position(100, &Position::Start(0), 1000);
366            assert_eq!(result.unwrap(), 0);
367        }
368
369        #[test]
370        fn test_position_start_at_size() {
371            let result = set_position(100, &Position::Start(1000), 1000);
372            assert_eq!(result.unwrap(), 1000);
373        }
374
375        #[test]
376        fn test_position_start_exceeds_size() {
377            let result = set_position(100, &Position::Start(1001), 1000);
378            assert!(result.is_err());
379            assert_eq!(result.unwrap_err(), Error::InvalidParameter);
380        }
381
382        #[test]
383        fn test_position_current_positive_offset() {
384            let result = set_position(100, &Position::Current(50), 1000);
385            assert_eq!(result.unwrap(), 150);
386        }
387
388        #[test]
389        fn test_position_current_negative_offset() {
390            let result = set_position(100, &Position::Current(-50), 1000);
391            assert_eq!(result.unwrap(), 50);
392        }
393
394        #[test]
395        fn test_position_current_zero_offset() {
396            let result = set_position(100, &Position::Current(0), 1000);
397            assert_eq!(result.unwrap(), 100);
398        }
399
400        #[test]
401        fn test_position_current_exceeds_size() {
402            let result = set_position(100, &Position::Current(901), 1000);
403            assert!(result.is_err());
404            assert_eq!(result.unwrap_err(), Error::InvalidParameter);
405        }
406
407        #[test]
408        fn test_position_current_wraps_to_valid() {
409            // Test wraparound behavior
410            let result = set_position(Size::MAX - 50, &Position::Current(100), Size::MAX);
411            assert_eq!(result.unwrap(), Size::MAX.wrapping_add(50));
412        }
413
414        #[test]
415        fn test_position_end_zero_offset() {
416            let result = set_position(100, &Position::End(0), 1000);
417            assert_eq!(result.unwrap(), 1000);
418        }
419
420        #[test]
421        fn test_position_end_negative_offset() {
422            let result = set_position(100, &Position::End(-50), 1000);
423            assert_eq!(result.unwrap(), 950);
424        }
425
426        #[test]
427        fn test_position_end_positive_offset() {
428            let result = set_position(100, &Position::End(10), 1000);
429            assert!(result.is_err());
430            assert_eq!(result.unwrap_err(), Error::InvalidParameter);
431        }
432
433        #[test]
434        fn test_position_end_negative_exceeds_zero() {
435            let result = set_position(100, &Position::End(-1001), 1000);
436            assert!(result.is_err());
437            assert_eq!(result.unwrap_err(), Error::InvalidParameter);
438        }
439
440        #[test]
441        fn test_position_end_exactly_at_start() {
442            let result = set_position(100, &Position::End(-1000), 1000);
443            assert_eq!(result.unwrap(), 0);
444        }
445
446        #[test]
447        fn test_position_boundaries() {
448            // Test at exact boundaries
449            let size = 1000;
450
451            // Start boundary
452            assert_eq!(set_position(0, &Position::Start(0), size).unwrap(), 0);
453            assert_eq!(set_position(0, &Position::Start(size), size).unwrap(), size);
454
455            // End boundary
456            assert_eq!(set_position(0, &Position::End(0), size).unwrap(), size);
457            assert_eq!(
458                set_position(0, &Position::End(-(size as i64)), size).unwrap(),
459                0
460            );
461
462            // Current boundary
463            assert_eq!(set_position(0, &Position::Current(0), size).unwrap(), 0);
464            assert_eq!(
465                set_position(0, &Position::Current(size as i64), size).unwrap(),
466                size
467            );
468        }
469    }
470
471    #[macro_export]
472    macro_rules! implement_block_device_tests {
473        ($device:expr) => {
474            #[test]
475            fn test_open_close() {
476                let device = $device;
477                $crate::block_device::tests::test_open_and_close(&device);
478            }
479
480            #[test]
481            fn test_basic_read_write() {
482                let device = $device;
483                 $crate::block_device::tests::test_basic_read_write(&device);
484            }
485
486            #[test]
487            fn test_write_at_offset() {
488                let device = $device;
489                 $crate::block_device::tests::test_write_at_offset(&device);
490            }
491
492            #[test]
493            fn test_position_management() {
494                let device = $device;
495                 $crate::block_device::tests::test_position_management(&device);
496            }
497
498            #[test]
499            fn test_write_pattern() {
500                let device = $device;
501                 $crate::block_device::tests::test_write_pattern(&device);
502            }
503
504            #[test]
505            fn test_write_vectored() {
506                let device = $device;
507                 $crate::block_device::tests::test_write_vectored(&device);
508            }
509
510            #[test]
511            fn test_read_until_delimiter() {
512                let device = $device;
513                 $crate::block_device::tests::test_read_until_delimiter(&device);
514            }
515
516            #[test]
517            fn test_flush() {
518                let device = $device;
519                 $crate::block_device::tests::test_flush(&device);
520            }
521
522            #[test]
523            fn test_clone_context() {
524                let device = $device;
525                 $crate::block_device::tests::test_clone_context(&device);
526            }
527
528            #[test]
529            fn test_control_commands() {
530                let device = $device;
531                 $crate::block_device::tests::test_control_commands(&device);
532            }
533
534            #[test]
535            fn test_read_until_boundary_conditions() {
536                let device = $device;
537                 $crate::block_device::tests::test_read_until_boundary_conditions(&device);
538            }
539
540            #[test]
541            fn test_write_pattern_edge_cases() {
542                let device = $device;
543                 $crate::block_device::tests::test_write_pattern_edge_cases(&device);
544            }
545
546            #[test]
547            fn test_write_vectored_edge_cases() {
548                let device = $device;
549                 $crate::block_device::tests::test_write_vectored_edge_cases(&device);
550            }
551
552            #[test]
553            fn test_concurrent_operations() {
554                let device = $device;
555                 $crate::block_device::tests::test_concurrent_operations(&device);
556            }
557
558            #[test]
559            fn test_large_read_write() {
560                let device = $device;
561                 $crate::block_device::tests::test_large_read_write(&device);
562            }
563        };
564        (
565            instance: $device:expr,
566            size: $size:expr
567        ) => {
568            implement!(instance: $device);
569
570            #[test]
571            fn test_position_wraparound() {
572                let device = $device;
573                test_position_wraparound(&device, $size);
574            }
575        };
576    }
577}