From c44151867fd1f4c6afc93403158473a9dd023141 Mon Sep 17 00:00:00 2001 From: Jonathan Klimt Date: Fri, 12 Sep 2025 22:39:18 +0200 Subject: [PATCH] lseek: Fixed incorrect lseek behaviour with whence Set or Cur --- src/fs/fuse.rs | 51 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/fs/fuse.rs b/src/fs/fuse.rs index 065b0cb414..cab0b9ae5c 100644 --- a/src/fs/fuse.rs +++ b/src/fs/fuse.rs @@ -724,25 +724,44 @@ impl FuseFileHandleInner { } fn lseek(&mut self, offset: isize, whence: SeekWhence) -> io::Result { - debug!("FUSE lseek"); + debug!("FUSE lseek: offset: {offset}, whence: {whence:?}"); + + // Seek on fuse file systems seems to be a little odd: All reads are referenced from the + // beginning of the file, thus we have to track the offset ourself. Also, a read doesn't + // move the read pointer on the remote side, so we can't get the current position using + // remote lseek when referencing from `Cur` and we have to use the internally tracked + // position instead. + match whence { + SeekWhence::End | SeekWhence::Data | SeekWhence::Hole => { + if let (Some(nid), Some(fh)) = (self.fuse_nid, self.fuse_fh) { + let (cmd, rsp_payload_len) = ops::Lseek::create(nid, fh, offset, whence); + let rsp = get_filesystem_driver() + .ok_or(Errno::Nosys)? + .lock() + .send_command(cmd, rsp_payload_len)?; + + if rsp.headers.out_header.error < 0 { + return Err(Errno::Io); + } - if let (Some(nid), Some(fh)) = (self.fuse_nid, self.fuse_fh) { - let (cmd, rsp_payload_len) = ops::Lseek::create(nid, fh, offset, whence); - let rsp = get_filesystem_driver() - .ok_or(Errno::Nosys)? - .lock() - .send_command(cmd, rsp_payload_len)?; + let rsp_offset = rsp.headers.op_header.offset; + self.offset = rsp.headers.op_header.offset.try_into().unwrap(); - if rsp.headers.out_header.error < 0 { - return Err(Errno::Io); + Ok(rsp_offset.try_into().unwrap()) + } else { + Err(Errno::Io) + } + } + SeekWhence::Set => { + self.offset = offset.try_into().map_err(|_e| Errno::Inval)?; + Ok(self.offset as isize) + } + SeekWhence::Cur => { + self.offset = (self.offset as isize + offset) + .try_into() + .map_err(|_e| Errno::Inval)?; + Ok(self.offset as isize) } - - let rsp_offset = rsp.headers.op_header.offset; - self.offset = rsp.headers.op_header.offset.try_into().unwrap(); - - Ok(rsp_offset.try_into().unwrap()) - } else { - Err(Errno::Io) } }