1use std::{
2 cell::RefCell,
3 fmt::Debug,
4 fs::File,
5 io::{self, Read},
6 path::{Path, PathBuf},
7 str::FromStr,
8};
9use sysfs_class::{Block, SysClass};
10
11pub trait BlockDeviceExt {
15 fn sys_block_path(&self) -> PathBuf { sys_block_path(self.get_device_name(), "") }
17
18 fn is_read_only(&self) -> bool {
20 Block::from_path(&self.sys_block_path())
21 .ok()
22 .map_or(false, |block| block.ro().ok() == Some(1))
23 }
24
25 fn is_removable(&self) -> bool {
30 Block::from_path(&self.sys_block_path())
31 .ok()
32 .map_or(false, |block| block.removable().ok() == Some(1))
33 }
34
35 fn is_rotational(&self) -> bool {
40 Block::from_path(&self.sys_block_path())
41 .ok()
42 .map_or(false, |block| block.queue_rotational().ok() == Some(1))
43 }
44
45 fn get_device_path(&self) -> &Path;
47
48 fn get_mount_point(&self) -> Option<&Path> { None }
50
51 fn get_device_name(&self) -> &str {
53 self.get_device_path()
54 .file_name()
55 .expect("BlockDeviceExt::get_device_path missing file_name")
56 .to_str()
57 .expect("BlockDeviceExt::get_device_path invalid file_name")
58 }
59
60 fn get_sectors(&self) -> u64 {
62 let size_file = sys_block_path(self.get_device_name(), "/size");
63 read_file::<u64>(&size_file).expect("no sector count found")
64 }
65
66 fn get_logical_block_size(&self) -> u64 {
68 let path = sys_block_path(self.get_device_name(), "/queue/logical_block_size");
69 read_file::<u64>(&path).expect("logical block size not found")
70 }
71
72 fn get_physical_block_size(&self) -> u64 {
74 let path = sys_block_path(self.get_device_name(), "/queue/physical_block_size");
75 read_file::<u64>(&path).expect("physical block size not found")
76 }
77}
78
79fn sys_block_path(name: &str, ppath: &str) -> PathBuf {
80 PathBuf::from(["/sys/class/block/", name, ppath].concat())
81}
82
83thread_local! {
84 static BUFFER: RefCell<String> = String::with_capacity(256).into();
85}
86
87fn read_file<T: FromStr>(path: &Path) -> io::Result<T>
88where
89 <T as FromStr>::Err: Debug,
90{
91 BUFFER.with(|buffer| {
92 let mut buffer = buffer.borrow_mut();
93 File::open(path)?.read_to_string(&mut buffer)?;
94 let value = buffer.trim().parse::<T>();
95 buffer.clear();
96 value.map_err(|why| io::Error::new(io::ErrorKind::Other, format!("{:?}", why)))
97 })
98}