use crate::illumos;
use crate::illumos::door_h::door_desc_t;
use crate::illumos::fattach;
use crate::illumos::DoorAttributes;
use crate::illumos::DoorFd;
use libc;
use std::ffi;
use std::fs::File;
use std::io;
use std::os::fd::RawFd;
use std::path::Path;
#[derive(Debug)]
pub enum Error {
InvalidPath(ffi::NulError),
InstallJamb(std::io::Error),
AttachDoor(illumos::Error),
OpenDoor(std::io::Error),
DoorCall(libc::c_int),
CreateDoor(illumos::Error),
}
pub struct Door(RawFd);
impl Door {
pub fn create(sp: illumos::ServerProcedure) -> Result<Self, Error> {
let cookie = 0;
let attrs = DoorAttributes::none();
Self::create_with_cookie_and_attributes(sp, cookie, attrs)
}
pub fn create_with_cookie(
sp: illumos::ServerProcedure,
cookie: u64,
) -> Result<Self, Error> {
let attrs = DoorAttributes::none();
Self::create_with_cookie_and_attributes(sp, cookie, attrs)
}
pub fn create_with_attributes(
sp: illumos::ServerProcedure,
attrs: DoorAttributes,
) -> Result<Self, Error> {
let cookie = 0;
Self::create_with_cookie_and_attributes(sp, cookie, attrs)
}
pub fn create_with_cookie_and_attributes(
sp: illumos::ServerProcedure,
cookie: u64,
attrs: illumos::DoorAttributes,
) -> Result<Self, Error> {
match illumos::door_create(sp, cookie, attrs) {
Ok(fd) => Ok(Self(fd as RawFd)),
Err(e) => Err(Error::CreateDoor(e)),
}
}
pub fn install<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
let _jamb = match create_new_file(&path) {
Ok(file) => file,
Err(e) => return Err(Error::InstallJamb(e)),
};
match fattach(self.0, &path) {
Err(e) => {
std::fs::remove_file(&path).ok();
Err(Error::AttachDoor(e))
}
Ok(()) => Ok(()),
}
}
pub fn force_install<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
if path.as_ref().exists() {
if let Err(e) = std::fs::remove_file(&path) {
return Err(Error::InstallJamb(e));
}
}
self.install(path)
}
}
impl Drop for Door {
fn drop(&mut self) {
unsafe {
illumos::door_h::door_revoke(self.0);
}
}
}
#[derive(Copy, Clone)]
pub struct Request<'a> {
pub cookie: u64,
pub data: &'a [u8],
pub descriptors: &'a [door_desc_t],
}
pub struct Response<C: AsRef<[u8]>> {
pub data: Option<C>,
pub num_descriptors: u32,
pub descriptors: [DoorFd; 2],
}
impl<C: AsRef<[u8]>> Response<C> {
pub fn new(data: C) -> Self {
let descriptors = [DoorFd::new(-1, true), DoorFd::new(-1, true)];
let num_descriptors = 0;
Self {
data: Some(data),
descriptors,
num_descriptors,
}
}
pub fn empty() -> Self {
let data = None;
let descriptors = [DoorFd::new(-1, true), DoorFd::new(-1, true)];
let num_descriptors = 0;
Self {
data,
descriptors,
num_descriptors,
}
}
pub fn add_descriptor(mut self, fd: RawFd, release: bool) -> Self {
if self.num_descriptors == 2 {
panic!("Only 2 descriptors are supported")
}
let desc = DoorFd::new(fd, release);
self.descriptors[self.num_descriptors as usize] = desc;
self.num_descriptors += 1;
self
}
}
fn create_new_file<P: AsRef<Path>>(path: P) -> io::Result<File> {
File::options()
.read(true)
.write(true)
.create_new(true)
.open(path)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn create_new_fails_if_file_exists() {
match File::create("/tmp/create_new_fail.txt") {
Err(e) => {
eprintln!("{:?}", e);
assert!(true)
}
Ok(_file) => {
create_new_file("/tmp/create_new_fail.txt").unwrap();
}
}
}
}