gpt_partition/
gpt_partition_cursor.rs1use gpt;
2use std::{os::unix::fs::FileTypeExt, io::{Seek}};
3
4#[derive(Debug)]
5pub struct GptPartitionCursor {
6 pub file: std::fs::File,
7 partition_offset: u64,
8 pub size: u64,
9 pub pos: u64,
10 pub part_num: u32,
11 }
12
13impl GptPartitionCursor {
14 pub fn new(path: &str, partition_name: &str) -> Result<Self, std::io::Error> {
15 let metadata = std::fs::metadata(path)?;
16 if ! metadata.file_type().is_block_device(){
17 eprintln!("Warning: {} is not a block device.", path);
18 }
23
24 let disk = gpt::GptConfig::new().writable(false).open(path)?;
25 let partitions = disk.partitions();
26
27 let mut partition: Option<&gpt::partition::Partition> = None;
28 let mut part_num = 0u32;
29 for (i, p) in partitions {
30 if partition_name.eq_ignore_ascii_case(&p.name){
31 partition = Some(p);
32 part_num = i.clone();
33 break;
34 }
35 }
36
37 if partition == None {
38 if let Ok(i) = partition_name.parse::<u32>() {
39 partition = partitions.get(&i);
40 }
41 if partition == None {
42 return Err(std::io::Error::new(
43 std::io::ErrorKind::InvalidData,
44 format!("Failed to find specified partition {} in GPT", partition_name),
45 ));
46 }
47 }
48
49 let info = partition.unwrap();
50 let file = std::fs::OpenOptions::new()
51 .read(true)
52 .write(true)
53 .open(path)?;
54 let block_size = *disk.logical_block_size(); let partition_offset = info.bytes_start(block_size).unwrap();
56
57 Ok(Self {
60 file,
61 partition_offset,
62 size: info.bytes_len(block_size).unwrap(),
63 pos: 0,
64 part_num
65 })
66 }
67
68 pub fn part_num(&self) -> u32{
69 return self.part_num;
70 }
71 }
72
73
74impl std::io::Read for GptPartitionCursor {
75 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
76 let bytes_to_read = std::cmp::min(buf.len() as u64, self.size - self.pos);
77 if bytes_to_read == 0 {
78 return Ok(0);
79 }
80 self.file.seek(std::io::SeekFrom::Start(self.partition_offset + self.pos))?;
81 let bytes_read = self.file.read(&mut buf[..bytes_to_read as usize])?;
82 self.pos += bytes_read as u64;
83 Ok(bytes_read)
84 }
85 }
86
87impl std::io::Write for GptPartitionCursor {
88 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
89 let bytes_to_write = std::cmp::min(buf.len() as u64, self.size - self.pos);
90 if bytes_to_write == 0 {
91 return Ok(0);
92 }
93
94 self.file.seek(std::io::SeekFrom::Start(self.partition_offset + self.pos))?;
95 let bytes_written = self.file.write(&buf[..bytes_to_write as usize])?;
96 self.pos += bytes_written as u64;
97 Ok(bytes_written)
98 }
99
100 fn flush(&mut self) -> std::io::Result<()> {
101 self.file.flush()
102 }
103 }
104
105
106impl std::io::Seek for GptPartitionCursor {
107 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
108 match pos {
109 std::io::SeekFrom::Start(new_pos) => {
110 if new_pos <= self.size as u64 {
111 self.pos = new_pos;
112 Ok(new_pos)
113 }
114 else{
115 Err(std::io::Error::new(
116 std::io::ErrorKind::InvalidInput,
117 "Cannot seek past end of data",
118 ))
119 }
120 }
121 std::io::SeekFrom::End(offset) => {
122 if self.pos as i64 + offset <= self.size as i64 {
123 self.pos = (self.size as i64 + offset) as u64;
124 Ok((self.pos) as u64)
125 }
126 else{
127 Err(std::io::Error::new(
128 std::io::ErrorKind::InvalidInput,
129 "Cannot seek past end of data",
130 ))
131 }
132 }
133 std::io::SeekFrom::Current(offset) => {
134 let new_pos = (self.pos as i64 + offset) as usize;
135 if new_pos <= self.size as usize {
136 self.pos = new_pos as u64;
137 Ok((self.pos) as u64)
138 }
139 else{
140 Err(std::io::Error::new(
141 std::io::ErrorKind::InvalidInput,
142 "Cannot seek past end of data",
143 ))
144 }
145 }
146 }
147 }
148 }