diff --git a/kernel/aster-nix/src/fs/file_handle.rs b/kernel/aster-nix/src/fs/file_handle.rs index 5393983b7..e12e682ff 100644 --- a/kernel/aster-nix/src/fs/file_handle.rs +++ b/kernel/aster-nix/src/fs/file_handle.rs @@ -23,6 +23,23 @@ pub trait FileLike: Send + Sync + Any { return_errno_with_message!(Errno::EINVAL, "write is not supported"); } + /// Read at the given file offset. + /// + /// The file must be seekable to support `read_at`. + /// Unlike [`read`], `read_at` will not change the file offset. + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + return_errno_with_message!(Errno::EINVAL, "read_at is not supported"); + } + + /// Write at the given file offset. + /// + /// The file must be seekable to support `write_at`. + /// Unlike [`write`], `write_at` will not change the file offset. + /// If the file is append-only, the `offset` will be ignored. + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + return_errno_with_message!(Errno::EINVAL, "write_at is not supported"); + } + fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { return_errno_with_message!(Errno::EINVAL, "ioctl is not supported"); } diff --git a/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs b/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs index 83c40a4f1..e2a416dde 100644 --- a/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs +++ b/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs @@ -98,6 +98,20 @@ impl FileLike for InodeHandle { self.0.write(buf) } + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + if !self.1.contains(Rights::READ) { + return_errno_with_message!(Errno::EBADF, "file is not readable"); + } + self.0.read_at(offset, buf) + } + + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + if !self.1.contains(Rights::WRITE) { + return_errno_with_message!(Errno::EBADF, "file is not writable"); + } + self.0.write_at(offset, buf) + } + fn resize(&self, new_size: usize) -> Result<()> { if !self.1.contains(Rights::WRITE) { return_errno_with_message!(Errno::EINVAL, "File is not writable"); diff --git a/kernel/aster-nix/src/fs/inode_handle/mod.rs b/kernel/aster-nix/src/fs/inode_handle/mod.rs index 78d39961b..66549b474 100644 --- a/kernel/aster-nix/src/fs/inode_handle/mod.rs +++ b/kernel/aster-nix/src/fs/inode_handle/mod.rs @@ -41,42 +41,64 @@ struct InodeHandle_ { impl InodeHandle_ { pub fn read(&self, buf: &mut [u8]) -> Result { - let mut offset = self.offset.lock(); - if let Some(ref file_io) = self.file_io { return file_io.read(buf); } - let len = if self.status_flags().contains(StatusFlags::O_DIRECT) { - self.dentry.inode().read_direct_at(*offset, buf)? - } else { - self.dentry.inode().read_at(*offset, buf)? - }; + let mut offset = self.offset.lock(); + + let len = self.read_at(*offset, buf)?; *offset += len; Ok(len) } pub fn write(&self, buf: &[u8]) -> Result { - let mut offset = self.offset.lock(); - if let Some(ref file_io) = self.file_io { return file_io.write(buf); } + let mut offset = self.offset.lock(); + if self.status_flags().contains(StatusFlags::O_APPEND) { *offset = self.dentry.size(); } - let len = if self.status_flags().contains(StatusFlags::O_DIRECT) { - self.dentry.inode().write_direct_at(*offset, buf)? - } else { - self.dentry.inode().write_at(*offset, buf)? - }; + + let len = self.write_at(*offset, buf)?; *offset += len; Ok(len) } + pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + if let Some(ref file_io) = self.file_io { + todo!("support read_at for FileIo"); + } + + if self.status_flags().contains(StatusFlags::O_DIRECT) { + self.dentry.inode().read_direct_at(offset, buf) + } else { + self.dentry.inode().read_at(offset, buf) + } + } + + pub fn write_at(&self, mut offset: usize, buf: &[u8]) -> Result { + if let Some(ref file_io) = self.file_io { + todo!("support write_at for FileIo"); + } + + if self.status_flags().contains(StatusFlags::O_APPEND) { + // If the file has the O_APPEND flag, the offset is ignored + offset = self.dentry.size(); + } + + if self.status_flags().contains(StatusFlags::O_DIRECT) { + self.dentry.inode().write_direct_at(offset, buf) + } else { + self.dentry.inode().write_at(offset, buf) + } + } + pub fn read_to_end(&self, buf: &mut Vec) -> Result { if self.file_io.is_some() { return_errno_with_message!(Errno::EINVAL, "file io does not support read to end");