vfsi-sync 0.1.14

Synchronous scalar and vectorized filesystem interfaces for VFSI
Documentation
use super::*;

pub fn stat_impl_default<F: VectorBackend + ?Sized>(
    backend: &mut F,
    path: &Path,
) -> VfResult<VfAttrs> {
    let mut a = VfAttrs {
        file: FileOperand::from_os_path(path),
        masks: AttrMask::stat(),
        ..VfAttrs::default()
    };
    backend.vgetattrs_impl(std::slice::from_mut(&mut a))?;
    Ok(a)
}

pub fn lstat_impl_default<F: VectorBackend + ?Sized>(
    backend: &mut F,
    path: &Path,
) -> VfResult<VfAttrs> {
    let mut a = VfAttrs {
        file: FileOperand::from_os_path(path),
        masks: AttrMask::stat(),
        ..VfAttrs::default()
    };
    backend.vgetattrs_nofollow_impl(std::slice::from_mut(&mut a))?;
    Ok(a)
}

pub fn fstat_impl_default<F: VectorBackend + ?Sized>(
    backend: &mut F,
    tcf: &FileOperand,
) -> VfResult<VfAttrs> {
    let mut a = VfAttrs {
        file: tcf.clone(),
        masks: AttrMask::stat(),
        ..VfAttrs::default()
    };
    backend.vgetattrs_impl(std::slice::from_mut(&mut a))?;
    Ok(a)
}

pub fn exists_impl_default<F: VectorBackend + ?Sized>(
    backend: &mut F,
    path: &Path,
) -> VfResult<bool> {
    match backend.lstat_impl(path) {
        Ok(_) => Ok(true),
        Err(e) if e.raw_code() == ERR_NOENT => Ok(false),
        Err(e) => Err(e),
    }
}

pub fn file_type_impl_default<F: VectorBackend + ?Sized>(
    backend: &mut F,
    path: &Path,
) -> VfResult<VfType> {
    Ok(backend.lstat_impl(path)?.ftype)
}

pub fn native_metadata_impl_default<F: VectorBackend + ?Sized>(
    backend: &mut F,
    target: Target<'_, FileOperand>,
    options: vfsi_core::api::AttrsOptions,
) -> VfResult<VfAttrs> {
    let file = match target {
        Target::Path(path) => FileOperand::from_os_path(path),
        Target::File(file) => file.clone(),
    };
    let path = match target {
        Target::Path(path) => Some(path),
        Target::File(file) => file.path(),
    };
    let mut attrs = VfAttrs {
        file,
        masks: options.fields(),
        ..VfAttrs::default()
    };
    let result = if options.follow_final_symlink() {
        backend.vgetattrs_impl(std::slice::from_mut(&mut attrs))
    } else {
        backend.vgetattrs_nofollow_impl(std::slice::from_mut(&mut attrs))
    };
    result.map_err(|error| match path {
        Some(path) => error.with_context("metadata", path),
        None => error,
    })?;
    Ok(attrs)
}

pub fn native_metadata_path_impl_default<F: VectorBackend + ?Sized>(
    backend: &mut F,
    path: &std::path::Path,
    follow: bool,
) -> VfResult<Attrs> {
    native_metadata_impl_default(
        backend,
        Target::Path(path),
        vfsi_core::api::AttrsOptions::new()
            .with_fields(metadata_mask())
            .with_follow_final_symlink(follow),
    )
    .map(vfsi_core::metadata_from_attrs)
}

pub fn native_set_metadata_path_impl_default<F: VectorBackend + ?Sized>(
    backend: &mut F,
    op: &SetAttrsOp<&std::path::Path>,
) -> VfResult<()> {
    let path = *op.target();
    backend
        .set_attributes_impl(&op.with_target(Target::Path(path)))
        .map_err(|error| error.with_context("set_metadata", path))
}

// Wire/raw masks and timestamp tuples are execution details, not a second
// public mutation type. Convert and validate every operation before dispatch.
fn setattrs_to_legacy(op: &SetAttrsOp<Target<'_, FileOperand>>) -> VfResult<VfAttrs> {
    let [accessed, modified] = vfsi_core::internal::validate_setattrs(op)?;
    let mut attrs = VfAttrs {
        file: match op.target() {
            Target::Path(path) => FileOperand::from_os_path(path),
            Target::File(file) => (*file).clone(),
        },
        ..VfAttrs::default()
    };
    if let Some(permissions) = op.requested_permissions() {
        attrs.masks |= AttrMask::MODE;
        attrs.mode = permissions.mode();
    }
    if let Some(uid) = op.requested_uid() {
        attrs.masks |= AttrMask::UID;
        attrs.uid = uid;
    }
    if let Some(gid) = op.requested_gid() {
        attrs.masks |= AttrMask::GID;
        attrs.gid = gid;
    }
    if let Some(size) = op.requested_len() {
        attrs.masks |= AttrMask::SIZE;
        attrs.size = size;
    }
    if let Some(time) = accessed {
        (attrs.atime_sec, attrs.atime_nsec) = time;
        attrs.masks |= AttrMask::ATIME;
    }
    if let Some(time) = modified {
        (attrs.mtime_sec, attrs.mtime_nsec) = time;
        attrs.masks |= AttrMask::MTIME;
    }
    Ok(attrs)
}

pub fn vsetattrs_typed_default<F: VectorBackend + ?Sized>(
    backend: &mut F,
    updates: &[SetAttrsOp<Target<'_, FileOperand>>],
) -> VfResult<()> {
    let attrs = updates
        .iter()
        .enumerate()
        .map(|(index, op)| {
            setattrs_to_legacy(op).map_err(|error| {
                let error = error.with_index(index);
                let path = match op.target() {
                    Target::Path(path) => Some(*path),
                    Target::File(file) => file.path(),
                };
                match path {
                    Some(path) => error.with_context("vsetattrs", path),
                    None => error,
                }
            })
        })
        .collect::<VfResult<Vec<_>>>()?;
    let mut start = 0;
    while start < updates.len() {
        let follow = updates[start].follow_final_symlink();
        let count = updates[start..]
            .iter()
            .take_while(|op| op.follow_final_symlink() == follow)
            .count();
        let result = if follow {
            backend.vsetattrs_raw_impl(&attrs[start..start + count])
        } else {
            backend.vsetattrs_raw_nofollow_impl(&attrs[start..start + count])
        };
        result.map_err(|error| match error.index() {
            Some(index) if index < count => error.with_index(start + index),
            Some(_) => VfError::transport(None, "setattrs backend returned an invalid error index"),
            None => error,
        })?;
        start += count;
    }
    Ok(())
}