mirror of
https://github.com/LearningOS/rust-based-os-comp2022.git
synced 2026-07-05 20:16:05 +08:00
add os[1-8]-ref for os refereces, add guide, add README
This commit is contained in:
169
os6-ref/src/fs/inode.rs
Normal file
169
os6-ref/src/fs/inode.rs
Normal file
@@ -0,0 +1,169 @@
|
||||
use easy_fs::{
|
||||
EasyFileSystem,
|
||||
Inode,
|
||||
};
|
||||
use crate::drivers::BLOCK_DEVICE;
|
||||
use crate::sync::UPSafeCell;
|
||||
use alloc::sync::Arc;
|
||||
use lazy_static::*;
|
||||
use bitflags::*;
|
||||
use alloc::vec::Vec;
|
||||
use super::File;
|
||||
use crate::mm::UserBuffer;
|
||||
|
||||
/// A wrapper around a filesystem inode
|
||||
/// to implement File trait atop
|
||||
pub struct OSInode {
|
||||
readable: bool,
|
||||
writable: bool,
|
||||
inner: UPSafeCell<OSInodeInner>,
|
||||
}
|
||||
|
||||
/// The OS inode inner in 'UPSafeCell'
|
||||
pub struct OSInodeInner {
|
||||
offset: usize,
|
||||
inode: Arc<Inode>,
|
||||
}
|
||||
|
||||
impl OSInode {
|
||||
/// Construct an OS inode from a inode
|
||||
pub fn new(
|
||||
readable: bool,
|
||||
writable: bool,
|
||||
inode: Arc<Inode>,
|
||||
) -> Self {
|
||||
Self {
|
||||
readable,
|
||||
writable,
|
||||
inner: unsafe { UPSafeCell::new(OSInodeInner {
|
||||
offset: 0,
|
||||
inode,
|
||||
})},
|
||||
}
|
||||
}
|
||||
/// Read all data inside a inode into vector
|
||||
pub fn read_all(&self) -> Vec<u8> {
|
||||
let mut inner = self.inner.exclusive_access();
|
||||
let mut buffer = [0u8; 512];
|
||||
let mut v: Vec<u8> = Vec::new();
|
||||
loop {
|
||||
let len = inner.inode.read_at(inner.offset, &mut buffer);
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
inner.offset += len;
|
||||
v.extend_from_slice(&buffer[..len]);
|
||||
}
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// The root of all inodes, or '/' in short
|
||||
pub static ref ROOT_INODE: Arc<Inode> = {
|
||||
let efs = EasyFileSystem::open(BLOCK_DEVICE.clone());
|
||||
Arc::new(EasyFileSystem::root_inode(&efs))
|
||||
};
|
||||
}
|
||||
|
||||
/// List all files in the filesystems
|
||||
pub fn list_apps() {
|
||||
println!("/**** APPS ****");
|
||||
for app in ROOT_INODE.ls() {
|
||||
println!("{}", app);
|
||||
}
|
||||
println!("**************/");
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags for opening files
|
||||
pub struct OpenFlags: u32 {
|
||||
const RDONLY = 0;
|
||||
const WRONLY = 1 << 0;
|
||||
const RDWR = 1 << 1;
|
||||
const CREATE = 1 << 9;
|
||||
const TRUNC = 1 << 10;
|
||||
}
|
||||
}
|
||||
|
||||
impl OpenFlags {
|
||||
/// Get the current read write permission on an inode
|
||||
/// does not check validity for simplicity
|
||||
/// returns (readable, writable)
|
||||
pub fn read_write(&self) -> (bool, bool) {
|
||||
if self.is_empty() {
|
||||
(true, false)
|
||||
} else if self.contains(Self::WRONLY) {
|
||||
(false, true)
|
||||
} else {
|
||||
(true, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Open a file by path
|
||||
pub fn open_file(name: &str, flags: OpenFlags) -> Option<Arc<OSInode>> {
|
||||
let (readable, writable) = flags.read_write();
|
||||
if flags.contains(OpenFlags::CREATE) {
|
||||
if let Some(inode) = ROOT_INODE.find(name) {
|
||||
// clear size
|
||||
inode.clear();
|
||||
Some(Arc::new(OSInode::new(
|
||||
readable,
|
||||
writable,
|
||||
inode,
|
||||
)))
|
||||
} else {
|
||||
// create file
|
||||
ROOT_INODE.create(name)
|
||||
.map(|inode| {
|
||||
Arc::new(OSInode::new(
|
||||
readable,
|
||||
writable,
|
||||
inode,
|
||||
))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
ROOT_INODE.find(name)
|
||||
.map(|inode| {
|
||||
if flags.contains(OpenFlags::TRUNC) {
|
||||
inode.clear();
|
||||
}
|
||||
Arc::new(OSInode::new(
|
||||
readable,
|
||||
writable,
|
||||
inode
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl File for OSInode {
|
||||
fn readable(&self) -> bool { self.readable }
|
||||
fn writable(&self) -> bool { self.writable }
|
||||
fn read(&self, mut buf: UserBuffer) -> usize {
|
||||
let mut inner = self.inner.exclusive_access();
|
||||
let mut total_read_size = 0usize;
|
||||
for slice in buf.buffers.iter_mut() {
|
||||
let read_size = inner.inode.read_at(inner.offset, *slice);
|
||||
if read_size == 0 {
|
||||
break;
|
||||
}
|
||||
inner.offset += read_size;
|
||||
total_read_size += read_size;
|
||||
}
|
||||
total_read_size
|
||||
}
|
||||
fn write(&self, buf: UserBuffer) -> usize {
|
||||
let mut inner = self.inner.exclusive_access();
|
||||
let mut total_write_size = 0usize;
|
||||
for slice in buf.buffers.iter() {
|
||||
let write_size = inner.inode.write_at(inner.offset, *slice);
|
||||
assert_eq!(write_size, slice.len());
|
||||
inner.offset += write_size;
|
||||
total_write_size += write_size;
|
||||
}
|
||||
total_write_size
|
||||
}
|
||||
}
|
||||
43
os6-ref/src/fs/mod.rs
Normal file
43
os6-ref/src/fs/mod.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
mod stdio;
|
||||
mod inode;
|
||||
|
||||
use crate::mm::UserBuffer;
|
||||
|
||||
/// The common abstraction of all IO resources
|
||||
pub trait File : Send + Sync {
|
||||
fn readable(&self) -> bool;
|
||||
fn writable(&self) -> bool;
|
||||
fn read(&self, buf: UserBuffer) -> usize;
|
||||
fn write(&self, buf: UserBuffer) -> usize;
|
||||
}
|
||||
|
||||
/// The stat of a inode
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Stat {
|
||||
/// ID of device containing file
|
||||
pub dev: u64,
|
||||
/// inode number
|
||||
pub ino: u64,
|
||||
/// file type and mode
|
||||
pub mode: StatMode,
|
||||
/// number of hard links
|
||||
pub nlink: u32,
|
||||
/// unused pad
|
||||
pad: [u64; 7],
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// The mode of a inode
|
||||
/// whether a directory or a file
|
||||
pub struct StatMode: u32 {
|
||||
const NULL = 0;
|
||||
/// directory
|
||||
const DIR = 0o040000;
|
||||
/// ordinary regular file
|
||||
const FILE = 0o100000;
|
||||
}
|
||||
}
|
||||
|
||||
pub use stdio::{Stdin, Stdout};
|
||||
pub use inode::{OSInode, open_file, OpenFlags, list_apps};
|
||||
48
os6-ref/src/fs/stdio.rs
Normal file
48
os6-ref/src/fs/stdio.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use super::File;
|
||||
use crate::mm::{UserBuffer};
|
||||
use crate::sbi::console_getchar;
|
||||
use crate::task::suspend_current_and_run_next;
|
||||
|
||||
/// The standard input
|
||||
pub struct Stdin;
|
||||
/// The standard output
|
||||
pub struct Stdout;
|
||||
|
||||
impl File for Stdin {
|
||||
fn readable(&self) -> bool { true }
|
||||
fn writable(&self) -> bool { false }
|
||||
fn read(&self, mut user_buf: UserBuffer) -> usize {
|
||||
assert_eq!(user_buf.len(), 1);
|
||||
// busy loop
|
||||
let mut c: usize;
|
||||
loop {
|
||||
c = console_getchar();
|
||||
if c == 0 {
|
||||
suspend_current_and_run_next();
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let ch = c as u8;
|
||||
unsafe { user_buf.buffers[0].as_mut_ptr().write_volatile(ch); }
|
||||
1
|
||||
}
|
||||
fn write(&self, _user_buf: UserBuffer) -> usize {
|
||||
panic!("Cannot write to stdin!");
|
||||
}
|
||||
}
|
||||
|
||||
impl File for Stdout {
|
||||
fn readable(&self) -> bool { false }
|
||||
fn writable(&self) -> bool { true }
|
||||
fn read(&self, _user_buf: UserBuffer) -> usize{
|
||||
panic!("Cannot read from stdout!");
|
||||
}
|
||||
fn write(&self, user_buf: UserBuffer) -> usize {
|
||||
for buffer in user_buf.buffers.iter() {
|
||||
print!("{}", core::str::from_utf8(*buffer).unwrap());
|
||||
}
|
||||
user_buf.len()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user