use nix::{libc::c_int, Result as NixResult};
use std::{fs::File, os::unix::prelude::*};
type Result = NixResult<c_int>;
mod _impl {
use nix::{
libc::{c_char, c_int, c_longlong, c_void},
*,
};
#[repr(C)]
pub struct BlockPageIoctlArgs {
op: c_int,
flags: c_int,
data_len: c_int,
data: *mut c_void,
}
impl BlockPageIoctlArgs {
pub fn new(op: i32, data: &mut BlockPagePartArgs) -> Self {
BlockPageIoctlArgs {
op,
flags: 0,
data_len: std::mem::size_of::<BlockPagePartArgs>() as i32,
data: data as *mut _ as *mut _,
}
}
}
#[repr(C)]
pub struct BlockPagePartArgs {
start: c_longlong,
length: c_longlong,
part_num: c_int,
dev_name: [c_char; 64],
vol_name: [c_char; 64],
}
impl BlockPagePartArgs {
pub fn new(part_num: i32, start: i64, end: i64) -> Self {
let length = end - start;
BlockPagePartArgs {
start,
length,
part_num,
dev_name: [0; 64],
vol_name: [0; 64],
}
}
}
ioctl_write_ptr_bad!(
block_page,
0x1269,
super::BlockPageIoctlArgs
);
ioctl_none! {
block_reread_part,
0x12,
95
}
}
#[doc(inline)]
use _impl::{BlockPageIoctlArgs, BlockPagePartArgs};
const BLOCK_ADD_PART: i32 = 1;
const BLOCK_DEL_PART: i32 = 2;
pub fn add_partition(fd: &File, part: i32, start: i64, end: i64) -> Result {
assert!(
fd.metadata().unwrap().file_type().is_block_device(),
"File {:?} was not a block device",
fd,
);
assert!(part >= 65536, "Invalid partition number: {}", part);
let mut part = BlockPagePartArgs::new(part, start, end);
let args = BlockPageIoctlArgs::new(BLOCK_ADD_PART, &mut part);
unsafe { _impl::block_page(fd.as_raw_fd(), &args) }
}
pub fn remove_partition(fd: &File, part: i32) -> Result {
assert!(
fd.metadata().unwrap().file_type().is_block_device(),
"File {:?} was not a block device",
fd,
);
let mut part = BlockPagePartArgs::new(part, 0, 0);
let args = BlockPageIoctlArgs::new(BLOCK_DEL_PART, &mut part);
unsafe { _impl::block_page(fd.as_raw_fd(), &args) }
}
pub fn remove_existing_partitions(fd: &File) -> Result {
for i in 1..=64 {
match remove_partition(fd, i) {
Ok(_) => (),
Err(nix::Error::Sys(nix::errno::Errno::ENXIO)) => (),
e @ Err(_) => return e,
}
}
Ok(0)
}
#[deprecated = "BLKRRPART has been superseded by BLKPG"]
pub fn reread_partitions(fd: &File) -> Result {
assert!(
fd.metadata().unwrap().file_type().is_block_device(),
"File {:?} was not a block device",
fd,
);
unsafe { _impl::block_reread_part(fd.as_raw_fd()) }
}