Implement SMB Byte-range Lock (Phase 7)
- Add LockManager to oplock.rs: - LockRange struct for tracking byte-range locks - acquire() - check conflicts before granting lock - release() - remove specific lock by offset/length - clear() - clear all locks when file closed - ranges_overlap() - helper for conflict detection - Add LockManager to ServerState - Update handlers/lock.rs: - Parse LockRequest and LockElement - Process each lock element (acquire/release) - Support FLAG_EXCLUSIVE_LOCK, FLAG_SHARED_LOCK, FLAG_UNLOCK - Return STATUS_LOCK_NOT_GRANTED on conflict - Update handlers/close.rs: - Clear all locks when file closed - Add STATUS_LOCK_NOT_GRANTED to ntstatus.rs All 229 tests pass.
This commit is contained in:
+3
@@ -52,6 +52,9 @@ pub async fn handle(
|
||||
server.oplock_manager.unregister(&path, &req.file_id).await;
|
||||
}
|
||||
|
||||
// Phase 7: Clear all byte-range locks for this file
|
||||
server.lock_manager.clear(&req.file_id).await;
|
||||
|
||||
// Stat before closing if needed.
|
||||
let info_before_close = if want_attrs {
|
||||
if let Some(h) = handle.as_ref() {
|
||||
|
||||
+51
-5
@@ -3,18 +3,64 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::proto::header::Smb2Header;
|
||||
use crate::proto::messages::LockResponse;
|
||||
use crate::proto::messages::{LockElement, LockRequest, LockResponse};
|
||||
|
||||
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],
|
||||
server: &Arc<ServerState>,
|
||||
conn: &Arc<Connection>,
|
||||
hdr: &Smb2Header,
|
||||
body: &[u8],
|
||||
) -> HandlerResponse {
|
||||
let req = match LockRequest::parse(body) {
|
||||
Ok(r) => r,
|
||||
Err(_) => return HandlerResponse::err(ntstatus::STATUS_INVALID_PARAMETER),
|
||||
};
|
||||
|
||||
// Validate tree/session
|
||||
let tree_arc = match lookup_session_tree(conn, hdr).await {
|
||||
Ok(t) => t,
|
||||
Err(s) => return HandlerResponse::err(s),
|
||||
};
|
||||
|
||||
// Phase 7: Process each lock element
|
||||
for lock in &req.locks {
|
||||
let exclusive = lock.flags & LockElement::FLAG_EXCLUSIVE_LOCK != 0;
|
||||
let unlock = lock.flags & LockElement::FLAG_UNLOCK != 0;
|
||||
|
||||
if unlock {
|
||||
// Release lock
|
||||
server.lock_manager.release(
|
||||
&req.file_id,
|
||||
lock.offset,
|
||||
lock.length,
|
||||
hdr.session_id,
|
||||
tree_arc.read().await.id,
|
||||
).await;
|
||||
} else {
|
||||
// Acquire lock
|
||||
let fail_immediately = lock.flags & LockElement::FLAG_FAIL_IMMEDIATELY != 0;
|
||||
|
||||
let result = server.lock_manager.acquire(
|
||||
&req.file_id,
|
||||
lock.offset,
|
||||
lock.length,
|
||||
exclusive,
|
||||
hdr.session_id,
|
||||
tree_arc.read().await.id,
|
||||
).await;
|
||||
|
||||
if result.is_err() && fail_immediately {
|
||||
return HandlerResponse::err(ntstatus::STATUS_LOCK_NOT_GRANTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut buf = Vec::new();
|
||||
LockResponse::default().write_to(&mut buf).expect("encode");
|
||||
HandlerResponse::ok(buf)
|
||||
|
||||
Reference in New Issue
Block a user