ssh-mcp-rs 3.0.1

MCP server exposing SSH control for Linux systems via Model Context Protocol
Documentation
use std::path::{Path, PathBuf};

use crate::error::{Result, SshMcpError};

use super::TransferCounts;

pub(super) async fn count_dir_no_symlinks(root: &Path) -> Result<TransferCounts> {
    let meta = tokio::fs::symlink_metadata(root).await?;
    if meta.file_type().is_symlink() {
        return Err(SshMcpError::invalid_params(
            "symlinks are not supported by directory transfer",
        ));
    }
    if !meta.is_dir() {
        return Err(SshMcpError::invalid_params("local_path is not a directory"));
    }

    let mut counts = TransferCounts::zero();

    let mut stack: Vec<PathBuf> = vec![root.to_path_buf()];
    while let Some(dir) = stack.pop() {
        let mut rd = tokio::fs::read_dir(&dir).await?;
        while let Some(ent) = rd.next_entry().await? {
            let p = ent.path();
            let m = tokio::fs::symlink_metadata(&p).await?;
            if m.file_type().is_symlink() {
                return Err(SshMcpError::invalid_params(
                    "symlinks are not supported by directory transfer",
                ));
            }
            if m.is_dir() {
                counts.directories += 1;
                stack.push(p);
            } else if m.is_file() {
                counts.files += 1;
                counts.bytes += m.len();
            } else {
                return Err(SshMcpError::invalid_params(
                    "unsupported file type in directory transfer",
                ));
            }
        }
    }

    Ok(counts)
}