From cab19688d594d519d2f3449b31dd61ee09bb0ca9 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 26 Feb 2019 01:44:13 +0800 Subject: [PATCH] rename File to FileHandle. impl create for sys_open. --- kernel/Cargo.lock | 9 +++- kernel/src/fs/file.rs | 39 ++++++++++++---- kernel/src/fs/mod.rs | 2 +- kernel/src/process/structs.rs | 10 ++-- kernel/src/syscall/fs.rs | 88 +++++++++++++++++++++++++---------- kernel/src/syscall/mod.rs | 6 +-- 6 files changed, 109 insertions(+), 45 deletions(-) diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 7b4e2a6..0f98e0c 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -103,6 +103,11 @@ name = "cfg-if" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "deque" +version = "0.3.2" +source = "git+https://github.com/wangrunji0408/deque.git?branch=no_std#907d03935b9badde1902d9c84d138872f34c6763" + [[package]] name = "device_tree" version = "1.0.3" @@ -296,8 +301,9 @@ dependencies = [ name = "rcore-thread" version = "0.1.0" dependencies = [ + "deque 0.3.2 (git+https://github.com/wangrunji0408/deque.git?branch=no_std)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -511,6 +517,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum deque 0.3.2 (git+https://github.com/wangrunji0408/deque.git?branch=no_std)" = "" "checksum device_tree 1.0.3 (git+https://github.com/jiegec/device_tree-rs)" = "" "checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" "checksum fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f7f8eb465745ea9b02e2704612a9946a59fa40572086c6fd49d6ddcf30bf31" diff --git a/kernel/src/fs/file.rs b/kernel/src/fs/file.rs index 9658bb9..6a0cb24 100644 --- a/kernel/src/fs/file.rs +++ b/kernel/src/fs/file.rs @@ -1,31 +1,50 @@ -//! File structure for process +//! File handle for process use alloc::{string::String, sync::Arc}; -use rcore_fs::vfs::{Metadata, INode, Result}; +use rcore_fs::vfs::{Metadata, INode, Result, FsError}; #[derive(Clone)] -pub struct File { +pub struct FileHandle { inode: Arc, offset: usize, - readable: bool, - writable: bool, + options: OpenOptions, } -impl File { - pub fn new(inode: Arc, readable: bool, writable: bool) -> Self { - File { inode, offset: 0, readable, writable } +#[derive(Debug, Clone)] +pub struct OpenOptions { + pub read: bool, + pub write: bool, + /// Before each write, the file offset is positioned at the end of the file. + pub append: bool, +} + +impl FileHandle { + pub fn new(inode: Arc, options: OpenOptions) -> Self { + FileHandle { + inode, + offset: 0, + options, + } } pub fn read(&mut self, buf: &mut [u8]) -> Result { - assert!(self.readable); + if !self.options.read { + return Err(FsError::InvalidParam); // FIXME: => EBADF + } let len = self.inode.read_at(self.offset, buf)?; self.offset += len; Ok(len) } pub fn write(&mut self, buf: &[u8]) -> Result { - assert!(self.writable); + if !self.options.write { + return Err(FsError::InvalidParam); // FIXME: => EBADF + } + if self.options.append { + let info = self.inode.metadata()?; + self.offset = info.size; + } let len = self.inode.write_at(self.offset, buf)?; self.offset += len; Ok(len) diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index 22aa44c..dc18fd9 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -10,7 +10,7 @@ use crate::arch::driver::ide; use crate::drivers::{self, AsAny}; use crate::drivers::block::virtio_blk::VirtIOBlkDriver; -pub use self::file::File; +pub use self::file::*; pub use self::stdio::{STDIN, STDOUT}; mod file; diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 2248af6..5617ec8 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -7,7 +7,7 @@ use xmas_elf::{ElfFile, header, program::{Flags, Type}}; use crate::arch::interrupt::{Context, TrapFrame}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; -use crate::fs::File; +use crate::fs::{FileHandle, OpenOptions}; use super::abi::ProcInitInfo; @@ -20,7 +20,7 @@ pub struct Thread { pub struct Process { pub memory_set: MemorySet, - pub files: BTreeMap, + pub files: BTreeMap, pub cwd: String, } @@ -112,9 +112,9 @@ impl Thread { let kstack = KernelStack::new(); let mut files = BTreeMap::new(); - files.insert(0, File::new(crate::fs::STDIN.clone(), true, false)); - files.insert(1, File::new(crate::fs::STDOUT.clone(), false, true)); - files.insert(2, File::new(crate::fs::STDOUT.clone(), false, true)); + files.insert(0, FileHandle::new(crate::fs::STDIN.clone(), OpenOptions { read: true, write: false, append: false })); + files.insert(1, FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })); + files.insert(2, FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })); Box::new(Thread { context: unsafe { diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 6a8889c..471799a 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -2,6 +2,8 @@ use super::*; +use crate::fs::{ROOT_INODE, OpenOptions}; + pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len); let mut proc = process(); @@ -24,22 +26,44 @@ pub fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult { Ok(len as isize) } -pub fn sys_open(path: *const u8, flags: usize) -> SysResult { +pub fn sys_open(path: *const u8, flags: usize, mode: usize) -> SysResult { let mut proc = process(); let path = unsafe { proc.memory_set.check_and_clone_cstr(path) } .ok_or(SysError::Inval)?; - let flags = VfsFlags::from_ucore_flags(flags); - info!("open: path: {:?}, flags: {:?}", path, flags); - let (fd, inode) = match path.as_str() { - "stdin:" => (0, crate::fs::STDIN.clone() as Arc), - "stdout:" => (1, crate::fs::STDOUT.clone() as Arc), - _ => { - let fd = (3..).find(|i| !proc.files.contains_key(i)).unwrap(); - let inode = crate::fs::ROOT_INODE.lookup(path.as_str())?; - (fd, inode) + let flags = OpenFlags::from_bits_truncate(flags); + info!("open: path: {:?}, flags: {:?}, mode: {:#o}", path, flags, mode); + + let inode = + if flags.contains(OpenFlags::CREATE) { + // FIXME: assume path start from root now + let mut split = path.as_str().rsplitn(2, '/'); + let file_name = split.next().unwrap(); + let dir_path = split.next().unwrap_or("."); + let dir_inode = ROOT_INODE.lookup(dir_path)?; + match dir_inode.find(file_name) { + Ok(file_inode) => { + if flags.contains(OpenFlags::EXCLUSIVE) { + return Err(SysError::Exists); + } + file_inode + }, + Err(FsError::EntryNotFound) => { + dir_inode.create(file_name, FileType::File, mode as u32)? + } + Err(e) => return Err(SysError::from(e)), + } + } else { + // TODO: remove "stdin:" "stdout:" + match path.as_str() { + "stdin:" => crate::fs::STDIN.clone() as Arc, + "stdout:" => crate::fs::STDOUT.clone() as Arc, + _ => ROOT_INODE.lookup(path.as_str())?, } }; - let file = File::new(inode, flags.contains(VfsFlags::READABLE), flags.contains(VfsFlags::WRITABLE)); + + let fd = (3..).find(|i| !proc.files.contains_key(i)).unwrap(); + + let file = FileHandle::new(inode, flags.to_options()); proc.files.insert(fd, file); Ok(fd as isize) } @@ -98,30 +122,44 @@ pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult { Ok(0) } -fn get_file<'a>(proc: &'a mut MutexGuard<'static, Process>, fd: usize) -> Result<&'a mut File, SysError> { +fn get_file<'a>(proc: &'a mut MutexGuard<'static, Process>, fd: usize) -> Result<&'a mut FileHandle, SysError> { proc.files.get_mut(&fd).ok_or(SysError::Inval) } bitflags! { - struct VfsFlags: usize { - // WARNING: different from origin uCore - const READABLE = 1 << 0; - const WRITABLE = 1 << 1; + struct OpenFlags: usize { + /// read only + const RDONLY = 0; + /// write only + const WRONLY = 1; + /// read write + const RDWR = 2; /// create file if it does not exist - const CREATE = 1 << 2; - /// error if O_CREAT and the file exists - const EXCLUSIVE = 1 << 3; + const CREATE = 1 << 6; + /// error if CREATE and the file exists + const EXCLUSIVE = 1 << 7; /// truncate file upon open - const TRUNCATE = 1 << 4; + const TRUNCATE = 1 << 9; /// append on each write - const APPEND = 1 << 5; + const APPEND = 1 << 10; } } -impl VfsFlags { - fn from_ucore_flags(f: usize) -> Self { - assert_ne!(f & 0b11, 0b11); - Self::from_bits_truncate(f + 1) +impl OpenFlags { + fn readable(&self) -> bool { + let b = self.bits() & 0b11; + b == OpenFlags::RDONLY.bits() || b == OpenFlags::RDWR.bits() + } + fn writable(&self) -> bool { + let b = self.bits() & 0b11; + b == OpenFlags::WRONLY.bits() || b == OpenFlags::RDWR.bits() + } + fn to_options(&self) -> OpenOptions { + OpenOptions { + read: self.readable(), + write: self.writable(), + append: self.contains(OpenFlags::APPEND), + } } } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index cd892e8..6998e4c 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -8,7 +8,7 @@ use rcore_fs::vfs::{FileType, FsError, INode, Metadata}; use spin::{Mutex, MutexGuard}; use crate::arch::interrupt::TrapFrame; -use crate::fs::File; +use crate::fs::FileHandle; use crate::process::*; use crate::thread; use crate::util; @@ -31,7 +31,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { // file 000 => sys_read(args[0], args[1] as *mut u8, args[2]), 001 => sys_write(args[0], args[1] as *const u8, args[2]), - 002 => sys_open(args[0] as *const u8, args[1]), + 002 => sys_open(args[0] as *const u8, args[1], args[2]), 003 => sys_close(args[0]), // 004 => sys_stat(), 005 => sys_fstat(args[0], args[1] as *mut Stat), @@ -107,7 +107,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { 158 => sys_arch_prctl(args[0] as i32, args[1], tf), 218 => { warn!("sys_set_tid_address is unimplemented"); - Ok(0) + Ok(thread::current().id() as isize) } _ => { error!("unknown syscall id: {:#x?}, args: {:x?}", id, args);