1use std::ffi::{c_int, c_uint, c_ushort};
13use std::fs::File;
14use std::io;
15use std::io::Result;
16use std::os::unix::fs::FileTypeExt;
17use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
18
19use nix::{ioctl_none, ioctl_read, ioctl_read_bad, ioctl_write_ptr_bad, request_code_none};
20
21use crate::BlockSize;
22
23ioctl_read_bad! {blksectget, request_code_none!(0x12, 103), c_ushort}
24ioctl_read_bad! {blksszget, request_code_none!(0x12, 104), c_int}
25ioctl_read! {blkbszget, 0x12, 112, c_int}
26ioctl_read! {blkgetsize64, 0x12, 114, u64}
27ioctl_read_bad! {blkiomin, request_code_none!(0x12, 120), c_uint}
28ioctl_read_bad! {blkioopt, request_code_none!(0x12, 121), c_uint}
29ioctl_read_bad! {blkalignoff, request_code_none!(0x12, 122), c_int}
30ioctl_read_bad! {blkpbszget, request_code_none!(0x12, 123), c_uint}
31ioctl_read_bad! {blkdiscardzeroes, request_code_none!(0x12, 124), c_uint}
32ioctl_write_ptr_bad! {blkdiscard, request_code_none!(0x12, 119), [u64; 2]}
33
34ioctl_read_bad! {blkroget, request_code_none!(0x12, 93), c_int}
35ioctl_write_ptr_bad! {blkroset, request_code_none!(0x12, 94), c_int}
36ioctl_none! {blkflsbuf, 0x12, 97}
37
38pub struct BlockDev {
73 inner: File,
76}
77
78impl AsRawFd for BlockDev {
79 fn as_raw_fd(&self) -> RawFd {
80 self.inner.as_raw_fd()
81 }
82}
83
84impl FromRawFd for BlockDev {
85 unsafe fn from_raw_fd(fd: RawFd) -> BlockDev {
86 BlockDev::from_file_raw(File::from_raw_fd(fd))
87 }
88}
89
90impl IntoRawFd for BlockDev {
91 fn into_raw_fd(self) -> RawFd {
92 self.inner.into_raw_fd()
93 }
94}
95
96impl BlockDev {
97 pub unsafe fn from_file_raw(i: File) -> BlockDev {
104 BlockDev { inner: i }
105 }
106
107 pub fn from_file(i: File) -> io::Result<BlockDev> {
108 let m = i.metadata()?;
109 if !m.file_type().is_block_device() {
110 return Err(io::Error::new(
111 io::ErrorKind::InvalidInput,
112 "Not a block device",
113 ));
114 }
115
116 Ok(unsafe { BlockDev::from_file_raw(i) })
117 }
118
119 pub fn ro(&self) -> io::Result<bool> {
120 let mut c: c_int = 0;
121 unsafe { blkroget(self.as_raw_fd(), &mut c) }
122 .map_err(|e| io::Error::from_raw_os_error(e as i32))?;
123
124 Ok(c != 0)
125 }
126
127 pub fn block_io_min(&self) -> Result<u32> {
128 let mut c: c_uint = 0;
129 unsafe { blkiomin(self.as_raw_fd(), &mut c) }
130 .map_err(|e| io::Error::from_raw_os_error(e as i32))?;
131
132 Ok(c)
133 }
134}
135
136impl BlockSize for BlockDev {
137 fn block_size_logical(&self) -> Result<u64> {
138 let mut c: c_int = 0;
139 unsafe { blksszget(self.as_raw_fd(), &mut c) }
140 .map_err(|e| io::Error::from_raw_os_error(e as i32))?;
141
142 Ok(c as u64)
143 }
144
145 fn block_count(&self) -> Result<u64> {
146 let mut c: u64 = 0;
147 unsafe { blkgetsize64(self.as_raw_fd(), &mut c) }
148 .map_err(|e| io::Error::from_raw_os_error(e as i32))?;
149
150 Ok(c)
151 }
152
153 fn block_size_physical(&self) -> Result<u64> {
154 let mut c: c_uint = 0;
155 unsafe { blkpbszget(self.as_raw_fd(), &mut c) }
156 .map_err(|e| io::Error::from_raw_os_error(e as i32))?;
157
158 Ok(c as u64)
159 }
160}