wireshift-uring 0.1.1

Native Linux io_uring backend for wireshift
Documentation
#![allow(clippy::unnecessary_wraps)]
use std::ffi::CString;
use std::os::fd::AsRawFd;
use std::os::unix::ffi::OsStrExt;

use io_uring::{opcode, squeue, types};
use wireshift_core::op::OpDescriptor;
use wireshift_core::{Error, Result};

use super::PreparedEntry;
use crate::file_registry::FileRegistryTable;
use crate::helpers::{build_open_flags, has_sequential_hint};
use crate::types::InflightData;

pub(crate) fn build_openat(
    descriptor: &OpDescriptor,
    id: u64,
    _fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::OpenAt {
        dir,
        path,
        flags: open_flags_bits,
        read,
        write,
        create,
        truncate,
    } = descriptor
    else {
        unreachable!()
    };
    let path_cstr = CString::new(path.as_os_str().as_bytes()).map_err(|_| {
        Error::validation(
            "openat path contains an interior NUL byte",
            "pass a path without embedded NUL characters",
        )
    })?;
    let dir_fd = dir.as_ref().map_or(libc::AT_FDCWD, AsRawFd::as_raw_fd);
    let flags = build_open_flags(*open_flags_bits, *read, *write, *create, *truncate)?;
    let mode = if *create { 0o600_u32 } else { 0_u32 };
    let entry = opcode::OpenAt::new(types::Fd(dir_fd), path_cstr.as_ptr())
        .flags(flags)
        .mode(mode)
        .build()
        .user_data(id);
    Ok(vec![PreparedEntry {
        entry,
        pinned: InflightData::Path(path_cstr),
        link_to_next: None,
    }])
}

pub(crate) fn build_openat_direct(
    descriptor: &OpDescriptor,
    id: u64,
    _fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::OpenAtDirect {
        dir,
        path,
        flags: open_flags_bits,
        read,
        write,
        create,
        truncate,
        slot,
    } = descriptor
    else {
        unreachable!()
    };
    let path_cstr = CString::new(path.as_os_str().as_bytes()).map_err(|_| {
        Error::validation(
            "openat path contains an interior NUL byte",
            "pass a path without embedded NUL characters",
        )
    })?;
    let dir_fd = dir.as_ref().map_or(libc::AT_FDCWD, AsRawFd::as_raw_fd);
    let flags = build_open_flags(*open_flags_bits, *read, *write, *create, *truncate)?;
    let mode = if *create { 0o600_u32 } else { 0_u32 };
    let entry = opcode::OpenAt::new(types::Fd(dir_fd), path_cstr.as_ptr())
        .file_index(Some(
            types::DestinationSlot::try_from_slot_target(*slot).map_err(|_| {
                Error::validation(
                    "direct descriptor slot exceeds io_uring's supported range",
                    "reduce the number of concurrent chained reads",
                )
            })?,
        ))
        .flags(flags)
        .mode(mode)
        .build()
        .user_data(id);
    let mut entries = vec![PreparedEntry {
        entry,
        pinned: InflightData::Path(path_cstr),
        link_to_next: None,
    }];
    if has_sequential_hint(*open_flags_bits) {
        entries[0].link_to_next = Some(squeue::Flags::IO_LINK);
        entries.push(PreparedEntry {
            entry: opcode::Fadvise::new(types::Fixed(*slot), 0, libc::POSIX_FADV_SEQUENTIAL)
                .offset(0)
                .build()
                .user_data(id),
            pinned: InflightData::None,
            link_to_next: None,
        });
    }
    Ok(entries)
}

pub(crate) fn build_statx(
    descriptor: &OpDescriptor,
    id: u64,
    _fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::Statx { path } = descriptor else {
        unreachable!()
    };
    let path_cstr = CString::new(path.as_os_str().as_bytes()).map_err(|_| {
        Error::validation(
            "statx path contains an interior NUL byte",
            "pass a path without embedded NUL characters",
        )
    })?;
    // SAFETY: zeroed libc::statx is valid  -  all fields are integer types.
    let statx_buf: Box<libc::statx> = Box::new(unsafe { std::mem::zeroed() });
    let statx_ptr: *mut libc::statx = Box::into_raw(statx_buf);

    let entry = opcode::Statx::new(
        types::Fd(libc::AT_FDCWD),
        path_cstr.as_ptr(),
        statx_ptr.cast::<types::statx>(),
    )
    .flags(libc::AT_STATX_SYNC_AS_STAT)
    .mask(libc::STATX_TYPE | libc::STATX_SIZE)
    .build()
    .user_data(id);

    // SAFETY: statx_ptr was created by Box::into_raw two lines above and has
    // not been freed or aliased. Reconstructing the Box transfers ownership back.
    let statx_buf = unsafe { Box::from_raw(statx_ptr) };

    Ok(vec![PreparedEntry {
        entry,
        pinned: InflightData::Statx {
            path: path_cstr,
            statx_buf,
        },
        link_to_next: None,
    }])
}

pub(crate) fn build_fsync(
    descriptor: &OpDescriptor,
    id: u64,
    fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::Fsync { file } = descriptor else {
        unreachable!()
    };
    let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
        opcode::Fsync::new(types::Fixed(slot))
    } else {
        opcode::Fsync::new(types::Fd(file.as_raw_fd()))
    }
    .build()
    .user_data(id);
    Ok(vec![PreparedEntry {
        entry,
        pinned: InflightData::None,
        link_to_next: None,
    }])
}

pub(crate) fn build_close_fixed(
    descriptor: &OpDescriptor,
    id: u64,
    _fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
    let OpDescriptor::CloseFixed { slot } = descriptor else {
        unreachable!()
    };
    let entry = opcode::Close::new(types::Fixed(*slot))
        .build()
        .user_data(id);
    Ok(vec![PreparedEntry {
        entry,
        pinned: InflightData::None,
        link_to_next: None,
    }])
}