use super::utils::cstr;
use crate::fs::UringOpenOptions;
use crate::runtime::driver::op::{CancelData, Cancellable, Completable, CqeResult, Op};
use io_uring::{opcode, types};
use std::ffi::CString;
use std::io::{self, Error};
use std::os::fd::FromRawFd;
use std::path::Path;
#[derive(Debug)]
pub(crate) struct Open {
#[allow(dead_code)]
path: CString,
}
#[derive(Debug)]
pub(crate) enum OpenError {
Submission(io::Error),
Completion(io::Error),
}
impl Completable for Open {
type Output = Result<crate::fs::File, OpenError>;
fn complete(self, cqe: CqeResult) -> Self::Output {
cqe.result
.map(|fd| unsafe { crate::fs::File::from_raw_fd(fd as i32) })
.map_err(OpenError::Completion)
}
fn complete_with_error(self, err: Error) -> Self::Output {
Err(OpenError::Submission(err))
}
fn complete_after_cancel(err: Error) -> Self::Output {
Err(OpenError::Submission(err))
}
}
impl Cancellable for Open {
fn cancel(self) -> CancelData {
CancelData::Open(self)
}
}
impl Op<Open> {
pub(crate) fn open(path: &Path, options: &UringOpenOptions) -> io::Result<Op<Open>> {
let inner_opt = options;
let path = cstr(path)?;
let custom_flags = inner_opt.custom_flags;
let flags = libc::O_CLOEXEC
| options.access_mode()?
| options.creation_mode()?
| (custom_flags & !libc::O_ACCMODE);
let open_op = opcode::OpenAt::new(types::Fd(libc::AT_FDCWD), path.as_ptr())
.flags(flags)
.mode(inner_opt.mode)
.build();
let op = unsafe { Op::new(open_op, Open { path }) };
Ok(op)
}
}
pub(crate) async fn open(path: &Path, options: &UringOpenOptions) -> io::Result<crate::fs::File> {
loop {
match Op::open(path, options)?.await {
Ok(file) => return Ok(file),
Err(OpenError::Completion(e)) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(OpenError::Completion(e) | OpenError::Submission(e)) => return Err(e),
}
}
}