SMB Server Phase 2: VFS backend build fix + integration test
Some checks failed
Test / build (push) Has been cancelled
Test / test (push) Has been cancelled

- Add VfsFile: Send supertrait for Mutex compatibility
- Fix SmbServerCommand: struct → Subcommand enum with Start variant
- Fix tracing_subscriber::init() → try_init() to avoid panic when
  logger already initialized
- Fix CLI subcommand name: smb-server → smb-start (flatten naming)
- Add #[command(name = "smb-start")] for CLI disambiguation
- Fix unused variable warnings (smb_fs.rs, smb_server_backend.rs)
- Remove unused VfsFile imports (webdav.rs, scp_handler.rs)
- Integration test: Docker smbclient verified (list, upload, read)
This commit is contained in:
Warren
2026-06-20 19:42:29 +08:00
parent 45d050c0b3
commit 7eb528d35f
167 changed files with 59897 additions and 12 deletions

107
vendor/smb-server/src/handlers/close.rs vendored Normal file
View File

@@ -0,0 +1,107 @@
//! CLOSE handler.
use std::sync::Arc;
use crate::proto::header::Smb2Header;
use crate::proto::messages::{CloseRequest, CloseResponse};
use tracing::debug;
use crate::conn::state::Connection;
use crate::dispatch::HandlerResponse;
use crate::handlers::shared::lookup_session_tree;
use crate::ntstatus;
use crate::server::ServerState;
const FLAG_POSTQUERY_ATTRIB: u16 = 0x0001;
pub async fn handle(
_server: &Arc<ServerState>,
conn: &Arc<Connection>,
hdr: &Smb2Header,
body: &[u8],
) -> HandlerResponse {
let req = match CloseRequest::parse(body) {
Ok(r) => r,
Err(_) => return HandlerResponse::err(ntstatus::STATUS_INVALID_PARAMETER),
};
let tree_arc = match lookup_session_tree(conn, hdr).await {
Ok(t) => t,
Err(s) => return HandlerResponse::err(s),
};
let removed = {
let tree = tree_arc.write().await;
let mut opens = tree.opens.write().await;
opens.remove(&req.file_id)
};
let open_arc = match removed {
Some(o) => o,
None => return HandlerResponse::err(ntstatus::STATUS_FILE_CLOSED),
};
// Pull state out, close the handle, then optionally unlink.
let mut open = open_arc.write().await;
let handle = open.handle.take();
let path = open.last_path.clone();
let delete_on_close = open.delete_on_close;
let want_attrs = req.flags & FLAG_POSTQUERY_ATTRIB != 0;
drop(open);
// Stat before closing if needed.
let info_before_close = if want_attrs {
if let Some(h) = handle.as_ref() {
h.stat().await.ok()
} else {
None
}
} else {
None
};
if let Some(h) = handle {
let _ = h.close().await;
}
if delete_on_close {
let tree = tree_arc.read().await;
let backend = tree.share.backend.clone();
drop(tree);
if let Err(e) = backend.unlink(&path).await {
debug!(error = %e, "delete-on-close unlink failed");
}
}
let resp = CloseResponse {
structure_size: 60,
flags: req.flags & FLAG_POSTQUERY_ATTRIB,
reserved: 0,
creation_time: info_before_close
.as_ref()
.map(|i| i.creation_time)
.unwrap_or(0),
last_access_time: info_before_close
.as_ref()
.map(|i| i.last_access_time)
.unwrap_or(0),
last_write_time: info_before_close
.as_ref()
.map(|i| i.last_write_time)
.unwrap_or(0),
change_time: info_before_close
.as_ref()
.map(|i| i.change_time)
.unwrap_or(0),
allocation_size: info_before_close
.as_ref()
.map(|i| i.allocation_size)
.unwrap_or(0),
end_of_file: info_before_close
.as_ref()
.map(|i| i.end_of_file)
.unwrap_or(0),
file_attributes: info_before_close
.as_ref()
.map(|i| i.attributes())
.unwrap_or(0),
};
let mut buf = Vec::new();
resp.write_to(&mut buf).expect("encode");
HandlerResponse::ok(buf)
}