From: Shivani Bhardwaj Date: Thu, 12 Aug 2021 13:11:12 +0000 (+0530) Subject: nfs: use Direction enum X-Git-Tag: suricata-7.0.0-beta1~1219 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=11c438a07d94bef3ce97f2911b4adffe106399e2;p=thirdparty%2Fsuricata.git nfs: use Direction enum --- diff --git a/rust/src/nfs/nfs.rs b/rust/src/nfs/nfs.rs index d919dae2b9..b8c1cc497d 100644 --- a/rust/src/nfs/nfs.rs +++ b/rust/src/nfs/nfs.rs @@ -171,7 +171,7 @@ pub struct NFSTransaction { pub is_file_closed: bool, /// file transactions are unidirectional in the sense that they track /// a single file on one direction - pub file_tx_direction: u8, // STREAM_TOCLIENT or STREAM_TOSERVER + pub file_tx_direction: Direction, // Direction::ToClient or Direction::ToServer pub file_handle: Vec, /// Procedure type specific data @@ -205,7 +205,7 @@ impl NFSTransaction { nfs_version:0, is_file_tx: false, is_file_closed: false, - file_tx_direction: 0, + file_tx_direction: Direction::ToServer, file_handle:Vec::new(), type_data: None, de_state: None, @@ -474,7 +474,7 @@ impl NFSState { if self.ts > f.post_gap_ts { tx.request_done = true; tx.response_done = true; - let (files, flags) = self.files.get(tx.file_tx_direction.into()); + let (files, flags) = self.files.get(tx.file_tx_direction); f.file_tracker.trunc(files, flags); } else { post_gap_txs = true; @@ -490,9 +490,9 @@ impl NFSState { * can handle gaps. For the file transactions we set the current * (flow) time and prune them in 60 seconds if no update for them * was received. */ - fn post_gap_housekeeping(&mut self, dir: u8) + fn post_gap_housekeeping(&mut self, dir: Direction) { - if self.ts_ssn_gap && dir == STREAM_TOSERVER { + if self.ts_ssn_gap && dir == Direction::ToServer { for tx in &mut self.transactions { if tx.id >= self.tx_id { SCLogDebug!("post_gap_housekeeping: done"); @@ -510,7 +510,7 @@ impl NFSState { tx.request_done = true; } } - } else if self.tc_ssn_gap && dir == STREAM_TOCLIENT { + } else if self.tc_ssn_gap && dir == Direction::ToClient { for tx in &mut self.transactions { if tx.id >= self.tx_id { SCLogDebug!("post_gap_housekeeping: done"); @@ -576,7 +576,7 @@ impl NFSState { } } - pub fn new_file_tx(&mut self, file_handle: &Vec, file_name: &Vec, direction: u8) + pub fn new_file_tx(&mut self, file_handle: &Vec, file_name: &Vec, direction: Direction) -> (&mut NFSTransaction, &mut FileContainer, u16) { let mut tx = self.new_tx(); @@ -594,11 +594,11 @@ impl NFSState { tx.id, String::from_utf8_lossy(file_name)); self.transactions.push(tx); let tx_ref = self.transactions.last_mut(); - let (files, flags) = self.files.get(direction.into()); + let (files, flags) = self.files.get(direction); return (tx_ref.unwrap(), files, flags) } - pub fn get_file_tx_by_handle(&mut self, file_handle: &Vec, direction: u8) + pub fn get_file_tx_by_handle(&mut self, file_handle: &Vec, direction: Direction) -> Option<(&mut NFSTransaction, &mut FileContainer, u16)> { let fh = file_handle.to_vec(); @@ -608,7 +608,7 @@ impl NFSState { tx.file_handle == fh { SCLogDebug!("Found NFS file TX with ID {} XID {:04X}", tx.id, tx.xid); - let (files, flags) = self.files.get(direction.into()); + let (files, flags) = self.files.get(direction); return Some((tx, files, flags)); } } @@ -635,7 +635,7 @@ impl NFSState { Vec::new() }; - let found = match self.get_file_tx_by_handle(&file_handle, STREAM_TOSERVER) { + let found = match self.get_file_tx_by_handle(&file_handle, Direction::ToServer) { Some((tx, files, flags)) => { if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { filetracker_newchunk(&mut tdf.file_tracker, files, flags, @@ -656,7 +656,7 @@ impl NFSState { None => { false }, }; if !found { - let (tx, files, flags) = self.new_file_tx(&file_handle, &file_name, STREAM_TOSERVER); + let (tx, files, flags) = self.new_file_tx(&file_handle, &file_name, Direction::ToServer); if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { filetracker_newchunk(&mut tdf.file_tracker, files, flags, &file_name, w.file_data, w.offset, @@ -739,8 +739,8 @@ impl NFSState { // update in progress chunks for file transfers // return how much data we consumed - fn filetracker_update(&mut self, direction: u8, data: &[u8], gap_size: u32) -> u32 { - let mut chunk_left = if direction == STREAM_TOSERVER { + fn filetracker_update(&mut self, direction: Direction, data: &[u8], gap_size: u32) -> u32 { + let mut chunk_left = if direction == Direction::ToServer { self.ts_chunk_left } else { self.tc_chunk_left @@ -748,7 +748,7 @@ impl NFSState { if chunk_left == 0 { return 0 } - let xid = if direction == STREAM_TOSERVER { + let xid = if direction == Direction::ToServer { self.ts_chunk_xid } else { self.tc_chunk_xid @@ -760,7 +760,7 @@ impl NFSState { if chunk_left <= data.len() as u32 { chunk_left = 0; - if direction == STREAM_TOSERVER { + if direction == Direction::ToServer { self.ts_chunk_xid = 0; file_handle = self.ts_chunk_fh.to_vec(); self.ts_chunk_fh.clear(); @@ -781,7 +781,7 @@ impl NFSState { } else { chunk_left -= data.len() as u32; - if direction == STREAM_TOSERVER { + if direction == Direction::ToServer { file_handle = self.ts_chunk_fh.to_vec(); } else { // see if we have a file handle to work on @@ -797,7 +797,7 @@ impl NFSState { } } - if direction == STREAM_TOSERVER { + if direction == Direction::ToServer { self.ts_chunk_left = chunk_left; } else { self.tc_chunk_left = chunk_left; @@ -825,7 +825,7 @@ impl NFSState { let cs = tdf.file_tracker.update(files, flags, data, gap_size); /* see if we need to close the tx */ if tdf.file_tracker.is_done() { - if direction == STREAM_TOCLIENT { + if direction == Direction::ToClient { tx.response_done = true; tx.is_file_closed = true; SCLogDebug!("TX {} response is done now that the file track is ready", tx.id); @@ -901,7 +901,7 @@ impl NFSState { let is_partial = reply.data.len() < reply.count as usize; SCLogDebug!("partial data? {}", is_partial); - let found = match self.get_file_tx_by_handle(&file_handle, STREAM_TOCLIENT) { + let found = match self.get_file_tx_by_handle(&file_handle, Direction::ToClient) { Some((tx, files, flags)) => { SCLogDebug!("updated TX {:?}", tx); if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { @@ -931,7 +931,7 @@ impl NFSState { None => { false }, }; if !found { - let (tx, files, flags) = self.new_file_tx(&file_handle, &file_name, STREAM_TOCLIENT); + let (tx, files, flags) = self.new_file_tx(&file_handle, &file_name, Direction::ToClient); if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { filetracker_newchunk(&mut tdf.file_tracker, files, flags, &file_name, reply.data, chunk_offset, @@ -986,7 +986,7 @@ impl NFSState { pub fn parse_tcp_data_ts_gap<'b>(&mut self, gap_size: u32) -> AppLayerResult { SCLogDebug!("parse_tcp_data_ts_gap ({})", gap_size); let gap = vec![0; gap_size as usize]; - let consumed = self.filetracker_update(STREAM_TOSERVER, &gap, gap_size); + let consumed = self.filetracker_update(Direction::ToServer, &gap, gap_size); if consumed > gap_size { SCLogDebug!("consumed more than GAP size: {} > {}", consumed, gap_size); return AppLayerResult::ok(); @@ -1000,7 +1000,7 @@ impl NFSState { pub fn parse_tcp_data_tc_gap<'b>(&mut self, gap_size: u32) -> AppLayerResult { SCLogDebug!("parse_tcp_data_tc_gap ({})", gap_size); let gap = vec![0; gap_size as usize]; - let consumed = self.filetracker_update(STREAM_TOCLIENT, &gap, gap_size); + let consumed = self.filetracker_update(Direction::ToClient, &gap, gap_size); if consumed > gap_size { SCLogDebug!("consumed more than GAP size: {} > {}", consumed, gap_size); return AppLayerResult::ok(); @@ -1016,7 +1016,7 @@ impl NFSState { let mut cur_i = i; // take care of in progress file chunk transfers // and skip buffer beyond it - let consumed = self.filetracker_update(STREAM_TOSERVER, cur_i, 0); + let consumed = self.filetracker_update(Direction::ToServer, cur_i, 0); if consumed > 0 { if consumed > cur_i.len() as u32 { return AppLayerResult::err(); @@ -1032,7 +1032,7 @@ impl NFSState { let mut _cnt = 0; while cur_i.len() > 0 { _cnt += 1; - match nfs_probe(cur_i, STREAM_TOSERVER) { + match nfs_probe(cur_i, Direction::ToServer) { 1 => { SCLogDebug!("expected data found"); self.ts_gap = false; @@ -1155,7 +1155,7 @@ impl NFSState { } }; - self.post_gap_housekeeping(STREAM_TOSERVER); + self.post_gap_housekeeping(Direction::ToServer); if self.check_post_gap_file_txs && !self.post_gap_files_checked { self.post_gap_housekeeping_for_files(); self.post_gap_files_checked = true; @@ -1169,7 +1169,7 @@ impl NFSState { let mut cur_i = i; // take care of in progress file chunk transfers // and skip buffer beyond it - let consumed = self.filetracker_update(STREAM_TOCLIENT, cur_i, 0); + let consumed = self.filetracker_update(Direction::ToClient, cur_i, 0); if consumed > 0 { if consumed > cur_i.len() as u32 { return AppLayerResult::err(); @@ -1185,7 +1185,7 @@ impl NFSState { let mut _cnt = 0; while cur_i.len() > 0 { _cnt += 1; - match nfs_probe(cur_i, STREAM_TOCLIENT) { + match nfs_probe(cur_i, Direction::ToClient) { 1 => { SCLogDebug!("expected data found"); self.tc_gap = false; @@ -1306,7 +1306,7 @@ impl NFSState { }, } }; - self.post_gap_housekeeping(STREAM_TOCLIENT); + self.post_gap_housekeeping(Direction::ToClient); if self.check_post_gap_file_txs && !self.post_gap_files_checked { self.post_gap_housekeeping_for_files(); self.post_gap_files_checked = true; @@ -1361,17 +1361,17 @@ impl NFSState { AppLayerResult::ok() } - fn getfiles(&mut self, direction: u8) -> * mut FileContainer { - //SCLogDebug!("direction: {}", direction); - if direction == STREAM_TOCLIENT { + fn getfiles(&mut self, direction: Direction) -> * mut FileContainer { + //SCLogDebug!("direction: {:?}", direction); + if direction == Direction::ToClient { &mut self.files.files_tc as *mut FileContainer } else { &mut self.files.files_ts as *mut FileContainer } } - fn setfileflags(&mut self, direction: u8, flags: u16) { - SCLogDebug!("direction: {}, flags: {}", direction, flags); - if direction == STREAM_TOCLIENT { + fn setfileflags(&mut self, direction: Direction, flags: u16) { + SCLogDebug!("direction: {:?}, flags: {}", direction, flags); + if direction == Direction::ToClient { self.files.flags_tc = flags; } else { self.files.flags_ts = flags; @@ -1410,8 +1410,8 @@ pub unsafe extern "C" fn rs_nfs_parse_request(flow: *const Flow, { let state = cast_pointer!(state, NFSState); let flow = cast_pointer!(flow, Flow); - let file_flags = FileFlowToFlags(flow, STREAM_TOSERVER); - rs_nfs_setfileflags(STREAM_TOSERVER, state, file_flags); + let file_flags = FileFlowToFlags(flow, Direction::ToServer.into()); + rs_nfs_setfileflags(Direction::ToServer.into(), state, file_flags); if input.is_null() == true && input_len > 0 { return rs_nfs_parse_request_tcp_gap(state, input_len); @@ -1444,8 +1444,8 @@ pub unsafe extern "C" fn rs_nfs_parse_response(flow: *const Flow, { let state = cast_pointer!(state, NFSState); let flow = cast_pointer!(flow, Flow); - let file_flags = FileFlowToFlags(flow, STREAM_TOCLIENT); - rs_nfs_setfileflags(STREAM_TOCLIENT, state, file_flags); + let file_flags = FileFlowToFlags(flow, Direction::ToClient.into()); + rs_nfs_setfileflags(Direction::ToClient.into(), state, file_flags); if input.is_null() == true && input_len > 0 { return rs_nfs_parse_response_tcp_gap(state, input_len); @@ -1477,8 +1477,8 @@ pub unsafe extern "C" fn rs_nfs_parse_request_udp(f: *const Flow, _flags: u8) -> AppLayerResult { let state = cast_pointer!(state, NFSState); - let file_flags = FileFlowToFlags(f, STREAM_TOSERVER); - rs_nfs_setfileflags(STREAM_TOSERVER, state, file_flags); + let file_flags = FileFlowToFlags(f, Direction::ToServer.into()); + rs_nfs_setfileflags(Direction::ToServer.into(), state, file_flags); let buf = std::slice::from_raw_parts(input, input_len as usize); SCLogDebug!("parsing {} bytes of request data", input_len); @@ -1495,8 +1495,8 @@ pub unsafe extern "C" fn rs_nfs_parse_response_udp(f: *const Flow, _flags: u8) -> AppLayerResult { let state = cast_pointer!(state, NFSState); - let file_flags = FileFlowToFlags(f, STREAM_TOCLIENT); - rs_nfs_setfileflags(STREAM_TOCLIENT, state, file_flags); + let file_flags = FileFlowToFlags(f, Direction::ToClient.into()); + rs_nfs_setfileflags(Direction::ToClient.into(), state, file_flags); SCLogDebug!("parsing {} bytes of response data", input_len); let buf = std::slice::from_raw_parts(input, input_len as usize); state.parse_udp_tc(buf) @@ -1565,10 +1565,10 @@ pub unsafe extern "C" fn rs_nfs_tx_get_alstate_progress(tx: *mut std::os::raw::c -> std::os::raw::c_int { let tx = cast_pointer!(tx, NFSTransaction); - if direction == STREAM_TOSERVER && tx.request_done { + if direction == Direction::ToServer.into() && tx.request_done { //SCLogNotice!("TOSERVER progress 1"); return 1; - } else if direction == STREAM_TOCLIENT && tx.response_done { + } else if direction == Direction::ToClient.into() && tx.response_done { //SCLogNotice!("TOCLIENT progress 1"); return 1; } else { @@ -1715,11 +1715,11 @@ fn nfs_probe_dir(i: &[u8], rdir: *mut u8) -> i8 { match parse_rpc_packet_header(i) { Ok((_, ref hdr)) => { let dir = if hdr.msgtype == 0 { - STREAM_TOSERVER + Direction::ToServer } else { - STREAM_TOCLIENT + Direction::ToClient }; - unsafe { *rdir = dir }; + unsafe { *rdir = dir as u8 }; return 1; }, Err(nom::Err::Incomplete(_)) => { @@ -1731,8 +1731,8 @@ fn nfs_probe_dir(i: &[u8], rdir: *mut u8) -> i8 { } } -pub fn nfs_probe(i: &[u8], direction: u8) -> i32 { - if direction == STREAM_TOCLIENT { +pub fn nfs_probe(i: &[u8], direction: Direction) -> i32 { + if direction == Direction::ToClient { match parse_rpc_reply(i) { Ok((_, ref rpc)) => { if rpc.hdr.frag_len >= 24 && rpc.hdr.frag_len <= 35000 && rpc.hdr.msgtype == 1 && rpc.reply_state == 0 && rpc.accept_state == 0 { @@ -1787,8 +1787,8 @@ pub fn nfs_probe(i: &[u8], direction: u8) -> i32 { } } -pub fn nfs_probe_udp(i: &[u8], direction: u8) -> i32 { - if direction == STREAM_TOCLIENT { +pub fn nfs_probe_udp(i: &[u8], direction: Direction) -> i32 { + if direction == Direction::ToClient { match parse_rpc_udp_reply(i) { Ok((_, ref rpc)) => { if i.len() >= 32 && rpc.hdr.msgtype == 1 && rpc.reply_state == 0 && rpc.accept_state == 0 { @@ -1833,15 +1833,15 @@ pub unsafe extern "C" fn rs_nfs_probe_ms( let mut adirection : u8 = 0; match nfs_probe_dir(slice, &mut adirection) { 1 => { - if adirection == STREAM_TOSERVER { - SCLogDebug!("nfs_probe_dir said STREAM_TOSERVER"); + if adirection == Direction::ToServer.into() { + SCLogDebug!("nfs_probe_dir said Direction::ToServer"); } else { - SCLogDebug!("nfs_probe_dir said STREAM_TOCLIENT"); + SCLogDebug!("nfs_probe_dir said Direction::ToClient"); } - match nfs_probe(slice, adirection) { + match nfs_probe(slice, adirection.into()) { 1 => { SCLogDebug!("nfs_probe success: dir {:02x} adir {:02x}", direction, adirection); - if (direction & (STREAM_TOSERVER|STREAM_TOCLIENT)) != adirection { + if (direction & DIR_BOTH) != adirection { *rdir = adirection; } ALPROTO_NFS @@ -1869,7 +1869,7 @@ pub unsafe extern "C" fn rs_nfs_probe(_f: *const Flow, { let slice: &[u8] = build_slice!(input, len as usize); SCLogDebug!("rs_nfs_probe: running probe"); - match nfs_probe(slice, direction) { + match nfs_probe(slice, direction.into()) { 1 => { ALPROTO_NFS }, -1 => { ALPROTO_FAILED }, _ => { ALPROTO_UNKNOWN }, @@ -1886,7 +1886,7 @@ pub unsafe extern "C" fn rs_nfs_probe_udp_ts(_f: *const Flow, -> AppProto { let slice: &[u8] = build_slice!(input, len as usize); - match nfs_probe_udp(slice, STREAM_TOSERVER) { + match nfs_probe_udp(slice, Direction::ToServer) { 1 => { ALPROTO_NFS }, -1 => { ALPROTO_FAILED }, _ => { ALPROTO_UNKNOWN }, @@ -1903,7 +1903,7 @@ pub unsafe extern "C" fn rs_nfs_probe_udp_tc(_f: *const Flow, -> AppProto { let slice: &[u8] = build_slice!(input, len as usize); - match nfs_probe_udp(slice, STREAM_TOCLIENT) { + match nfs_probe_udp(slice, Direction::ToClient) { 1 => { ALPROTO_NFS }, -1 => { ALPROTO_FAILED }, _ => { ALPROTO_UNKNOWN }, @@ -1914,14 +1914,14 @@ pub unsafe extern "C" fn rs_nfs_probe_udp_tc(_f: *const Flow, pub unsafe extern "C" fn rs_nfs_getfiles(ptr: *mut std::ffi::c_void, direction: u8) -> * mut FileContainer { if ptr.is_null() { panic!("NULL ptr"); }; let parser = cast_pointer!(ptr, NFSState); - parser.getfiles(direction) + parser.getfiles(direction.into()) } #[no_mangle] pub unsafe extern "C" fn rs_nfs_setfileflags(direction: u8, ptr: *mut NFSState, flags: u16) { if ptr.is_null() { panic!("NULL ptr"); }; let parser = &mut *ptr; SCLogDebug!("direction {} flags {}", direction, flags); - parser.setfileflags(direction, flags) + parser.setfileflags(direction.into(), flags) } // Parser name as a C style string. @@ -1984,13 +1984,13 @@ pub unsafe extern "C" fn rs_nfs_register_parser() { /* register 'midstream' probing parsers if midstream is enabled. */ AppLayerProtoDetectPPRegister(IPPROTO_TCP as u8, default_port.as_ptr(), ALPROTO_NFS, 0, - NFS_MIN_FRAME_LEN, STREAM_TOSERVER, + NFS_MIN_FRAME_LEN, Direction::ToServer.into(), rs_nfs_probe_ms, rs_nfs_probe_ms); } } else { AppLayerProtoDetectPPRegister(IPPROTO_TCP as u8, default_port.as_ptr(), ALPROTO_NFS, 0, - NFS_MIN_FRAME_LEN, STREAM_TOSERVER, + NFS_MIN_FRAME_LEN, Direction::ToServer.into(), rs_nfs_probe, rs_nfs_probe); } if AppLayerParserConfParserEnabled( @@ -2060,7 +2060,7 @@ pub unsafe extern "C" fn rs_nfs_udp_register_parser() { default_port); AppLayerProtoDetectPPRegister(IPPROTO_UDP as u8, default_port.as_ptr(), ALPROTO_NFS, 0, - NFS_MIN_FRAME_LEN, STREAM_TOSERVER, + NFS_MIN_FRAME_LEN, Direction::ToServer.into(), rs_nfs_probe_udp_ts, rs_nfs_probe_udp_tc); } if AppLayerParserConfParserEnabled( diff --git a/rust/src/nfs/nfs3.rs b/rust/src/nfs/nfs3.rs index 90fee66435..b9fb120f76 100644 --- a/rust/src/nfs/nfs3.rs +++ b/rust/src/nfs/nfs3.rs @@ -118,7 +118,7 @@ impl NFSState { SCLogDebug!("COMMIT, closing shop"); if let Ok((_, rd)) = parse_nfs3_request_commit(r.prog_data) { let file_handle = rd.handle.value.to_vec(); - if let Some((tx, files, flags)) = self.get_file_tx_by_handle(&file_handle, STREAM_TOSERVER) { + if let Some((tx, files, flags)) = self.get_file_tx_by_handle(&file_handle, Direction::ToServer) { if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { tdf.chunk_count += 1; tdf.file_additional_procs.push(NFSPROC3_COMMIT); @@ -165,12 +165,12 @@ impl NFSState { } else if r.procedure == NFSPROC3_READ { - let found = match self.get_file_tx_by_handle(&xidmap.file_handle, STREAM_TOCLIENT) { + let found = match self.get_file_tx_by_handle(&xidmap.file_handle, Direction::ToClient) { Some((_, _, _)) => true, None => false, }; if !found { - let (tx, _, _) = self.new_file_tx(&xidmap.file_handle, &xidmap.file_name, STREAM_TOCLIENT); + let (tx, _, _) = self.new_file_tx(&xidmap.file_handle, &xidmap.file_name, Direction::ToClient); tx.procedure = NFSPROC3_READ; tx.xid = r.hdr.xid; tx.is_first = true; diff --git a/rust/src/nfs/nfs4.rs b/rust/src/nfs/nfs4.rs index 6da586cad8..aec2ef8988 100644 --- a/rust/src/nfs/nfs4.rs +++ b/rust/src/nfs/nfs4.rs @@ -60,7 +60,7 @@ impl NFSState { Vec::new() }; - let found = match self.get_file_tx_by_handle(&file_handle, STREAM_TOSERVER) { + let found = match self.get_file_tx_by_handle(&file_handle, Direction::ToServer) { Some((tx, files, flags)) => { if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { filetracker_newchunk(&mut tdf.file_tracker, files, flags, @@ -78,7 +78,7 @@ impl NFSState { None => false, }; if !found { - let (tx, files, flags) = self.new_file_tx(&file_handle, &file_name, STREAM_TOSERVER); + let (tx, files, flags) = self.new_file_tx(&file_handle, &file_name, Direction::ToServer); if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { filetracker_newchunk(&mut tdf.file_tracker, files, flags, &file_name, w.data, w.offset, @@ -110,7 +110,7 @@ impl NFSState { SCLogDebug!("COMMIT, closing shop"); let file_handle = fh.to_vec(); - if let Some((tx, files, flags)) = self.get_file_tx_by_handle(&file_handle, STREAM_TOSERVER) { + if let Some((tx, files, flags)) = self.get_file_tx_by_handle(&file_handle, Direction::ToServer) { if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { tdf.file_tracker.close(files, flags); tdf.file_last_xid = r.hdr.xid;