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
#![cfg(target_os = "linux")]
use std::fs;
use std::io;
use std::os::linux::fs::MetadataExt;
use std::os::unix::io::AsRawFd;
mod ioctl {
ioctl_read_bad!(blksszget, 0x1268, u64);
ioctl_none!(blkrrpart, 0x12, 95);
}
const S_IFMT: u32 = 0o170_000;
const S_IFBLK: u32 = 0o60_000;
#[derive(Debug, Error)]
pub enum BlockError {
#[error(display = "failed to get metadata of device fd")]
Metadata(#[error(cause)] io::Error),
#[error(display = "failed to reload partition table of device")]
RereadTable(#[error(cause)] nix::Error),
#[error(display = "failed to get the sector size of device")]
GetSectorSize(#[error(cause, no_from)] nix::Error),
#[error(display = "invalid return value of ioctl ({} != 0)", _0)]
InvalidReturnValue(i32),
#[error(display = "not a block device")]
NotBlock,
}
pub fn reread_partition_table(file: &mut fs::File) -> Result<(), BlockError> {
let metadata = file.metadata().map_err(BlockError::Metadata)?;
if metadata.st_mode() & S_IFMT == S_IFBLK {
match unsafe { ioctl::blkrrpart(file.as_raw_fd()) } {
Err(err) => Err(BlockError::RereadTable(err)),
Ok(0) => Ok(()),
Ok(r) => Err(BlockError::InvalidReturnValue(r)),
}
} else {
Err(BlockError::NotBlock)
}
}
pub fn get_sector_size(file: &mut fs::File) -> Result<u64, BlockError> {
let metadata = file.metadata().map_err(BlockError::Metadata)?;
let mut sector_size = 512;
if metadata.st_mode() & S_IFMT == S_IFBLK {
match unsafe { ioctl::blksszget(file.as_raw_fd(), &mut sector_size) } {
Err(err) => Err(BlockError::GetSectorSize(err)),
Ok(0) => Ok(sector_size),
Ok(r) => Err(BlockError::InvalidReturnValue(r)),
}
} else {
Err(BlockError::NotBlock)
}
}