use super::Op;
use crate::{
buf::IoBuf,
future::Future,
};
pub struct Openat<B: IoBuf> {
dir: lx::RawFd,
path: B,
flags: u32,
mode: u32,
}
unsafe impl<B: IoBuf> Op for Openat<B> {
type Output = lx::Result<lx::OwnedFd>;
fn fill_sqe(&mut self, sqe: &mut lx::io_uring_sqe) {
sqe.opcode = lx::IORING_OP_OPENAT;
sqe.fd = self.dir;
sqe.op_flags = self.flags;
sqe.addr = self.path.as_ref().as_ptr() as u64;
sqe.len = self.mode;
}
fn complete(self, ret: i32) -> Self::Output {
if let Ok(err) = lx::Error::try_from(ret) {
Err(err)
} else {
Ok(lx::OwnedFd::new(ret))
}
}
}
pub unsafe fn openat_unchecked<B: IoBuf>(
dir: &impl lx::AsRawFd,
path: B,
flags: u32,
mode: u32,
) -> Future<Openat<B>> {
Future::new(Openat {
dir: dir.as_raw_fd(),
path,
flags,
mode,
})
}
pub fn openat<B: IoBuf>(
dir: &impl lx::AsRawFd,
path: B,
flags: u32,
mode: u32,
) -> Future<Openat<B>> {
if path.as_ref().last().copied() != Some(0) {
panic!("path must be null-terminated");
}
unsafe { openat_unchecked(dir, path, flags, mode) }
}
pub fn open<B: IoBuf>(path: B, flags: u32, mode: u32) -> Future<Openat<B>> {
openat(&lx::AT_FDCWD, path, flags, mode)
}
#[cfg(test)]
mod tests {
#[test]
fn open() {
crate::spawn(async {
super::open(b"/dev/zero\0", lx::O_RDONLY, 0).await.unwrap();
});
crate::run().unwrap();
}
}