confuse 0.1.0

A fuser-compatible filesystem API facade using Dokan on Windows and fuser elsewhere.
Documentation
use winapi::shared::ntstatus::STATUS_NOT_IMPLEMENTED;
use winapi::um::winnt::{
    ACCESS_ALLOWED_ACE_TYPE, ACL_REVISION, FILE_GENERIC_EXECUTE, FILE_GENERIC_READ,
    FILE_GENERIC_WRITE, PSECURITY_DESCRIPTOR, SE_DACL_PRESENT, SE_SELF_RELATIVE,
};

use crate::fuser_facade::filesystem::Filesystem;
use crate::fuser_facade::reply::ReplyAttr;
use crate::fuser_facade::request::Request;
use crate::fuser_facade::types::{FileAttr, FileHandle, INodeNo};

use super::{checked_dokan_len, errno_to_ntstatus, missing_reply_status};

fn push_u16_le(out: &mut Vec<u8>, value: u16) {
    out.extend_from_slice(&value.to_le_bytes());
}

fn push_u32_le(out: &mut Vec<u8>, value: u32) {
    out.extend_from_slice(&value.to_le_bytes());
}

fn unix_sid(kind: u32, id: u32) -> Vec<u8> {
    let mut sid = vec![1, 2, 0, 0, 0, 0, 0, 22];
    push_u32_le(&mut sid, kind);
    push_u32_le(&mut sid, id);
    sid
}

fn world_sid() -> Vec<u8> {
    let mut sid = vec![1, 1, 0, 0, 0, 0, 0, 1];
    push_u32_le(&mut sid, 0);
    sid
}

fn perm_to_file_access(perm: u16, shift: u8) -> u32 {
    let bits = (perm >> shift) & 0o7;
    let mut access = 0;
    if bits & 0o4 != 0 {
        access |= FILE_GENERIC_READ;
    }
    if bits & 0o2 != 0 {
        access |= FILE_GENERIC_WRITE;
    }
    if bits & 0o1 != 0 {
        access |= FILE_GENERIC_EXECUTE;
    }
    access
}

fn push_allow_ace(out: &mut Vec<u8>, access: u32, sid: &[u8]) -> bool {
    if access == 0 {
        return false;
    }
    out.push(ACCESS_ALLOWED_ACE_TYPE);
    out.push(0);
    push_u16_le(out, (8 + sid.len()) as u16);
    push_u32_le(out, access);
    out.extend_from_slice(sid);
    true
}

pub(crate) fn synthesized_security_descriptor(attr: FileAttr) -> Vec<u8> {
    let owner_sid = unix_sid(1, attr.uid);
    let group_sid = unix_sid(2, attr.gid);
    let world_sid = world_sid();

    let mut aces = Vec::new();
    let ace_count = [
        push_allow_ace(&mut aces, perm_to_file_access(attr.perm, 6), &owner_sid),
        push_allow_ace(&mut aces, perm_to_file_access(attr.perm, 3), &group_sid),
        push_allow_ace(&mut aces, perm_to_file_access(attr.perm, 0), &world_sid),
    ]
    .into_iter()
    .filter(|added| *added)
    .count();

    let descriptor_len = 20;
    let owner_offset = descriptor_len;
    let group_offset = owner_offset + owner_sid.len();
    let dacl_offset = group_offset + group_sid.len();
    let acl_len = 8 + aces.len();

    let mut descriptor = Vec::with_capacity(dacl_offset + acl_len);
    descriptor.push(1);
    descriptor.push(0);
    push_u16_le(&mut descriptor, SE_SELF_RELATIVE | SE_DACL_PRESENT);
    push_u32_le(&mut descriptor, owner_offset as u32);
    push_u32_le(&mut descriptor, group_offset as u32);
    push_u32_le(&mut descriptor, 0);
    push_u32_le(&mut descriptor, dacl_offset as u32);
    descriptor.extend_from_slice(&owner_sid);
    descriptor.extend_from_slice(&group_sid);
    descriptor.push(ACL_REVISION);
    descriptor.push(0);
    push_u16_le(&mut descriptor, acl_len as u16);
    push_u16_le(&mut descriptor, ace_count as u16);
    push_u16_le(&mut descriptor, 0);
    descriptor.extend_from_slice(&aces);
    descriptor
}

pub(crate) fn synthesized_security_descriptor_from_fs<FS: Filesystem>(
    fs: &FS, req: &Request, ino: INodeNo, fh: FileHandle,
) -> Result<Vec<u8>, i32> {
    let attr = ReplyAttr::capture();
    fs.getattr(req, ino, Some(fh), attr.duplicate());
    match *attr.status.lock().map_err(|_| STATUS_NOT_IMPLEMENTED)? {
        Some(Ok(attr)) => Ok(synthesized_security_descriptor(attr)),
        Some(Err(err)) => Err(errno_to_ntstatus(err)),
        None => Err(missing_reply_status()),
    }
}

pub(crate) fn copy_security_descriptor(
    data: &[u8], security_descriptor: PSECURITY_DESCRIPTOR, buffer_length: u32,
) -> Result<u32, i32> {
    let needed = checked_dokan_len(data.len())?;
    if buffer_length < needed {
        return Ok(needed);
    }
    if !security_descriptor.is_null() {
        unsafe {
            std::ptr::copy_nonoverlapping(
                data.as_ptr(),
                security_descriptor.cast::<u8>(),
                data.len(),
            );
        }
    }
    Ok(needed)
}

pub(crate) fn xattr_reported_len(data_len: usize, size_hint: Option<u32>) -> Result<u32, i32> {
    size_hint.map_or_else(|| checked_dokan_len(data_len), Ok)
}

pub(crate) fn xattr_needs_data_fetch(data: &[u8], size_hint: Option<u32>) -> Option<u32> {
    if data.is_empty() {
        size_hint.filter(|size| *size > 0)
    } else {
        None
    }
}

pub(crate) fn stream_name_from_xattr(name: &[u8]) -> Option<String> {
    let name = std::str::from_utf8(name).ok()?;
    let stream = name.strip_prefix("user.")?;
    if stream.is_empty() || stream == "dokan.security_descriptor" {
        return None;
    }
    Some(format!(":{stream}:$DATA"))
}

pub(crate) const SECURITY_DESCRIPTOR_XATTR: &str = "user.dokan.security_descriptor";