use std::io::Write;
use whyno_core::state::path::PathComponent;
use whyno_core::state::SystemState;
use crate::error::OutputError;
pub fn write_path_walk(state: &SystemState, writer: &mut dyn Write) -> Result<(), OutputError> {
writeln!(writer, "=== Path Walk ===")?;
for (i, comp) in state.walk.iter().enumerate() {
write_component(i, comp, state, writer)?;
}
Ok(())
}
fn write_component(
index: usize,
comp: &PathComponent,
state: &SystemState,
writer: &mut dyn Write,
) -> Result<(), OutputError> {
writeln!(writer, " [{index}] {}", comp.path.display())?;
write_stat_info(comp, writer)?;
write_acl_info(comp, writer)?;
write_flags_info(comp, writer)?;
write_mount_info(comp, state, writer)?;
Ok(())
}
fn write_stat_info(comp: &PathComponent, writer: &mut dyn Write) -> Result<(), OutputError> {
match &comp.stat {
whyno_core::state::Probe::Known(stat) => {
writeln!(
writer,
" stat: mode={:#06o} uid={} gid={} type={:?}",
stat.mode, stat.uid, stat.gid, stat.file_type
)?;
}
whyno_core::state::Probe::Unknown => {
writeln!(writer, " stat: (unknown)")?;
}
whyno_core::state::Probe::Inaccessible => {
writeln!(writer, " stat: (inaccessible)")?;
}
_ => {
writeln!(writer, " stat: (unknown variant)")?;
}
}
Ok(())
}
fn write_acl_info(comp: &PathComponent, writer: &mut dyn Write) -> Result<(), OutputError> {
match &comp.acl {
whyno_core::state::Probe::Known(acl) if !acl.entries().is_empty() => {
writeln!(writer, " acl: {} entries", acl.entries().len())?;
for entry in acl.entries() {
write_acl_entry(entry, writer)?;
}
}
whyno_core::state::Probe::Known(_) => {
writeln!(writer, " acl: (none)")?;
}
whyno_core::state::Probe::Unknown => {
writeln!(writer, " acl: (unknown)")?;
}
whyno_core::state::Probe::Inaccessible => {
writeln!(writer, " acl: (inaccessible)")?;
}
_ => {
writeln!(writer, " acl: (unknown variant)")?;
}
}
Ok(())
}
fn write_acl_entry(
entry: &whyno_core::state::acl::AclEntry,
writer: &mut dyn Write,
) -> Result<(), OutputError> {
writeln!(
writer,
" {:?} q={:?} perms={:?}",
entry.tag, entry.qualifier, entry.perms
)?;
Ok(())
}
fn write_flags_info(comp: &PathComponent, writer: &mut dyn Write) -> Result<(), OutputError> {
match &comp.flags {
whyno_core::state::Probe::Known(flags) => {
writeln!(
writer,
" flags: immutable={} append_only={}",
flags.immutable, flags.append_only
)?;
}
whyno_core::state::Probe::Unknown => {
writeln!(writer, " flags: (unknown)")?;
}
whyno_core::state::Probe::Inaccessible => {
writeln!(writer, " flags: (inaccessible)")?;
}
_ => {
writeln!(writer, " flags: (unknown variant)")?;
}
}
Ok(())
}
fn write_mount_info(
comp: &PathComponent,
state: &SystemState,
writer: &mut dyn Write,
) -> Result<(), OutputError> {
match comp.mount.and_then(|i| state.mounts.0.get(i)) {
Some(entry) => {
writeln!(
writer,
" mount: {} ({}) ro={} noexec={} nosuid={}",
entry.mountpoint.display(),
entry.fs_type,
entry.options.read_only,
entry.options.noexec,
entry.options.nosuid,
)?;
}
None => {
writeln!(writer, " mount: (not resolved)")?;
}
}
Ok(())
}
#[cfg(test)]
#[path = "explain_walk_tests.rs"]
mod tests;