- Parse client's OPLOCK_BREAK_ACK - Update Open.oplock_level in Open struct - Update OplockManager entry via update_oplock_level() - Return confirmation response All 229 tests pass.
58 lines
1.7 KiB
Rust
58 lines
1.7 KiB
Rust
//! OPLOCK_BREAK handler — acknowledge breaks and update oplock state.
|
|
|
|
use std::sync::Arc;
|
|
|
|
use crate::proto::header::Smb2Header;
|
|
use crate::proto::messages::{FileId, OplockBreakAck};
|
|
|
|
use crate::conn::state::Connection;
|
|
use crate::dispatch::HandlerResponse;
|
|
use crate::handlers::shared::lookup_session_tree;
|
|
use crate::ntstatus;
|
|
use crate::server::ServerState;
|
|
|
|
pub async fn handle(
|
|
server: &Arc<ServerState>,
|
|
conn: &Arc<Connection>,
|
|
hdr: &Smb2Header,
|
|
body: &[u8],
|
|
) -> HandlerResponse {
|
|
// Parse client's ACK (MS-SMB2 §2.2.24)
|
|
let ack = match OplockBreakAck::parse(body) {
|
|
Ok(a) => a,
|
|
Err(_) => return HandlerResponse::err(ntstatus::STATUS_INVALID_PARAMETER),
|
|
};
|
|
|
|
// Lookup tree to get path for oplock manager
|
|
let tree_arc = match lookup_session_tree(conn, hdr).await {
|
|
Ok(t) => t,
|
|
Err(s) => return HandlerResponse::err(s),
|
|
};
|
|
|
|
// Update oplock level in the open
|
|
let path = {
|
|
// Find the open by file_id
|
|
let tree = tree_arc.read().await;
|
|
let opens = tree.opens.read().await;
|
|
if let Some(open_arc) = opens.get(&ack.file_id) {
|
|
let mut open = open_arc.write().await;
|
|
open.oplock_level = ack.oplock_level;
|
|
open.last_path.clone()
|
|
} else {
|
|
return HandlerResponse::err(ntstatus::STATUS_FILE_CLOSED);
|
|
}
|
|
};
|
|
|
|
// Update OplockManager entry
|
|
server.oplock_manager.update_oplock_level(
|
|
&path,
|
|
ack.file_id,
|
|
ack.oplock_level,
|
|
).await;
|
|
|
|
// Echo back the ACK as confirmation (MS-SMB2 §2.2.24)
|
|
let mut buf = Vec::new();
|
|
ack.write_to(&mut buf).expect("encode ack response");
|
|
HandlerResponse::ok(buf)
|
|
}
|