file_system/mbr/
utilities.rs

1//! Utility functions for Master Boot Record (MBR) operations.
2
3//!
4//! This module provides high-level utility functions for working with MBR partition tables,
5//! including creating partition devices, scanning for partitions, validation, and disk formatting.
6//! These utilities simplify common MBR operations and provide comprehensive error handling.
7
8use alloc::vec::Vec;
9
10use super::{Error, Mbr, Result};
11use crate::{
12    DirectBlockDevice, PartitionDevice,
13    mbr::{PartitionEntry, PartitionKind},
14};
15
16/// Create a partition device from an MBR partition entry.
17///
18/// This function takes a base device and a partition entry from an MBR, and creates
19/// a [`PartitionDevice`] that represents just that partition. The resulting
20/// partition device can be used for all standard device operations, but will only
21/// access the sectors allocated to that specific partition.
22///
23/// # Arguments
24///
25/// * `Base_device` - The underlying storage device containing the partition
26/// * `Partition` - MBR partition entry describing the partition layout
27///
28/// # Returns
29///
30/// * `Ok(Partition_device_type)` - Successfully created partition device
31/// * `Err(Error::InvalidParameter)` - Partition entry is invalid
32///
33/// # Examples
34///
35/// ```rust
36/// extern crate alloc;
37/// use file_system::{MemoryDevice, mbr::{Mbr, PartitionKind, create_partition_device}};
38///
39/// let device = MemoryDevice::<512>::new(4 * 1024 * 1024);
40/// // First create and write an MBR to the device
41/// let mut mbr = Mbr::new_with_signature(0x12345678);
42/// mbr.add_partition(PartitionKind::Fat32Lba, 2048, 1024, true).unwrap();
43/// mbr.write_to_device(&device).unwrap();
44///
45/// // Now read it back and create partition device
46/// let mbr = Mbr::read_from_device(&device).unwrap();
47/// if let Some(partition) = mbr.get_valid_partitions().first() {
48///     let partition_device = create_partition_device(&device, partition).unwrap();
49///     // Now you can use partition_device for I/O operations
50/// }
51/// ```
52pub fn create_partition_device<'a, D: DirectBlockDevice>(
53    device: &'a D,
54    partition: &PartitionEntry,
55) -> Result<PartitionDevice<'a, D>> {
56    if !partition.is_valid() {
57        return Err(Error::InvalidPartition);
58    }
59
60    device.open()?;
61    let block_size = device.get_block_size()?;
62
63    Ok(PartitionDevice::new(
64        device,
65        partition.start_block as _,
66        partition.block_count as _,
67        block_size,
68    ))
69}
70
71/// Scan a device for MBR and return partition information.
72///
73/// This function reads the MBR from a device and extracts information about all
74/// valid partitions. It returns a vector of tuples containing the partition index
75/// and the partition entry for each valid partition found.
76///
77/// # Arguments
78///
79/// * `Device` - The storage device to scan for MBR partitions
80///
81/// # Returns
82///
83/// * `Ok(Vec<(usize, PartitionEntry)>)` - List of valid partitions with their indices
84/// * `Err(Error)` - Error reading MBR or device access failure
85///
86/// # Examples
87///
88/// ```rust
89/// extern crate alloc;
90/// use file_system::{MemoryDevice, mbr::{Mbr, PartitionKind, scan_mbr_partitions}};
91///
92/// let device = MemoryDevice::<512>::new(4 * 1024 * 1024);
93///
94/// // Create and write an MBR first
95/// let mut mbr = Mbr::new_with_signature(0x12345678);
96/// mbr.add_partition(PartitionKind::Fat32Lba, 2048, 1024, true).unwrap();
97/// mbr.write_to_device(&device).unwrap();
98///
99/// match scan_mbr_partitions(&device) {
100///     Ok(partitions) => {
101///         println!("Found {} valid partitions", partitions.len());
102///         for (index, partition) in partitions {
103///             println!("Partition {}: {:?}", index, partition.kind);
104///         }
105///     }
106///     Err(e) => println!("Failed to scan partitions: {}", e),
107/// }
108/// ```
109pub fn scan_mbr_partitions(
110    device: &impl DirectBlockDevice,
111) -> Result<Vec<(usize, PartitionEntry)>> {
112    let mbr = Mbr::read_from_device(device)?;
113
114    let mut partitions = Vec::new();
115    for (i, partition) in mbr.partitions.iter().enumerate() {
116        if partition.is_valid() {
117            partitions.push((i, *partition));
118        }
119    }
120
121    Ok(partitions)
122}
123
124/// Validate MBR structure and partitions for consistency and correctness.
125///
126/// This function performs comprehensive validation of an MBR structure, checking:
127/// - MBR signature validity (0x55AA boot signature)
128/// - Partition overlap detection
129/// - Bootable partition count (at most one partition should be bootable)
130///
131/// # Arguments
132///
133/// * `Mbr` - The MBR structure to validate
134///
135/// # Returns
136///
137/// * `Ok(())` - MBR is valid and consistent
138/// * `Err(Error::Corrupted)` - MBR is invalid or corrupted
139///
140/// # Examples
141///
142/// ```rust
143/// extern crate alloc;
144/// use file_system::{MemoryDevice, mbr::{Mbr, Error, PartitionKind, validate_mbr}};
145///
146/// let device = MemoryDevice::<512>::new(4 * 1024 * 1024);
147/// // First create and write a valid MBR
148/// let mut mbr = Mbr::new_with_signature(0x12345678);
149/// mbr.add_partition(PartitionKind::Fat32Lba, 2048, 1024, true).unwrap();
150/// mbr.write_to_device(&device).unwrap();
151///
152/// // Read it back and validate
153/// let mbr = Mbr::read_from_device(&device).unwrap();
154/// match validate_mbr(&mbr) {
155///     Ok(()) => println!("MBR is valid"),
156///     Err(e) => println!("Validation error: {}", e),
157/// }
158/// ```
159pub fn validate_mbr(mbr: &Mbr) -> Result<()> {
160    mbr.validate()
161}
162
163/// Create partition devices for all valid partitions in an MBR.
164///
165/// This function iterates through all partition entries in an MBR and creates
166/// [`PartitionDevice`] instances for each valid partition. This is useful
167/// when you need to access all partitions on a disk programmatically.
168///
169/// # Arguments
170///
171/// * `Base_device` - The underlying storage device containing all partitions
172/// * `Mbr` - The MBR structure containing partition information
173///
174/// # Returns
175///
176/// * `Ok(Vec<PartitionDevice>)` - Vector of partition devices for all valid partitions
177/// * `Err(Error)` - Error if any partition device creation fails
178///
179/// # Examples
180///
181/// ```rust
182/// extern crate alloc;
183/// use file_system::{MemoryDevice, mbr::{Mbr, PartitionKind, create_all_partition_devices}};
184///
185/// let device = MemoryDevice::<512>::new(4 * 1024 * 1024);
186/// // Create an MBR with multiple partitions
187/// let mut mbr = Mbr::new_with_signature(0x12345678);
188/// mbr.add_partition(PartitionKind::Fat32Lba, 2048, 1024, true).unwrap();
189/// mbr.add_partition(PartitionKind::Linux, 4096, 2048, false).unwrap();
190/// mbr.write_to_device(&device).unwrap();
191///
192/// // Read it back and create all partition devices
193/// let mbr = Mbr::read_from_device(&device).unwrap();
194/// let partition_devices = create_all_partition_devices(&device, &mbr).unwrap();
195/// println!("Created {} partition devices", partition_devices.len());
196///
197/// for (i, partition) in partition_devices.iter().enumerate() {
198///     println!("Partition {}: {} blocks", i, partition.get_block_count());
199/// }
200/// ```
201pub fn create_all_partition_devices<'a, D: DirectBlockDevice>(
202    base_device: &'a D,
203    mbr: &super::Mbr,
204) -> Result<Vec<PartitionDevice<'a, D>>> {
205    mbr.create_all_partition_devices(base_device)
206}
207
208/// Find partitions of a specific type within an MBR.
209///
210/// This function searches through all partitions in an MBR and returns references
211/// to those that match the specified partition type. This is useful for locating
212/// specific types of partitions (e.g., FAT32, Linux, etc.) without creating
213/// partition devices.
214///
215/// # Arguments
216///
217/// * `Mbr` - The MBR structure to search through
218/// * `Partition_type` - The specific partition type to find
219///
220/// # Returns
221///
222/// A vector of tuples containing the partition index and reference to the partition entry
223/// for each matching partition.
224///
225/// # Examples
226///
227/// ```rust
228/// extern crate alloc;
229/// use file_system::{MemoryDevice, mbr::{Mbr, PartitionKind, find_partitions_by_type}};
230///
231/// let device = MemoryDevice::<512>::new(4 * 1024 * 1024);
232/// // Create an MBR with FAT32 partition
233/// let mut mbr = Mbr::new_with_signature(0x12345678);
234/// mbr.add_partition(PartitionKind::Fat32Lba, 2048, 1024, true).unwrap();
235/// mbr.write_to_device(&device).unwrap();
236///
237/// // Read it back and find FAT32 partitions
238/// let mbr = Mbr::read_from_device(&device).unwrap();
239/// let fat32_partitions = find_partitions_by_type(&mbr, PartitionKind::Fat32Lba);
240/// println!("Found {} FAT32 partitions", fat32_partitions.len());
241/// ```
242pub fn find_partitions_by_type(
243    mbr: &super::Mbr,
244    partition_type: PartitionKind,
245) -> Vec<(usize, &PartitionEntry)> {
246    mbr.find_partitions_by_type(partition_type)
247}
248
249/// Check if a device contains a valid MBR.
250///
251/// This function attempts to read an MBR from the device and validates its signature.
252/// It's a quick way to determine if a device has been properly partitioned with MBR.
253///
254/// # Arguments
255///
256/// * `Device` - The storage device to check
257///
258/// # Returns
259///
260/// * `true` - Device contains a valid MBR with proper signature
261/// * `false` - Device doesn't contain a valid MBR or cannot be read
262///
263/// # Examples
264///
265/// ```rust
266/// extern crate alloc;
267/// use file_system::{MemoryDevice, mbr::{Mbr, has_valid_mbr}};
268///
269/// let device = MemoryDevice::<512>::new(4 * 1024 * 1024);
270///
271/// // Create and write an MBR
272/// let mbr = Mbr::new_with_signature(0x12345678);
273/// mbr.write_to_device(&device).unwrap();
274///
275/// if has_valid_mbr(&device) {
276///     println!("Device has a valid MBR");
277/// } else {
278///     println!("Device needs to be partitioned");
279/// }
280/// ```
281pub fn has_valid_mbr(device: &impl DirectBlockDevice) -> bool {
282    match Mbr::read_from_device(device) {
283        Ok(mbr) => mbr.is_valid(),
284        Err(_) => false,
285    }
286}
287
288/// Check if a device uses GPT (GUID Partition Table) instead of MBR.
289///
290/// This function checks if the device contains a GPT protective partition in its MBR,
291/// which indicates that the device uses GPT partitioning instead of traditional MBR.
292/// GPT is the modern replacement for MBR and supports larger disks and more partitions.
293///
294/// # Arguments
295///
296/// * `Device` - The storage device to check
297///
298/// # Returns
299///
300/// * `true` - Device uses GPT partitioning (has protective MBR)
301/// * `false` - Device uses traditional MBR or cannot be read
302///
303/// # Examples
304///
305/// ```rust
306/// extern crate alloc;
307/// use file_system::{MemoryDevice, mbr::{Mbr, PartitionKind, is_gpt_disk}};
308///
309/// let device = MemoryDevice::<512>::new(4 * 1024 * 1024);
310///
311/// // Create an MBR with GPT protective partition
312/// let mut mbr = Mbr::new_with_signature(0x12345678);
313/// mbr.add_partition(PartitionKind::GptProtective, 1, 0xFFFFFFFF, false).unwrap();
314/// mbr.write_to_device(&device).unwrap();
315///
316/// if is_gpt_disk(&device) {
317///     println!("Device uses GPT partitioning");
318/// } else {
319///     println!("Device uses MBR partitioning");
320/// }
321/// ```
322pub fn is_gpt_disk(device: &impl DirectBlockDevice) -> bool {
323    match Mbr::read_from_device(device) {
324        Ok(mbr) => mbr.has_gpt_protective_partition(),
325        Err(_) => false,
326    }
327}
328
329/// Create a basic MBR with a single partition covering most of the disk.
330///
331/// This function creates a simple MBR structure with one partition that uses
332/// most of the available disk space. It leaves 2048 sectors at the beginning
333/// for proper alignment, which is standard practice for modern storage devices.
334///
335/// # Arguments
336///
337/// * `Disk_signature` - Unique 32-bit signature for the disk
338/// * `Partition_type` - Type of partition to create (e.g., FAT32, Linux, etc.)
339/// * `Total_sectors` - Total number of sectors available on the disk
340///
341/// # Returns
342///
343/// * `Ok(MBR_type)` - Successfully created MBR with single partition
344/// * `Err(Error::InvalidParameter)` - Disk is too small for a partition
345///
346/// # Examples
347///
348/// ```rust
349/// use file_system::mbr::{PartitionKind, create_basic_mbr};
350///
351/// // Create MBR for a 4MB device (8192 sectors)
352/// let mbr = create_basic_mbr(0x12345678, PartitionKind::Fat32Lba, 8192).unwrap();
353///
354/// // The MBR will have one FAT32 partition starting at sector 2048
355/// let partitions = mbr.get_valid_partitions();
356/// assert_eq!(partitions.len(), 1);
357/// assert_eq!(partitions[0].start_block, 2048);
358/// ```
359pub fn create_basic_mbr(
360    disk_signature: u32,
361    partition_type: PartitionKind,
362    total_sectors: u32,
363) -> Result<super::Mbr> {
364    Mbr::create_basic(disk_signature, partition_type, total_sectors)
365}
366
367/// Clone an MBR from one device to another.
368///
369/// This function reads the MBR from a source device, validates it for consistency,
370/// and writes it to a target device. This is useful for creating exact copies of
371/// partition layouts or backing up partition tables.
372///
373/// # Arguments
374///
375/// * `Source_device` - Device to read the MBR from
376/// * `Target_device` - Device to write the MBR to
377///
378/// # Returns
379///
380/// * `Ok(())` - MBR successfully cloned
381/// * `Err(Error)` - Error reading, validating, or writing MBR
382///
383/// # Examples
384///
385/// ```rust
386/// extern crate alloc;
387/// use file_system::{MemoryDevice, mbr::{Mbr, PartitionKind, {clone_mbr, has_valid_mbr}}};
388///
389/// let source = MemoryDevice::<512>::new(4 * 1024 * 1024);
390/// let target = MemoryDevice::<512>::new(4 * 1024 * 1024);
391///
392/// // Create a valid MBR on source device first
393/// let mut mbr = Mbr::new_with_signature(0x12345678);
394/// mbr.add_partition(PartitionKind::Fat32Lba, 2048, 1024, true).unwrap();
395/// mbr.write_to_device(&source).unwrap();
396///
397/// // Now clone the MBR to target
398/// clone_mbr(&source, &target).unwrap();
399///
400/// // Both devices now have valid MBRs
401/// assert_eq!(has_valid_mbr(&source), has_valid_mbr(&target));
402/// ```
403pub fn clone_mbr(
404    source_device: &impl DirectBlockDevice,
405    target_device: &impl DirectBlockDevice,
406) -> Result<()> {
407    let mbr = Mbr::read_from_device(source_device)?;
408    mbr.validate()?;
409    mbr.write_to_device(target_device)?;
410    Ok(())
411}
412
413/// Create a backup of an MBR as a byte array.
414///
415/// This function reads the MBR from a device and returns it as a 512-byte array.
416/// This backup can be stored and later restored using [`restore_mbr`]. This is
417/// essential for disaster recovery and partition table management.
418///
419/// # Arguments
420///
421/// * `Device` - The storage device to backup the MBR from
422///
423/// # Returns
424///
425/// * `Ok([u8; 512])` - 512-byte array containing the complete MBR
426/// * `Err(Error)` - Error reading MBR from device
427///
428/// # Examples
429///
430/// ```rust
431/// extern crate alloc;
432/// use file_system::{MemoryDevice, mbr::{Mbr, PartitionKind, {backup_mbr, restore_mbr}}};
433///
434/// let device = MemoryDevice::<512>::new(4 * 1024 * 1024);
435/// // Create a valid MBR first
436/// let mut mbr = Mbr::new_with_signature(0x12345678);
437/// mbr.add_partition(PartitionKind::Fat32Lba, 2048, 1024, true).unwrap();
438/// mbr.write_to_device(&device).unwrap();
439///
440/// // Create backup
441/// let backup = backup_mbr(&device).unwrap();
442///
443/// // Store backup somewhere safe...
444/// // Later, restore it if needed
445/// restore_mbr(&device, &backup).unwrap();
446/// ```
447pub fn backup_mbr(device: &impl DirectBlockDevice) -> Result<[u8; 512]> {
448    let mbr = Mbr::read_from_device(device)?;
449    Ok(mbr.to_bytes())
450}
451
452/// Restore an MBR from a backup byte array.
453///
454/// This function takes a previously created MBR backup and writes it to a device.
455/// The backup is validated before writing to ensure data integrity. This is the
456/// counterpart to [`backup_mbr`] for disaster recovery scenarios.
457///
458/// # Arguments
459///
460/// * `Device` - The storage device to restore the MBR to
461/// * `Backup` - 512-byte array containing the MBR backup
462///
463/// # Returns
464///
465/// * `Ok(())` - MBR successfully restored
466/// * `Err(Error)` - Error validating backup or writing to device
467///
468/// # Examples
469///
470/// ```rust
471/// extern crate alloc;
472/// use file_system::{MemoryDevice, mbr::{Mbr, PartitionKind, {backup_mbr, restore_mbr, has_valid_mbr}}};
473///
474/// let device = MemoryDevice::<512>::new(4 * 1024 * 1024);
475/// // Create a valid MBR first
476/// let mut mbr = Mbr::new_with_signature(0x12345678);
477/// mbr.add_partition(PartitionKind::Fat32Lba, 2048, 1024, true).unwrap();
478/// mbr.write_to_device(&device).unwrap();
479///
480/// // Create a backup
481/// let backup = backup_mbr(&device).unwrap();
482///
483/// // Simulate corruption or need to restore
484/// restore_mbr(&device, &backup).unwrap();
485///
486/// assert!(has_valid_mbr(&device));
487/// ```
488pub fn restore_mbr(device: &impl DirectBlockDevice, backup: &[u8; 512]) -> Result<()> {
489    let mbr = Mbr::from_bytes(backup)?;
490    mbr.validate()?;
491    mbr.write_to_device(device)?;
492    Ok(())
493}
494
495/// Format disk to MBR if it doesn't contain valid MBR and return first partition device
496///
497/// This function checks if the device contains a valid MBR. If not, it creates a new MBR
498/// with a single partition using the full disk size. It then returns a partition device
499/// for the first partition.
500///
501/// # Arguments
502/// * `Device` - The device to format and get partition from
503/// * `Partition_type` - The type of partition to create if formatting is needed
504/// * `Disk_signature` - The disk signature to use when creating new MBR (optional, uses random if None)
505///
506/// # Returns
507/// * `Result<Partition_device_type>` - The first partition device
508pub fn format_disk_and_get_first_partition<'a, D: DirectBlockDevice>(
509    device: &'a D,
510    partition_type: PartitionKind,
511    disk_signature: Option<u32>,
512) -> Result<PartitionDevice<'a, D>> {
513    // Check if device already has valid MBR
514    let mbr = if has_valid_mbr(device) {
515        // Read existing MBR
516        Mbr::read_from_device(device)?
517    } else {
518        // Get device size in sectors
519        device.open()?;
520        let block_count = device.get_block_count()?;
521        device.close()?;
522
523        if block_count < 2048 {
524            return Err(Error::DeviceTooSmall);
525        }
526
527        // Create new MBR with signature
528        let signature = disk_signature.unwrap_or({
529            // Generate a simple signature based on current time or use a default
530            // In a real implementation, you might want to use a proper random number generator
531            0x12345678
532        });
533
534        let new_mbr = Mbr::create_basic(signature, partition_type, block_count as _)?;
535
536        // Write the new MBR to device
537        new_mbr.write_to_device(device)?;
538
539        new_mbr
540    };
541
542    // Get the first valid partition
543    let valid_partitions = mbr.get_valid_partitions();
544    if valid_partitions.is_empty() {
545        return Err(Error::NoValidPartitions);
546    }
547
548    // Create partition device for the first partition
549    create_partition_device(device, valid_partitions[0])
550}
551
552#[cfg(test)]
553mod tests {
554    use super::*;
555    use crate::{DirectBaseOperations, MemoryDevice, Position, Size, mbr::Error};
556    use alloc::vec;
557
558    /// Create a test device with MBR data
559    fn create_test_device_with_mbr() -> MemoryDevice<512> {
560        let mut data = vec![0u8; 4096 * 1024]; // Make it large enough (4MB = 8192 sectors)
561
562        // Create a simple MBR at the beginning
563        let mbr = create_test_mbr();
564        let mbr_bytes = mbr.to_bytes();
565        data[0..512].copy_from_slice(&mbr_bytes);
566
567        MemoryDevice::<512>::from_vec(data)
568    }
569
570    /// Create a test device without valid MBR
571    fn create_test_device_no_mbr() -> MemoryDevice<512> {
572        MemoryDevice::<512>::new(4096 * 1024)
573    }
574
575    /// Create a test MBR for testing
576    fn create_test_mbr() -> Mbr {
577        let mut mbr = Mbr::new_with_signature(0x12345678);
578
579        // Add a few test partitions
580        let _ = mbr.add_partition(PartitionKind::Fat32Lba, 2048, 1024, true);
581        let _ = mbr.add_partition(PartitionKind::Linux, 4096, 2048, false);
582        let _ = mbr.add_partition(PartitionKind::HiddenFat16, 8192, 512, false);
583
584        mbr
585    }
586
587    #[test]
588    fn test_create_partition_device() {
589        let base_device = create_test_device_with_mbr();
590        let mbr = Mbr::read_from_device(&base_device).unwrap();
591        let entry = &mbr.partitions[0];
592
593        let device_result = create_partition_device(&base_device, entry);
594        assert!(device_result.is_ok());
595
596        let device = device_result.unwrap();
597        assert_eq!(device.get_start_lba(), entry.start_block as Size);
598        assert_eq!(device.get_block_count(), entry.block_count);
599        assert!(device.is_valid());
600    }
601
602    #[test]
603    fn test_create_partition_device_invalid() {
604        let base_device = create_test_device_with_mbr();
605        let invalid_partition = PartitionEntry::new_empty();
606
607        let device_result = create_partition_device(&base_device, &invalid_partition);
608        assert!(device_result.is_err());
609        assert_eq!(device_result.unwrap_err(), Error::InvalidPartition);
610    }
611
612    #[test]
613    fn test_scan_mbr_partitions() {
614        let device = create_test_device_with_mbr();
615
616        let scan_result = scan_mbr_partitions(&device);
617        assert!(scan_result.is_ok());
618
619        let partitions = scan_result.unwrap();
620        assert_eq!(partitions.len(), 3); // Should find 3 valid partitions
621
622        // Check that indices are correct
623        assert_eq!(partitions[0].0, 0);
624        assert_eq!(partitions[1].0, 1);
625        assert_eq!(partitions[2].0, 2);
626
627        // Check partition types
628        assert_eq!(partitions[0].1.kind, PartitionKind::Fat32Lba);
629        assert_eq!(partitions[1].1.kind, PartitionKind::Linux);
630        assert_eq!(partitions[2].1.kind, PartitionKind::HiddenFat16);
631    }
632
633    #[test]
634    fn test_scan_mbr_partitions_no_mbr() {
635        let device = create_test_device_no_mbr();
636
637        let scan_result = scan_mbr_partitions(&device);
638        assert!(scan_result.is_err());
639    }
640
641    #[test]
642    fn test_validate_mbr_valid() {
643        let mbr = create_test_mbr();
644        let validation_result = validate_mbr(&mbr);
645        assert!(validation_result.is_ok());
646    }
647
648    #[test]
649    fn test_validate_mbr_invalid_signature() {
650        let mut mbr = super::Mbr::new();
651        // Manually set invalid signature - should be invalid
652        mbr.boot_signature = [0x00, 0x00];
653
654        let validation_result = validate_mbr(&mbr);
655        assert!(validation_result.is_err());
656        assert_eq!(validation_result.unwrap_err(), Error::InvalidSignature);
657    }
658
659    #[test]
660    fn test_validate_mbr_multiple_bootable() {
661        let mut mbr = Mbr::new_with_signature(0x12345678);
662
663        // Manually create multiple bootable partitions (bypassing Add_partition validation)
664        mbr.partitions[0] =
665            PartitionEntry::new_with_params(true, PartitionKind::Fat32Lba, 2048, 1024);
666        mbr.partitions[1] = PartitionEntry::new_with_params(true, PartitionKind::Linux, 4096, 2048);
667
668        let validation_result = validate_mbr(&mbr);
669        assert!(validation_result.is_err());
670        assert_eq!(
671            validation_result.unwrap_err(),
672            Error::MultipleBootablePartitions
673        );
674    }
675
676    #[test]
677    fn test_validate_mbr_overlapping_partitions() {
678        let mut mbr = Mbr::new_with_signature(0x12345678);
679
680        // Manually create overlapping partitions (bypassing Add_partition validation)
681        mbr.partitions[0] =
682            PartitionEntry::new_with_params(false, PartitionKind::Fat32Lba, 2048, 2048);
683        mbr.partitions[1] =
684            PartitionEntry::new_with_params(false, PartitionKind::Linux, 3000, 2048);
685
686        let validation_result = validate_mbr(&mbr);
687        assert!(validation_result.is_err());
688        assert_eq!(validation_result.unwrap_err(), Error::OverlappingPartitions);
689    }
690
691    #[test]
692    fn test_create_all_partition_devices() {
693        let base_device = create_test_device_with_mbr();
694        let mbr = create_test_mbr();
695
696        let devices_result = create_all_partition_devices(&base_device, &mbr);
697        assert!(devices_result.is_ok());
698
699        let devices = devices_result.unwrap();
700        assert_eq!(devices.len(), 3); // Should create 3 devices
701
702        // Check that all devices are valid
703        for device in &devices {
704            assert!(device.is_valid());
705        }
706
707        // Check first device properties
708        assert_eq!(devices[0].get_start_lba(), Mbr::MINIMUM_START_BLOCK);
709        assert_eq!(devices[0].get_block_count(), 1024);
710    }
711
712    #[test]
713    fn test_find_partitions_by_type() {
714        let mbr = create_test_mbr();
715
716        // Find FAT32 partitions
717        let fat_partitions = find_partitions_by_type(&mbr, PartitionKind::Fat32Lba);
718        assert_eq!(fat_partitions.len(), 1);
719        assert_eq!(fat_partitions[0].0, 0); // Index 0
720
721        // Find Linux partitions
722        let linux_partitions = find_partitions_by_type(&mbr, PartitionKind::Linux);
723        assert_eq!(linux_partitions.len(), 1);
724        assert_eq!(linux_partitions[0].0, 1); // Index 1
725
726        // Find non-existent type
727        let ntfs_partitions = find_partitions_by_type(&mbr, PartitionKind::NtfsExfat);
728        assert_eq!(ntfs_partitions.len(), 0);
729    }
730
731    #[test]
732    fn test_partition_statistics() {
733        let mbr = create_test_mbr();
734        let stats = mbr.get_statistics();
735
736        assert_eq!(stats.total_partitions, 3);
737        assert_eq!(stats.bootable_partitions, 1);
738        assert_eq!(stats.fat_partitions, 2); // Fat32_lba + Hidden_fat16
739        assert_eq!(stats.linux_partitions, 1);
740        assert_eq!(stats.hidden_partitions, 1); // Hidden_fat16
741        assert_eq!(stats.extended_partitions, 0);
742        assert_eq!(stats.unknown_partitions, 0);
743        assert_eq!(stats.total_used_sectors, 1024 + 2048 + 512); // Sum of all partition sizes
744        assert_eq!(stats.largest_partition_sectors, 2048);
745        assert_eq!(stats.smallest_partition_sectors, 512);
746    }
747
748    #[test]
749    fn test_partition_statistics_empty_mbr() {
750        let mbr = Mbr::new_with_signature(0x12345678);
751        let stats = mbr.get_statistics();
752
753        assert_eq!(stats.total_partitions, 0);
754        assert_eq!(stats.bootable_partitions, 0);
755        assert_eq!(stats.fat_partitions, 0);
756        assert_eq!(stats.linux_partitions, 0);
757        assert_eq!(stats.hidden_partitions, 0);
758        assert_eq!(stats.extended_partitions, 0);
759        assert_eq!(stats.unknown_partitions, 0);
760        assert_eq!(stats.total_used_sectors, 0);
761        assert_eq!(stats.largest_partition_sectors, 0);
762        assert_eq!(stats.smallest_partition_sectors, 0);
763    }
764
765    #[test]
766    fn test_has_valid_mbr() {
767        let valid_device = create_test_device_with_mbr();
768        assert!(has_valid_mbr(&valid_device));
769
770        let invalid_device = create_test_device_no_mbr();
771        assert!(!has_valid_mbr(&invalid_device));
772    }
773
774    #[test]
775    fn test_is_gpt_disk() {
776        // Create MBR with GPT protective partition
777        let mut mbr = Mbr::new_with_signature(0x12345678);
778        let _ = mbr.add_partition(PartitionKind::GptProtective, 1, 0xFFFFFFFF, false);
779
780        let mut data = vec![0u8; 4096 * 1024];
781        let mbr_bytes = mbr.to_bytes();
782        data[0..512].copy_from_slice(&mbr_bytes);
783        let memory_device = MemoryDevice::<512>::from_vec(data);
784
785        assert!(is_gpt_disk(&memory_device));
786
787        // Regular MBR should not be detected as GPT
788        let regular_device = create_test_device_with_mbr();
789        assert!(!is_gpt_disk(&regular_device));
790    }
791
792    #[test]
793    fn test_create_basic_mbr() {
794        let mbr_result = create_basic_mbr(0xABCDEF00, PartitionKind::Fat32Lba, 100000);
795        assert!(mbr_result.is_ok());
796
797        let mbr = mbr_result.unwrap();
798        assert!(mbr.is_valid());
799        assert_eq!(mbr.get_disk_signature(), 0xABCDEF00);
800
801        let valid_partitions = mbr.get_valid_partitions();
802        assert_eq!(valid_partitions.len(), 1);
803
804        let partition = &valid_partitions[0];
805        assert_eq!(partition.kind, PartitionKind::Fat32Lba);
806        assert_eq!(partition.start_block, 2048);
807        assert_eq!(partition.block_count, 100000 - 2048);
808        assert!(partition.bootable);
809    }
810
811    #[test]
812    fn test_create_basic_mbr_too_small() {
813        let mbr_result = create_basic_mbr(0x12345678, PartitionKind::Fat32Lba, 1000);
814        assert!(mbr_result.is_err());
815        assert_eq!(mbr_result.unwrap_err(), Error::DeviceTooSmall);
816    }
817
818    #[test]
819    fn test_clone_mbr() {
820        let source_device = create_test_device_with_mbr();
821        let target_data = vec![0u8; 4096 * 1024];
822        let target_device = MemoryDevice::<512>::from_vec(target_data);
823
824        let clone_result = clone_mbr(&source_device, &target_device);
825        assert!(clone_result.is_ok());
826
827        // Verify that target device now has the same MBR
828        let source_mbr = Mbr::read_from_device(&source_device).unwrap();
829        let target_mbr = Mbr::read_from_device(&target_device).unwrap();
830
831        assert_eq!(source_mbr.to_bytes(), target_mbr.to_bytes());
832    }
833
834    #[test]
835    fn test_backup_and_restore_mbr() {
836        let device = create_test_device_with_mbr();
837
838        // Backup MBR
839        let backup_result = backup_mbr(&device);
840        assert!(backup_result.is_ok());
841        let backup = backup_result.unwrap();
842
843        // Create a new device with zeros
844        let target_data = vec![0u8; 4096 * 1024];
845        let memory_device = MemoryDevice::<512>::from_vec(target_data);
846
847        // Restore MBR
848        let restore_result = restore_mbr(&memory_device, &backup);
849        assert!(restore_result.is_ok());
850
851        // Verify restoration
852        let original_mbr = Mbr::read_from_device(&device).unwrap();
853        let restored_mbr = Mbr::read_from_device(&memory_device).unwrap();
854
855        assert_eq!(original_mbr.to_bytes(), restored_mbr.to_bytes());
856    }
857
858    #[test]
859    fn test_backup_mbr_invalid_device() {
860        let invalid_device = create_test_device_no_mbr();
861
862        let backup_result = backup_mbr(&invalid_device);
863        assert!(backup_result.is_err());
864    }
865
866    #[test]
867    fn test_restore_mbr_invalid_backup() {
868        let device = create_test_device_no_mbr();
869        let invalid_backup = [0u8; 512]; // No valid signature
870
871        let restore_result = restore_mbr(&device, &invalid_backup);
872        assert!(restore_result.is_err());
873    }
874
875    #[test]
876    fn test_utilities_with_complex_mbr() {
877        // Create a more complex MBR for comprehensive testing
878        let mut mbr = Mbr::new_with_signature(0xDEADBEEF);
879
880        let _ = mbr.add_partition(PartitionKind::Fat16, 63, 1000, true);
881        let _ = mbr.add_partition(PartitionKind::ExtendedLba, 2048, 10000, false);
882        let _ = mbr.add_partition(PartitionKind::LinuxSwap, 15000, 2000, false);
883        let _ = mbr.add_partition(PartitionKind::Unknown(0x42), 20000, 5000, false);
884
885        // Test statistics
886        let stats = mbr.get_statistics();
887        assert_eq!(stats.total_partitions, 4);
888        assert_eq!(stats.bootable_partitions, 1);
889        assert_eq!(stats.fat_partitions, 1);
890        assert_eq!(stats.linux_partitions, 1); // Linux_swap counts as Linux
891        assert_eq!(stats.extended_partitions, 1);
892        assert_eq!(stats.unknown_partitions, 1);
893
894        // Test finding by type
895        let extended = find_partitions_by_type(&mbr, PartitionKind::ExtendedLba);
896        assert_eq!(extended.len(), 1);
897        assert_eq!(extended[0].0, 1);
898
899        let unknown = find_partitions_by_type(&mbr, PartitionKind::Unknown(0x42));
900        assert_eq!(unknown.len(), 1);
901        assert_eq!(unknown[0].0, 3);
902    }
903
904    #[test]
905    fn test_edge_cases() {
906        // Test with MBR containing only empty partitions
907        let empty_mbr = Mbr::new_with_signature(0x12345678);
908
909        let stats = empty_mbr.get_statistics();
910        assert_eq!(stats.total_partitions, 0);
911
912        let partitions = find_partitions_by_type(&empty_mbr, PartitionKind::Fat32);
913        assert_eq!(partitions.len(), 0);
914
915        // Test scan on empty device
916        let mut empty_data = vec![0u8; 4096 * 1024];
917        let empty_mbr_bytes = empty_mbr.to_bytes();
918        empty_data[0..512].copy_from_slice(&empty_mbr_bytes);
919        let empty_device = MemoryDevice::<512>::from_vec(empty_data);
920
921        let scan_result = scan_mbr_partitions(&empty_device);
922        assert!(scan_result.is_ok());
923        assert_eq!(scan_result.unwrap().len(), 0);
924    }
925
926    // Tests for the new Format_disk_and_get_first_partition function
927
928    #[test]
929    fn test_format_disk_and_get_first_partition_existing_mbr() {
930        let device = create_test_device_with_mbr();
931
932        let partition_device_result =
933            format_disk_and_get_first_partition(&device, PartitionKind::Fat32Lba, Some(0xABCDEF00));
934        assert!(partition_device_result.is_ok());
935
936        let partition_device = partition_device_result.unwrap();
937        assert!(partition_device.is_valid());
938        assert_eq!(partition_device.get_start_lba(), 2048); // First partition starts at 2048
939        assert_eq!(partition_device.get_block_count(), 1024); // First partition size
940    }
941
942    #[test]
943    fn test_format_disk_and_get_first_partition_no_mbr() {
944        let device = create_test_device_no_mbr();
945
946        let partition_device_result =
947            format_disk_and_get_first_partition(&device, PartitionKind::Fat32Lba, Some(0x12345678));
948        assert!(partition_device_result.is_ok());
949
950        let partition_device = partition_device_result.unwrap();
951        assert!(partition_device.is_valid());
952        assert_eq!(partition_device.get_start_lba(), 2048); // Should start at 2048 for alignment
953
954        // Check that MBR was created on device
955        assert!(has_valid_mbr(&device));
956
957        // Verify the MBR has one partition with correct type
958        let mbr = Mbr::read_from_device(&device).unwrap();
959        let valid_partitions = mbr.get_valid_partitions();
960        assert_eq!(valid_partitions.len(), 1);
961        assert_eq!(valid_partitions[0].kind, PartitionKind::Fat32Lba);
962        assert!(valid_partitions[0].bootable);
963    }
964
965    #[test]
966    fn test_format_disk_and_get_first_partition_default_signature() {
967        let device = create_test_device_no_mbr();
968
969        let partition_device_result = format_disk_and_get_first_partition(
970            &device,
971            PartitionKind::Linux,
972            None, // Use default signature
973        );
974        assert!(partition_device_result.is_ok());
975
976        let partition_device = partition_device_result.unwrap();
977        assert!(partition_device.is_valid());
978
979        // Check that MBR was created with default signature
980        let mbr = Mbr::read_from_device(&device).unwrap();
981        assert_eq!(mbr.get_disk_signature(), 0x12345678); // Default signature
982    }
983
984    #[test]
985    fn test_format_disk_and_get_first_partition_device_too_small() {
986        // Create a very small device (less than 2048 sectors)
987        let small_data = vec![0u8; 1024]; // 2 sectors of 512 bytes each
988        let small_device = MemoryDevice::<512>::from_vec(small_data);
989
990        let partition_device_result = format_disk_and_get_first_partition(
991            &small_device,
992            PartitionKind::Fat32Lba,
993            Some(0x12345678),
994        );
995        assert!(partition_device_result.is_err());
996        assert_eq!(partition_device_result.unwrap_err(), Error::DeviceTooSmall);
997    }
998
999    #[test]
1000    fn test_format_disk_and_get_first_partition_empty_mbr() {
1001        // Create device with valid MBR but no partitions
1002        let mut data = vec![0u8; 4096 * 1024];
1003        let empty_mbr = Mbr::new_with_signature(0xDEADBEEF);
1004        let mbr_bytes = empty_mbr.to_bytes();
1005        data[0..512].copy_from_slice(&mbr_bytes);
1006
1007        let memory_device = MemoryDevice::<512>::from_vec(data);
1008        let device = memory_device;
1009
1010        let partition_device_result =
1011            format_disk_and_get_first_partition(&device, PartitionKind::Fat32Lba, Some(0x12345678));
1012        assert!(partition_device_result.is_err());
1013        assert_eq!(
1014            partition_device_result.unwrap_err(),
1015            Error::NoValidPartitions
1016        );
1017    }
1018
1019    #[test]
1020    fn test_format_disk_and_get_first_partition_different_types() {
1021        // Test with different partition types
1022        let partition_types = [
1023            PartitionKind::Fat32Lba,
1024            PartitionKind::Linux,
1025            PartitionKind::NtfsExfat,
1026            PartitionKind::ExtendedLba,
1027        ];
1028
1029        for partition_type in &partition_types {
1030            let device = create_test_device_no_mbr();
1031
1032            let partition_device_result =
1033                format_disk_and_get_first_partition(&device, *partition_type, Some(0xABCDEF00));
1034            assert!(partition_device_result.is_ok());
1035
1036            let partition_device = partition_device_result.unwrap();
1037            assert!(partition_device.is_valid());
1038
1039            // Verify the partition type in MBR
1040            let mbr = Mbr::read_from_device(&device).unwrap();
1041            let valid_partitions = mbr.get_valid_partitions();
1042            assert_eq!(valid_partitions.len(), 1);
1043            assert_eq!(valid_partitions[0].kind, *partition_type);
1044        }
1045    }
1046
1047    #[test]
1048    fn test_format_disk_and_write_read_data() {
1049        let device = create_test_device_no_mbr();
1050
1051        // Format disk and get first partition
1052        let partition_device_result =
1053            format_disk_and_get_first_partition(&device, PartitionKind::Fat32Lba, Some(0x12345678));
1054        assert!(partition_device_result.is_ok());
1055        let partition_device = partition_device_result.unwrap();
1056
1057        // Test 1: Write at position 0 (absolute position within partition)
1058        let test_data = b"Hello, Partition World! This is a test of writing and reading data from a partition device.";
1059        let mut write_buffer = vec![0u8; 512];
1060        write_buffer[0..test_data.len()].copy_from_slice(test_data);
1061
1062        // Write at absolute position 0 within the partition
1063        let write_result = partition_device.write(&write_buffer, 0);
1064        assert!(write_result.is_ok());
1065        let bytes_written = write_result.unwrap();
1066        assert_eq!(bytes_written, 512);
1067
1068        // Read it back from absolute position 0
1069        let mut read_buffer = vec![0u8; 512];
1070        let read_result = partition_device.read(&mut read_buffer, 0);
1071        assert!(read_result.is_ok());
1072        let bytes_read = read_result.unwrap();
1073        assert_eq!(bytes_read, 512);
1074        assert_eq!(&read_buffer[0..test_data.len()], test_data);
1075
1076        // Test 2: Write at a different position (1024 bytes from start)
1077        let second_test_data = b"Second write test at offset";
1078        let second_position = 1024; // Absolute position 1024 within partition
1079        let mut second_write_buffer = vec![0u8; 512];
1080        second_write_buffer[0..second_test_data.len()].copy_from_slice(second_test_data);
1081
1082        // Write at absolute position 1024 within the partition
1083        let write_result = partition_device.write(&second_write_buffer, second_position);
1084        assert!(write_result.is_ok());
1085
1086        // Read back from absolute position 1024
1087        let mut second_read_buffer = vec![0u8; 512];
1088        let read_result = partition_device.read(&mut second_read_buffer, second_position);
1089        assert!(read_result.is_ok());
1090        assert_eq!(
1091            &second_read_buffer[0..second_test_data.len()],
1092            second_test_data
1093        );
1094
1095        // Test 3: Verify first write is still intact at position 0
1096        let mut final_read_buffer = vec![0u8; 512];
1097        let read_result = partition_device.read(&mut final_read_buffer, 0);
1098        assert!(read_result.is_ok());
1099        assert_eq!(&final_read_buffer[0..test_data.len()], test_data);
1100    }
1101
1102    #[test]
1103    fn test_partition_data_isolation() {
1104        // Test that data written to one partition doesn't affect another
1105        let device = create_test_device_no_mbr();
1106
1107        let mut mbr = Mbr::new_with_signature(0x12345678);
1108
1109        // Add two partitions
1110        let first_partition_size = 2048; // 1MB worth of sectors
1111        let second_partition_start = 2048 + first_partition_size;
1112        let second_partition_size = 2048;
1113
1114        let _ = mbr.add_partition(PartitionKind::Fat32Lba, 2048, first_partition_size, true);
1115        let _ = mbr.add_partition(
1116            PartitionKind::Linux,
1117            second_partition_start,
1118            second_partition_size,
1119            false,
1120        );
1121
1122        // Write MBR to device
1123        let write_result = mbr.write_to_device(&device);
1124        assert!(write_result.is_ok());
1125
1126        // Create partition devices
1127        let valid_partitions = mbr.get_valid_partitions();
1128        assert_eq!(valid_partitions.len(), 2);
1129
1130        let first_partition_device = create_partition_device(&device, valid_partitions[0]).unwrap();
1131        let second_partition_device =
1132            create_partition_device(&device, valid_partitions[1]).unwrap();
1133
1134        // Write different data to each partition
1135        let first_data = b"Data for first partition - FAT32";
1136        let second_data = b"Data for second partition - Linux";
1137
1138        let mut first_buffer = vec![0u8; 512];
1139        first_buffer[0..first_data.len()].copy_from_slice(first_data);
1140        let write_result = first_partition_device.write(&first_buffer, 0);
1141        assert!(write_result.is_ok());
1142
1143        let mut second_buffer = vec![0u8; 512];
1144        second_buffer[0..second_data.len()].copy_from_slice(second_data);
1145        let write_result = second_partition_device.write(&second_buffer, 0);
1146        assert!(write_result.is_ok());
1147
1148        // Reset positions and read back
1149        let _ = first_partition_device.set_position(512, &Position::Start(0));
1150        let _ = second_partition_device.set_position(512, &Position::Start(0));
1151
1152        let mut first_read_buffer = vec![0u8; 512];
1153        let mut second_read_buffer = vec![0u8; 512];
1154
1155        let read_result = first_partition_device.read(&mut first_read_buffer, 0);
1156        assert!(read_result.is_ok());
1157        let read_result = second_partition_device.read(&mut second_read_buffer, 0);
1158        assert!(read_result.is_ok());
1159
1160        // Verify each partition has its own data
1161        assert_eq!(&first_read_buffer[0..first_data.len()], first_data);
1162        assert_eq!(&second_read_buffer[0..second_data.len()], second_data);
1163
1164        // Verify the data is different (partitions are isolated)
1165        assert_ne!(&first_read_buffer[0..32], &second_read_buffer[0..32]);
1166    }
1167
1168    #[test]
1169    fn test_partition_bounds_checking() {
1170        let device = create_test_device_no_mbr();
1171
1172        let partition_device_result =
1173            format_disk_and_get_first_partition(&device, PartitionKind::Fat32Lba, Some(0x12345678));
1174        assert!(partition_device_result.is_ok());
1175        let partition_device = partition_device_result.unwrap();
1176
1177        // Try to write beyond partition bounds
1178        let partition_size_bytes = partition_device.get_block_count() as u64 * 512;
1179        let beyond_bounds_position = partition_size_bytes;
1180
1181        let _ = partition_device
1182            .set_position(512, &Position::Start(beyond_bounds_position))
1183            .unwrap_err();
1184        // This should either fail or be clamped to valid range
1185        // The exact behavior depends on the partition device implementation
1186
1187        // Write a small amount of data at the very end of the partition (should work)
1188        let end_position = partition_size_bytes - 512;
1189        let set_position_result =
1190            partition_device.set_position(512, &Position::Start(end_position));
1191        assert!(set_position_result.is_ok());
1192
1193        let test_data = b"End of partition data";
1194        let mut write_buffer = vec![0u8; 512];
1195        write_buffer[0..test_data.len()].copy_from_slice(test_data);
1196
1197        let write_result = partition_device.write(&write_buffer, 0);
1198        assert!(write_result.is_ok());
1199
1200        // Read it back to verify
1201        let set_position_result =
1202            partition_device.set_position(512, &Position::Start(end_position));
1203        assert!(set_position_result.is_ok());
1204        let mut read_buffer = vec![0u8; 512];
1205        let read_result = partition_device.read(&mut read_buffer, 0);
1206        assert!(read_result.is_ok());
1207        assert_eq!(&read_buffer[0..test_data.len()], test_data);
1208    }
1209}