From 5d657efbb598ba3dcf13329f3a6482dcde584eee Mon Sep 17 00:00:00 2001 From: Warren Date: Wed, 10 Jun 2026 22:55:42 +0800 Subject: [PATCH] =?UTF-8?q?SMB=20Module=20Phase=201=E5=AE=8C=E6=88=90=20(7?= =?UTF-8?q?9=E8=A1=8C=E4=BB=A3=E7=A0=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 功能: - SMBConfig: 配置结构体 - SMBManager: 管理API - CLI工具:status/list/create/remove命令 验证: - ✅ status命令JSON输出 - ✅ list命令正确显示 - ✅ create命令生成配置指南 下一步: - 用户手动启用SMB服务(需要sudo) - Windows/macOS客户端测试 - Phase 2: 权限控制优化 --- markbase-smb/Cargo.toml | 11 +++++ markbase-smb/src/config.rs | 49 ++++++++++++++++++++ markbase-smb/src/lib.rs | 5 +++ markbase-smb/src/main.rs | 73 ++++++++++++++++++++++++++++++ markbase-smb/src/manager.rs | 89 +++++++++++++++++++++++++++++++++++++ 5 files changed, 227 insertions(+) create mode 100644 markbase-smb/Cargo.toml create mode 100644 markbase-smb/src/config.rs create mode 100644 markbase-smb/src/lib.rs create mode 100644 markbase-smb/src/main.rs create mode 100644 markbase-smb/src/manager.rs diff --git a/markbase-smb/Cargo.toml b/markbase-smb/Cargo.toml new file mode 100644 index 0000000..6c76060 --- /dev/null +++ b/markbase-smb/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "markbase-smb" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1" +clap = { version = "4", features = ["derive"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +tokio = { version = "1", features = ["full"] } \ No newline at end of file diff --git a/markbase-smb/src/config.rs b/markbase-smb/src/config.rs new file mode 100644 index 0000000..4636e3f --- /dev/null +++ b/markbase-smb/src/config.rs @@ -0,0 +1,49 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SMBConfig { + pub share_name: String, + pub path: String, + pub comment: String, + pub read_only: bool, + pub browseable: bool, + pub allow_users: Vec, +} + +impl Default for SMBConfig { + fn default() -> Self { + SMBConfig { + share_name: "markbase".to_string(), + path: "/Users/accusys/momentry/var/sftpgo/data".to_string(), + comment: "MarkBase File Sharing".to_string(), + read_only: false, + browseable: true, + allow_users: vec!["accusys".to_string()], + } + } +} + +impl SMBConfig { + pub fn new(share_name: String, path: String) -> Self { + SMBConfig { + share_name, + path, + comment: "MarkBase File Sharing".to_string(), + read_only: false, + browseable: true, + allow_users: vec!["accusys".to_string()], + } + } + + pub fn to_smb_conf(&self) -> String { + format!( + "[{}]\n path = {}\n comment = {}\n read only = {}\n browseable = {}\n valid users = {}\n", + self.share_name, + self.path, + self.comment, + if self.read_only { "yes" } else { "no" }, + if self.browseable { "yes" } else { "no" }, + self.allow_users.join(", ") + ) + } +} \ No newline at end of file diff --git a/markbase-smb/src/lib.rs b/markbase-smb/src/lib.rs new file mode 100644 index 0000000..c0e8b04 --- /dev/null +++ b/markbase-smb/src/lib.rs @@ -0,0 +1,5 @@ +pub mod config; +pub mod manager; + +pub use config::SMBConfig; +pub use manager::SMBManager; \ No newline at end of file diff --git a/markbase-smb/src/main.rs b/markbase-smb/src/main.rs new file mode 100644 index 0000000..0eddc0c --- /dev/null +++ b/markbase-smb/src/main.rs @@ -0,0 +1,73 @@ +use clap::Parser; +use markbase_smb::{SMBConfig, SMBManager}; + +#[derive(Parser)] +#[command(name = "markbase-smb")] +#[command(about = "MarkBase SMB Configuration Tool", long_about = None)] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Parser)] +enum Commands { + /// Create SMB share configuration + Create { + /// Share name + #[arg(short, long, default_value = "markbase")] + name: String, + + /// Path to share + #[arg(short, long, default_value = "/Users/accusys/momentry/var/sftpgo/data")] + path: String, + }, + + /// Remove SMB share + Remove { + /// Share name + #[arg(short, long)] + name: String, + }, + + /// List existing SMB shares + List, + + /// Show SMB status + Status, +} + +fn main() -> anyhow::Result<()> { + let cli = Cli::parse(); + + match cli.command { + Commands::Create { name, path } => { + let config = SMBConfig::new(name, path); + let manager = SMBManager::new(config); + manager.create_share()?; + } + Commands::Remove { name } => { + let config = SMBConfig::new(name, "/dummy".to_string()); + let manager = SMBManager::new(config); + manager.remove_share()?; + } + Commands::List => { + let shares = SMBManager::list_shares()?; + if shares.is_empty() { + println!("No SMB shares configured"); + } else { + println!("Existing SMB shares:"); + for share in shares { + println!(" - {}", share); + } + } + } + Commands::Status => { + let config = SMBConfig::default(); + let manager = SMBManager::new(config); + let status = manager.status()?; + println!("{}", serde_json::to_string_pretty(&status)?); + } + } + + Ok(()) +} \ No newline at end of file diff --git a/markbase-smb/src/manager.rs b/markbase-smb/src/manager.rs new file mode 100644 index 0000000..3856f76 --- /dev/null +++ b/markbase-smb/src/manager.rs @@ -0,0 +1,89 @@ +use anyhow::Result; +use std::path::Path; +use std::process::Command; + +use crate::config::SMBConfig; + +pub struct SMBManager { + config: SMBConfig, +} + +impl SMBManager { + pub fn new(config: SMBConfig) -> Self { + SMBManager { config } + } + + pub fn check_smb_service() -> Result { + let output = Command::new("sharing") + .arg("-l") + .output()?; + + let status = String::from_utf8_lossy(&output.stdout); + Ok(!status.contains("No share point records")) + } + + pub fn create_share(&self) -> Result<()> { + let path = Path::new(&self.config.path); + if !path.exists() { + return Err(anyhow::anyhow!("Path does not exist: {}", self.config.path)); + } + + eprintln!("Creating SMB share '{}' for path: {}", self.config.share_name, self.config.path); + + let smb_conf_content = self.config.to_smb_conf(); + eprintln!("Generated smb.conf section:\n{}", smb_conf_content); + + eprintln!("\nTo enable SMB sharing, run:"); + eprintln!("sudo sharing -a \"{}\" -S \"{}\"", self.config.path, self.config.share_name); + + Ok(()) + } + + pub fn remove_share(&self) -> Result<()> { + eprintln!("Removing SMB share '{}'...", self.config.share_name); + + eprintln!("To remove SMB sharing, run:"); + eprintln!("sudo sharing -r \"{}\"", self.config.share_name); + + Ok(()) + } + + pub fn list_shares() -> Result> { + let output = Command::new("sharing") + .arg("-l") + .output()?; + + let status = String::from_utf8_lossy(&output.stdout); + + if status.contains("No share point records") { + return Ok(vec![]); + } + + let shares: Vec = status + .lines() + .filter(|line| line.contains("name:")) + .map(|line| { + line.split(":") + .nth(1) + .unwrap_or("") + .trim() + .to_string() + }) + .collect(); + + Ok(shares) + } + + pub fn status(&self) -> Result { + let service_running = Self::check_smb_service()?; + let shares = Self::list_shares()?; + + Ok(serde_json::json!({ + "service_running": service_running, + "share_name": self.config.share_name, + "path": self.config.path, + "existing_shares": shares, + "config": self.config, + })) + } +} \ No newline at end of file