1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

/*
 * Copyright, 2017, Alexander von Gluck IV. All rights reserved.
 * Released under the terms of the MIT license.
 *
 * Authors:
 *   Alexander von Gluck IV <kallisti5@unixzen.com>
 */


use std::fmt;
use std::path::PathBuf;
use std::fs::File;
use std::io::{Read,SeekFrom,Error};
use std::io::prelude::*;
use std::vec::Vec;

// Start +446
#[derive(Debug, Clone)]
pub struct Partition {
	/// Partition Status
	pub p_status: u8,
	/// Start cylinder (Legacy CHS)
	pub p_cyl_begin: u8,
	/// Start head (Legacy CHS)
	pub p_head_begin: u8,
	/// Start sector (Legacy CHS)
	pub p_sect_begin: u8,
	/// Partition Type (DOS, Windows, BeOS, etc)
	pub p_type: u8,
	/// End cylinder (Legacy CHS)
	pub p_cyl_end: u8,
	/// End head (Legacy CHS)
	pub p_head_end: u8,
	/// End sector
	pub p_sect_end: u8,
	/// Logical block address to start of partition
	pub p_lba: u32,
	/// Number of sectors in partition
	pub p_size: u32,
}

fn read1<R: Read>(r: &mut R) -> u8 {
	let mut buf = [0];
	r.read(&mut buf).unwrap();
	buf[0]
}

fn read4<R: Read>(r: &mut R) -> u32 {
	let mut buf = [0, 0, 0, 0];
	r.read(&mut buf).unwrap();
	// TODO: Endian issues on non-x86 platforms? (maybe use byteorder crate?)
	//original: (buf[0] as u32) << 24 | (buf[1] as u32) << 16 | (buf[2] as u32) << 8 | (buf[3] as u32)
	(buf[3] as u32) << 24 | (buf[2] as u32) << 16 | (buf[1] as u32) << 8 | (buf[0] as u32)
}

fn read_partition(path: PathBuf, index: u8) -> Result<Partition, Error> {
	let mut f = File::open(&path.as_path())?;
	assert!(index < 4);

	let position: u64 = 446 + (16 * (index as u64));

	f.seek(SeekFrom::Start(position))?;
	let b = &mut f;

	let new_part = Partition {
		p_status: read1(b),
		p_head_begin: read1(b),
		p_sect_begin: read1(b),
		p_cyl_begin: read1(b),
		p_type: read1(b),
		p_head_end: read1(b),
		p_sect_end: read1(b),
		p_cyl_end: read1(b),
		p_lba: read4(b),
		p_size: read4(b),
	};

	return Ok(new_part);
}

impl fmt::Display for Partition {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let mut part_size = self.p_size;
		if self.p_size > 0 {
			part_size -= 1;
		}
		let end = self.p_lba + part_size;
		write!(f, "Partition. Type: 0x{:X}. Location: {}-{}.", self.p_type, self.p_lba, end)
	}
}

/// Read an mbr partition table from a block device for file.
///
/// let partitions: Result<Vec<Partition>, Error> = read_partitions("/dev/sda");
///
pub fn read_partitions(path: PathBuf) -> Result<Vec<Partition>, Error> {
	let mut partitions: Vec<Partition> = Vec::new();

	for i in [0,1,2,3].iter() {
		partitions.push(read_partition(path.clone(), *i)?);
	}

	return Ok(partitions);
}

/// Dump a partition table to stdout (for debugging)
///
/// table_dump(Vec<Partition>);
///
pub fn table_dump(partitions: Vec<Partition>) {
	for i in partitions.iter() {
		print!("{}\n", i);
	}
}