//! READ handler. use std::sync::Arc; use crate::proto::header::Smb2Header; use crate::proto::messages::{ReadRequest, ReadResponse}; use crate::conn::state::Connection; use crate::dispatch::HandlerResponse; use crate::handlers::shared::{lookup_open, lookup_session_tree}; use crate::ntstatus; use crate::server::ServerState; pub async fn handle( server: &Arc, conn: &Arc, hdr: &Smb2Header, body: &[u8], ) -> HandlerResponse { let req = match ReadRequest::parse(body) { Ok(r) => r, Err(_) => return HandlerResponse::err(ntstatus::STATUS_INVALID_PARAMETER), }; let max_read = *conn.max_read_size.read().await; if req.length > max_read { 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 open_arc = match lookup_open(&tree_arc, req.file_id).await { Some(o) => o, None => return HandlerResponse::err(ntstatus::STATUS_FILE_CLOSED), }; // Phase 5.5: Get path and trigger oplock break before read (if needed) let (path, share_access, granted_access) = { let open = open_arc.read().await; (open.last_path.clone(), open.share_access, open.granted_access) }; // Trigger oplock break if this read conflicts with other opens let notifications = server.oplock_manager.break_oplock( &path, share_access, granted_access, ).await; // Send notifications to affected clients for notification in notifications { use crate::proto::framing::encode_frame; let notification_bytes = notification.write_to_bytes(); let mut frame = Vec::with_capacity(notification_bytes.len() + 4); encode_frame(¬ification_bytes, &mut frame); if let Some(tx) = conn.notification_tx.read().await.as_ref() { let _ = tx.send(frame).await; } } // Phase 5: Trigger lease break if lease exists (SMB 3.x) // READ operation doesn't break WRITE leases (only WRITE/HANDLE operations do) // But we still check for HANDLE lease conflicts let lease_notifications = server.lease_manager.break_lease( crate::oplock::SMB2_LEASE_HANDLE, // READ operation may break HANDLE leases ).await; for lease_notification in lease_notifications { use crate::proto::framing::encode_frame; let notification_bytes = lease_notification.write_to_bytes(); let mut frame = Vec::with_capacity(notification_bytes.len() + 4); encode_frame(¬ification_bytes, &mut frame); if let Some(tx) = conn.notification_tx.read().await.as_ref() { let _ = tx.send(frame).await; } } let result = { let open = open_arc.read().await; match open.handle.as_ref() { Some(h) => h.read(req.offset, req.length).await, None => return HandlerResponse::err(ntstatus::STATUS_FILE_CLOSED), } }; let bytes = match result { Ok(b) => b, Err(e) => return HandlerResponse::err(e.to_nt_status()), }; if bytes.is_empty() && req.length > 0 { return HandlerResponse::err(ntstatus::STATUS_END_OF_FILE); } let resp = ReadResponse { structure_size: 17, data_offset: ReadResponse::STANDARD_DATA_OFFSET, reserved: 0, data_length: bytes.len() as u32, data_remaining: 0, flags: 0, data: bytes.to_vec(), }; let mut buf = Vec::new(); resp.write_to(&mut buf).expect("encode"); HandlerResponse::ok(buf) }