gpt_partition/
gpt_partition_cursor.rs

1use 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            // Err(Err(io::Error::new(
19            //         io::ErrorKind::InvalidInput,
20            //         format!("{path} is not a block device.", path)
21            //         )))
22            }
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(); // 512
55        let partition_offset = info.bytes_start(block_size).unwrap();
56
57        // file.seek(std::io::SeekFrom::Start(partition_offset))?;
58
59        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    }