RustForge

rust-kernel

Rustbelt: a hobby x86_64 kernel written in Rust

rust-kernel / src / fs / file.rs
1540 bytes ยท raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//! Open files: what a file descriptor refers to.
//!
//! `File` is the interface the read/write syscalls use. It's separate from
//! `Inode` because the same inode can be open several times with different
//! offsets, and because some files aren't in any file system at all (the
//! console). Linux calls this `struct file` + `file_operations`.

use super::{Inode, InodeKind};
use crate::errno::Errno;
use alloc::sync::Arc;
use spin::Mutex;

pub trait File: Send + Sync {
    /// Read up to `buf.len()` bytes; 0 means end of file.
    fn read(&self, buf: &mut [u8]) -> Result<usize, Errno>;
    /// Write bytes; returns how many were written.
    fn write(&self, buf: &[u8]) -> Result<usize, Errno>;
}

/// A regular file opened through the VFS: inode + current position.
pub struct InodeFile {
    inode: Arc<dyn Inode>,
    offset: Mutex<usize>,
}

impl InodeFile {
    pub fn open(inode: Arc<dyn Inode>) -> Result<Self, Errno> {
        if inode.kind() == InodeKind::Directory {
            return Err(Errno::EISDIR); // no getdents yet
        }
        Ok(InodeFile { inode, offset: Mutex::new(0) })
    }
}

impl File for InodeFile {
    fn read(&self, buf: &mut [u8]) -> Result<usize, Errno> {
        let mut offset = self.offset.lock();
        let n = self.inode.read_at(*offset, buf)?;
        *offset += n;
        Ok(n)
    }

    fn write(&self, buf: &[u8]) -> Result<usize, Errno> {
        let mut offset = self.offset.lock();
        let n = self.inode.write_at(*offset, buf)?;
        *offset += n;
        Ok(n)
    }
}