From 0b4cc1a9930c9ff268d5a1072641dbccd90c0baf Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Tue, 31 Aug 2021 19:01:17 +0200 Subject: [PATCH 01/26] Add file syscalls --- src/api/syscall.rs | 35 +++++++++++++++++++++++++++++++++++ src/sys/process.rs | 37 ++++++++++++++++++++++++++++++++++++- src/sys/syscall/mod.rs | 26 ++++++++++++++++++++++---- src/sys/syscall/number.rs | 4 ++++ src/sys/syscall/service.rs | 32 ++++++++++++++++++++++++++++++++ src/usr/read.rs | 2 ++ 6 files changed, 131 insertions(+), 5 deletions(-) diff --git a/src/api/syscall.rs b/src/api/syscall.rs index f0d530600..5968045a3 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -14,3 +14,38 @@ pub fn realtime() -> f64 { let res = unsafe { syscall!(REALTIME) }; f64::from_bits(res as u64) } + +pub fn open(path: &str, mode: u8) -> u16 { + let ptr = path.as_ptr() as usize; + let len = path.len() as usize; + let res = unsafe { syscall!(OPEN, ptr, len, mode as usize) }; + res as u16 +} + +pub fn read(fh: u16, buf: &mut [u8]) -> usize { + let ptr = buf.as_ptr() as usize; + let len = buf.len() as usize; + let res = unsafe { syscall!(READ, fh, ptr, len) }; + res as usize +} + +pub fn write(fh: u16, buf: &mut [u8]) -> usize { + let ptr = buf.as_ptr() as usize; + let len = buf.len() as usize; + let res = unsafe { syscall!(WRITE, fh, ptr, len) }; + res as usize +} + +pub fn close(fh: u16) { + unsafe { syscall!(CLOSE, fh as usize) }; +} + +#[test_case] +fn test_open() { + use crate::sys::fs::{mount_mem, format_mem, File, dismount}; + mount_mem(); + format_mem(); + assert!(File::create("/test").is_some()); + //assert_eq!(open("/test", 0), 4); + dismount(); +} diff --git a/src/sys/process.rs b/src/sys/process.rs index d7fd2ae0f..ef2a691ec 100644 --- a/src/sys/process.rs +++ b/src/sys/process.rs @@ -1,9 +1,14 @@ +use crate::sys::fs::File; use alloc::collections::btree_map::BTreeMap; use alloc::string::{String, ToString}; +use alloc::vec; +use alloc::vec::Vec; use core::sync::atomic::{AtomicUsize, Ordering}; use lazy_static::lazy_static; use spin::Mutex; +const MAX_FILE_HANDLES: usize = 1024; + lazy_static! { pub static ref PIDS: AtomicUsize = AtomicUsize::new(0); pub static ref PROCESS: Mutex = Mutex::new(Process::new("/", None)); // TODO @@ -14,6 +19,7 @@ pub struct Process { env: BTreeMap, dir: String, user: Option, + file_handles: Vec>, } impl Process { @@ -22,7 +28,8 @@ impl Process { let env = BTreeMap::new(); let dir = dir.to_string(); let user = user.map(String::from); - Self { id, env, dir, user } + let file_handles = vec![None; MAX_FILE_HANDLES]; + Self { id, env, dir, user, file_handles } } } @@ -57,3 +64,31 @@ pub fn set_dir(dir: &str) { pub fn set_user(user: &str) { PROCESS.lock().user = Some(user.into()) } + +pub fn create_file_handle(file: File) -> Result { + let min = 4; // The first 4 file handles are reserved + let max = MAX_FILE_HANDLES; + let proc = &mut *PROCESS.lock(); + for fh in min..max { + if proc.file_handles[fh].is_none() { + proc.file_handles[fh] = Some(file); + return Ok(fh); + } + } + Err(()) +} + +pub fn update_file_handle(fh: usize, file: File) { + let proc = &mut *PROCESS.lock(); + proc.file_handles[fh] = Some(file); +} + +pub fn delete_file_handle(fh: usize) { + let proc = &mut *PROCESS.lock(); + proc.file_handles[fh] = None; +} + +pub fn file_handle(fh: usize) -> Option { + let proc = &mut *PROCESS.lock(); + proc.file_handles[fh].clone() +} diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index 228800810..34d2750df 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -1,25 +1,43 @@ pub mod number; pub mod service; +use alloc::string::String; + /* * Dispatching system calls */ -pub fn dispatcher(n: usize, arg1: usize, _arg2: usize, _arg3: usize) -> usize { +pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { match n { number::SLEEP => { - // sleep(f64) service::sleep(f64::from_bits(arg1 as u64)); 0 } number::UPTIME => { - // uptime() -> f64 service::uptime().to_bits() as usize } number::REALTIME => { - // realtime() -> f64 service::realtime().to_bits() as usize } + number::OPEN => { + let ptr = arg1 as *mut u8; + let len = arg2; + let mode = arg3 as u8; + let path = unsafe { String::from_raw_parts(ptr, len, len) }; + service::open(&path, mode) as usize + } + number::READ => { + let fh = arg1 as u16; + let ptr = arg2 as *mut u8; + let len = arg3; + let mut buf = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; + service::read(fh, &mut buf) + } + number::CLOSE => { + let fh = arg1 as u16; + service::close(fh); + 0 + } _ => { unimplemented!(); } diff --git a/src/sys/syscall/number.rs b/src/sys/syscall/number.rs index 2c0cb77fa..4b2bd5d7b 100644 --- a/src/sys/syscall/number.rs +++ b/src/sys/syscall/number.rs @@ -1,3 +1,7 @@ pub const SLEEP: usize = 0; pub const UPTIME: usize = 1; pub const REALTIME: usize = 2; +pub const OPEN: usize = 3; +pub const READ: usize = 4; +pub const WRITE: usize = 5; +pub const CLOSE: usize = 6; diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index ea6204d70..2d3a152c9 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -13,3 +13,35 @@ pub fn uptime() -> f64 { pub fn realtime() -> f64 { sys::clock::realtime() } + +pub fn open(path: &str, _mode: u8) -> u16 { + if let Some(file) = sys::fs::File::open(path) { + if let Ok(fh) = sys::process::create_file_handle(file) { + return fh as u16; + } + } + 0 +} + +pub fn read(fh: u16, buf: &mut [u8]) -> usize { + if let Some(mut file) = sys::process::file_handle(fh as usize) { + let bytes = file.read(buf); + sys::process::update_file_handle(fh as usize, file); + return bytes; + } + 0 +} + +pub fn write(fh: u16, buf: &mut [u8]) -> usize { + if let Some(mut file) = sys::process::file_handle(fh as usize) { + if let Ok(bytes) = file.write(buf) { + sys::process::update_file_handle(fh as usize, file); + return bytes; + } + } + 0 +} + +pub fn close(fh: u16) { + sys::process::delete_file_handle(fh as usize); +} diff --git a/src/usr/read.rs b/src/usr/read.rs index 089bc7be4..c2b3ef6fe 100644 --- a/src/usr/read.rs +++ b/src/usr/read.rs @@ -11,6 +11,8 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { let pathname = args[1]; + syscall::open(pathname, 0); + match pathname { "/dev/rtc" => { let rtc = CMOS::new().rtc(); From 908e76b5990661e353f686412220f567876343c8 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Tue, 31 Aug 2021 22:00:46 +0200 Subject: [PATCH 02/26] Change syscalls return type --- src/api/syscall.rs | 38 ++++++++++++++++++++++++++------------ src/sys/syscall/mod.rs | 13 ++++++++++--- src/sys/syscall/service.rs | 30 +++++++++++++++--------------- src/usr/read.rs | 2 -- 4 files changed, 51 insertions(+), 32 deletions(-) diff --git a/src/api/syscall.rs b/src/api/syscall.rs index 5968045a3..2200110f6 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -15,28 +15,40 @@ pub fn realtime() -> f64 { f64::from_bits(res as u64) } -pub fn open(path: &str, mode: u8) -> u16 { +pub fn open(path: &str, mode: u8) -> Option { let ptr = path.as_ptr() as usize; let len = path.len() as usize; - let res = unsafe { syscall!(OPEN, ptr, len, mode as usize) }; - res as u16 + let res = unsafe { syscall!(OPEN, ptr, len, mode as usize) } as isize; + if res.is_positive() { + Some(res as usize) + } else { + None + } } -pub fn read(fh: u16, buf: &mut [u8]) -> usize { +pub fn read(fh: usize, buf: &mut [u8]) -> Option { let ptr = buf.as_ptr() as usize; let len = buf.len() as usize; - let res = unsafe { syscall!(READ, fh, ptr, len) }; - res as usize + let res = unsafe { syscall!(READ, fh, ptr, len) } as isize; + if res.is_positive() { + Some(res as usize) + } else { + None + } } -pub fn write(fh: u16, buf: &mut [u8]) -> usize { +pub fn write(fh: usize, buf: &mut [u8]) -> Option { let ptr = buf.as_ptr() as usize; let len = buf.len() as usize; - let res = unsafe { syscall!(WRITE, fh, ptr, len) }; - res as usize + let res = unsafe { syscall!(WRITE, fh, ptr, len) } as isize; + if res.is_positive() { + Some(res as usize) + } else { + None + } } -pub fn close(fh: u16) { +pub fn close(fh: usize) { unsafe { syscall!(CLOSE, fh as usize) }; } @@ -45,7 +57,9 @@ fn test_open() { use crate::sys::fs::{mount_mem, format_mem, File, dismount}; mount_mem(); format_mem(); - assert!(File::create("/test").is_some()); - //assert_eq!(open("/test", 0), 4); + assert!(File::create("/test1").is_some()); + // FIXME: allocator panic + // assert_eq!(open("/test1", 0), Some(4)); + // assert_eq!(open("/test2", 0), None); dismount(); } diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index 34d2750df..345ac0068 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -27,14 +27,21 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { service::open(&path, mode) as usize } number::READ => { - let fh = arg1 as u16; + let fh = arg1; let ptr = arg2 as *mut u8; let len = arg3; let mut buf = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; - service::read(fh, &mut buf) + service::read(fh, &mut buf) as usize + } + number::WRITE => { + let fh = arg1; + let ptr = arg2 as *mut u8; + let len = arg3; + let mut buf = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; + service::write(fh, &mut buf) as usize } number::CLOSE => { - let fh = arg1 as u16; + let fh = arg1; service::close(fh); 0 } diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 2d3a152c9..9a4622689 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -14,34 +14,34 @@ pub fn realtime() -> f64 { sys::clock::realtime() } -pub fn open(path: &str, _mode: u8) -> u16 { +pub fn open(path: &str, _mode: u8) -> isize { if let Some(file) = sys::fs::File::open(path) { if let Ok(fh) = sys::process::create_file_handle(file) { - return fh as u16; + return fh as isize; } } - 0 + -1 } -pub fn read(fh: u16, buf: &mut [u8]) -> usize { - if let Some(mut file) = sys::process::file_handle(fh as usize) { +pub fn read(fh: usize, buf: &mut [u8]) -> isize { + if let Some(mut file) = sys::process::file_handle(fh) { let bytes = file.read(buf); - sys::process::update_file_handle(fh as usize, file); - return bytes; + sys::process::update_file_handle(fh, file); + return bytes as isize; } - 0 + -1 } -pub fn write(fh: u16, buf: &mut [u8]) -> usize { - if let Some(mut file) = sys::process::file_handle(fh as usize) { +pub fn write(fh: usize, buf: &mut [u8]) -> isize { + if let Some(mut file) = sys::process::file_handle(fh) { if let Ok(bytes) = file.write(buf) { - sys::process::update_file_handle(fh as usize, file); - return bytes; + sys::process::update_file_handle(fh, file); + return bytes as isize; } } - 0 + -1 } -pub fn close(fh: u16) { - sys::process::delete_file_handle(fh as usize); +pub fn close(fh: usize) { + sys::process::delete_file_handle(fh); } diff --git a/src/usr/read.rs b/src/usr/read.rs index c2b3ef6fe..089bc7be4 100644 --- a/src/usr/read.rs +++ b/src/usr/read.rs @@ -11,8 +11,6 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { let pathname = args[1]; - syscall::open(pathname, 0); - match pathname { "/dev/rtc" => { let rtc = CMOS::new().rtc(); From 66cabdd634a5f8511f1f872ac9152d33ddf86040 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Tue, 31 Aug 2021 22:36:47 +0200 Subject: [PATCH 03/26] Add stat syscall --- src/api/fs.rs | 13 +++++++++++++ src/api/syscall.rs | 32 +++++++++++++++++++++++--------- src/sys/fs/file.rs | 23 +++++++++++++++++++++++ src/sys/fs/mod.rs | 2 +- src/sys/syscall/mod.rs | 8 ++++++++ src/sys/syscall/number.rs | 1 + src/sys/syscall/service.rs | 10 ++++++++++ 7 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index 32b80bab5..58b2c1d79 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -1,3 +1,4 @@ +use crate::api::syscall; use crate::sys; use alloc::string::{String, ToString}; use alloc::vec; @@ -23,6 +24,17 @@ pub fn read_to_string(path: &str) -> Result { Ok(path) => path, Err(_) => return Err(()), }; + if let Some(stat) = syscall::stat(&path) { + if let Some(fh) = syscall::open(&path, 0) { + let mut buf = vec![0; stat.size() as usize]; + if let Some(bytes) = syscall::read(fh, &mut buf) { + buf.resize(bytes, 0); + return Ok(String::from_utf8_lossy(&buf).to_string()); + } + } + } + Err(()) + /* match sys::fs::File::open(&path) { Some(mut file) => { Ok(file.read_to_string()) @@ -31,6 +43,7 @@ pub fn read_to_string(path: &str) -> Result { Err(()) } } + */ } pub fn read(path: &str) -> Result, ()> { diff --git a/src/api/syscall.rs b/src/api/syscall.rs index 2200110f6..f6111ae3d 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -1,5 +1,6 @@ use crate::syscall; use crate::sys::syscall::number::*; +use crate::sys::fs::FileStat; pub fn sleep(seconds: f64) { unsafe { syscall!(SLEEP, seconds.to_bits()) }; @@ -15,14 +16,27 @@ pub fn realtime() -> f64 { f64::from_bits(res as u64) } +pub fn stat(path: &str) -> Option { + let path_ptr = path.as_ptr() as usize; + let path_len = path.len() as usize; + let mut stat = FileStat::new(); + let stat_ptr = &mut stat as *mut FileStat as usize; + let res = unsafe { syscall!(STAT, path_ptr, path_len, stat_ptr) } as isize; + if res.is_negative() { + None + } else { + Some(stat) + } +} + pub fn open(path: &str, mode: u8) -> Option { let ptr = path.as_ptr() as usize; let len = path.len() as usize; let res = unsafe { syscall!(OPEN, ptr, len, mode as usize) } as isize; - if res.is_positive() { - Some(res as usize) - } else { + if res.is_negative() { None + } else { + Some(res as usize) } } @@ -30,10 +44,10 @@ pub fn read(fh: usize, buf: &mut [u8]) -> Option { let ptr = buf.as_ptr() as usize; let len = buf.len() as usize; let res = unsafe { syscall!(READ, fh, ptr, len) } as isize; - if res.is_positive() { - Some(res as usize) - } else { + if res.is_negative() { None + } else { + Some(res as usize) } } @@ -41,10 +55,10 @@ pub fn write(fh: usize, buf: &mut [u8]) -> Option { let ptr = buf.as_ptr() as usize; let len = buf.len() as usize; let res = unsafe { syscall!(WRITE, fh, ptr, len) } as isize; - if res.is_positive() { - Some(res as usize) - } else { + if res.is_negative() { None + } else { + Some(res as usize) } } diff --git a/src/sys/fs/file.rs b/src/sys/fs/file.rs index e029d7f6e..e6c2bc568 100644 --- a/src/sys/fs/file.rs +++ b/src/sys/fs/file.rs @@ -13,6 +13,25 @@ pub enum SeekFrom { End(i32), } +pub struct FileStat { + size: u32, + time: u64, +} + +impl FileStat { + pub fn new() -> Self { + Self { size: 0, time: 0 } + } + + pub fn size(&self) -> u32 { + self.size + } + + pub fn time(&self) -> u64 { + self.time + } +} + #[derive(Clone)] pub struct File { name: String, @@ -71,6 +90,10 @@ impl File { self.size as usize } + pub fn stat(&self) -> FileStat { + FileStat { size: self.size, time: self.time } + } + pub fn seek(&mut self, pos: SeekFrom) -> Result { let offset = match pos { SeekFrom::Start(i) => i as i32, diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index 57c2d6342..490be03c4 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -7,7 +7,7 @@ mod file; mod read_dir; pub use dir::Dir; -pub use file::{File, SeekFrom}; +pub use file::{File, FileStat, SeekFrom}; pub use block_device::{format_ata, format_mem, is_mounted, mount_ata, mount_mem, dismount}; use block_bitmap::BlockBitmap; diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index 345ac0068..c9e8b62fc 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -1,6 +1,7 @@ pub mod number; pub mod service; +use crate::sys::fs::FileStat; use alloc::string::String; /* @@ -19,6 +20,13 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { number::REALTIME => { service::realtime().to_bits() as usize } + number::STAT => { + let ptr = arg1 as *mut u8; + let len = arg2; + let path = unsafe { String::from_raw_parts(ptr, len, len) }; + let stat = unsafe { &mut *(arg3 as *mut FileStat) }; + service::stat(&path, stat) as usize + } number::OPEN => { let ptr = arg1 as *mut u8; let len = arg2; diff --git a/src/sys/syscall/number.rs b/src/sys/syscall/number.rs index 4b2bd5d7b..4e9c9c181 100644 --- a/src/sys/syscall/number.rs +++ b/src/sys/syscall/number.rs @@ -5,3 +5,4 @@ pub const OPEN: usize = 3; pub const READ: usize = 4; pub const WRITE: usize = 5; pub const CLOSE: usize = 6; +pub const STAT: usize = 7; diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 9a4622689..3e3928279 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -1,4 +1,5 @@ use crate::sys; +use crate::sys::fs::FileStat; pub fn sleep(seconds: f64) { unsafe { asm!("sti") }; // Restore interrupts @@ -14,6 +15,15 @@ pub fn realtime() -> f64 { sys::clock::realtime() } +pub fn stat(path: &str, stat: &mut FileStat) -> isize { + if let Some(file) = sys::fs::File::open(path) { + *stat = file.stat(); + 0 + } else { + -1 + } +} + pub fn open(path: &str, _mode: u8) -> isize { if let Some(file) = sys::fs::File::open(path) { if let Ok(fh) = sys::process::create_file_handle(file) { From d64ed0994f92a61826642de54e6e9f0e02f2ea9d Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 1 Sep 2021 21:01:03 +0200 Subject: [PATCH 04/26] Add file creation --- src/api/syscall.rs | 42 +++++++++++++++++++++++++------------- src/sys/fs/file.rs | 1 + src/sys/fs/mod.rs | 16 +++++++++++++++ src/sys/process.rs | 20 +++++++++--------- src/sys/syscall/mod.rs | 23 ++++++++++----------- src/sys/syscall/service.rs | 24 +++++++++++----------- 6 files changed, 78 insertions(+), 48 deletions(-) diff --git a/src/api/syscall.rs b/src/api/syscall.rs index f6111ae3d..c622fb3dc 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -29,10 +29,10 @@ pub fn stat(path: &str) -> Option { } } -pub fn open(path: &str, mode: u8) -> Option { +pub fn open(path: &str, flags: usize) -> Option { let ptr = path.as_ptr() as usize; let len = path.len() as usize; - let res = unsafe { syscall!(OPEN, ptr, len, mode as usize) } as isize; + let res = unsafe { syscall!(OPEN, ptr, len, flags) } as isize; if res.is_negative() { None } else { @@ -40,10 +40,10 @@ pub fn open(path: &str, mode: u8) -> Option { } } -pub fn read(fh: usize, buf: &mut [u8]) -> Option { +pub fn read(handle: usize, buf: &mut [u8]) -> Option { let ptr = buf.as_ptr() as usize; let len = buf.len() as usize; - let res = unsafe { syscall!(READ, fh, ptr, len) } as isize; + let res = unsafe { syscall!(READ, handle, ptr, len) } as isize; if res.is_negative() { None } else { @@ -51,10 +51,10 @@ pub fn read(fh: usize, buf: &mut [u8]) -> Option { } } -pub fn write(fh: usize, buf: &mut [u8]) -> Option { +pub fn write(handle: usize, buf: &[u8]) -> Option { let ptr = buf.as_ptr() as usize; let len = buf.len() as usize; - let res = unsafe { syscall!(WRITE, fh, ptr, len) } as isize; + let res = unsafe { syscall!(WRITE, handle, ptr, len) } as isize; if res.is_negative() { None } else { @@ -62,18 +62,32 @@ pub fn write(fh: usize, buf: &mut [u8]) -> Option { } } -pub fn close(fh: usize) { - unsafe { syscall!(CLOSE, fh as usize) }; +pub fn close(handle: usize) { + unsafe { syscall!(CLOSE, handle as usize) }; } #[test_case] -fn test_open() { - use crate::sys::fs::{mount_mem, format_mem, File, dismount}; +fn test_file() { + use crate::sys::fs::{mount_mem, format_mem, dismount, OpenFlag}; + use alloc::vec; mount_mem(); format_mem(); - assert!(File::create("/test1").is_some()); - // FIXME: allocator panic - // assert_eq!(open("/test1", 0), Some(4)); - // assert_eq!(open("/test2", 0), None); + + let flags = 0; + assert_eq!(open("/test", flags), None); + + // Write file + let flags = OpenFlag::Create as usize; + assert_eq!(open("/test", flags), Some(4)); + let input = "Hello, world!".as_bytes(); + assert_eq!(write(4, &input), Some(input.len())); + + // Read file + let flags = 0; + assert_eq!(open("/test", flags), Some(5)); + let mut output = vec![0; input.len()]; + assert_eq!(read(5, &mut output), Some(input.len())); + assert_eq!(output, input); + dismount(); } diff --git a/src/sys/fs/file.rs b/src/sys/fs/file.rs index e6c2bc568..383ad2d1e 100644 --- a/src/sys/fs/file.rs +++ b/src/sys/fs/file.rs @@ -13,6 +13,7 @@ pub enum SeekFrom { End(i32), } +#[derive(Debug)] pub struct FileStat { size: u32, time: u64, diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index 490be03c4..64a77034d 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -16,6 +16,22 @@ use crate::sys; use alloc::format; use alloc::string::String; +#[repr(u8)] +pub enum OpenFlag { + Read = 1, + Write = 2, + Create = 4, +} + +pub fn open_file(path: &str, flags: usize) -> Option { + let res = File::open(path); + if res.is_none() && flags & (OpenFlag::Create as usize) != 0 { + File::create(path) + } else { + res + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FileType { Dir = 0, diff --git a/src/sys/process.rs b/src/sys/process.rs index ef2a691ec..ba0ca25ae 100644 --- a/src/sys/process.rs +++ b/src/sys/process.rs @@ -69,26 +69,26 @@ pub fn create_file_handle(file: File) -> Result { let min = 4; // The first 4 file handles are reserved let max = MAX_FILE_HANDLES; let proc = &mut *PROCESS.lock(); - for fh in min..max { - if proc.file_handles[fh].is_none() { - proc.file_handles[fh] = Some(file); - return Ok(fh); + for handle in min..max { + if proc.file_handles[handle].is_none() { + proc.file_handles[handle] = Some(file); + return Ok(handle); } } Err(()) } -pub fn update_file_handle(fh: usize, file: File) { +pub fn update_file_handle(handle: usize, file: File) { let proc = &mut *PROCESS.lock(); - proc.file_handles[fh] = Some(file); + proc.file_handles[handle] = Some(file); } -pub fn delete_file_handle(fh: usize) { +pub fn delete_file_handle(handle: usize) { let proc = &mut *PROCESS.lock(); - proc.file_handles[fh] = None; + proc.file_handles[handle] = None; } -pub fn file_handle(fh: usize) -> Option { +pub fn file_handle(handle: usize) -> Option { let proc = &mut *PROCESS.lock(); - proc.file_handles[fh].clone() + proc.file_handles[handle].clone() } diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index c9e8b62fc..6688c275d 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -2,7 +2,6 @@ pub mod number; pub mod service; use crate::sys::fs::FileStat; -use alloc::string::String; /* * Dispatching system calls @@ -23,34 +22,34 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { number::STAT => { let ptr = arg1 as *mut u8; let len = arg2; - let path = unsafe { String::from_raw_parts(ptr, len, len) }; + let path = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(ptr, len)) }; let stat = unsafe { &mut *(arg3 as *mut FileStat) }; - service::stat(&path, stat) as usize + service::stat(path, stat) as usize } number::OPEN => { let ptr = arg1 as *mut u8; let len = arg2; - let mode = arg3 as u8; - let path = unsafe { String::from_raw_parts(ptr, len, len) }; - service::open(&path, mode) as usize + let flags = arg3; + let path = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(ptr, len)) }; + service::open(path, flags) as usize } number::READ => { - let fh = arg1; + let handle = arg1; let ptr = arg2 as *mut u8; let len = arg3; let mut buf = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; - service::read(fh, &mut buf) as usize + service::read(handle, &mut buf) as usize } number::WRITE => { - let fh = arg1; + let handle = arg1; let ptr = arg2 as *mut u8; let len = arg3; let mut buf = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; - service::write(fh, &mut buf) as usize + service::write(handle, &mut buf) as usize } number::CLOSE => { - let fh = arg1; - service::close(fh); + let handle = arg1; + service::close(handle); 0 } _ => { diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 3e3928279..aeb88a500 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -24,34 +24,34 @@ pub fn stat(path: &str, stat: &mut FileStat) -> isize { } } -pub fn open(path: &str, _mode: u8) -> isize { - if let Some(file) = sys::fs::File::open(path) { - if let Ok(fh) = sys::process::create_file_handle(file) { - return fh as isize; +pub fn open(path: &str, flags: usize) -> isize { + if let Some(file) = sys::fs::open_file(path, flags) { + if let Ok(handle) = sys::process::create_file_handle(file) { + return handle as isize; } } -1 } -pub fn read(fh: usize, buf: &mut [u8]) -> isize { - if let Some(mut file) = sys::process::file_handle(fh) { +pub fn read(handle: usize, buf: &mut [u8]) -> isize { + if let Some(mut file) = sys::process::file_handle(handle) { let bytes = file.read(buf); - sys::process::update_file_handle(fh, file); + sys::process::update_file_handle(handle, file); return bytes as isize; } -1 } -pub fn write(fh: usize, buf: &mut [u8]) -> isize { - if let Some(mut file) = sys::process::file_handle(fh) { +pub fn write(handle: usize, buf: &mut [u8]) -> isize { + if let Some(mut file) = sys::process::file_handle(handle) { if let Ok(bytes) = file.write(buf) { - sys::process::update_file_handle(fh, file); + sys::process::update_file_handle(handle, file); return bytes as isize; } } -1 } -pub fn close(fh: usize) { - sys::process::delete_file_handle(fh); +pub fn close(handle: usize) { + sys::process::delete_file_handle(handle); } From 700a6ba837f47d4c26e8c400c1bb3ec6474ac9b9 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 1 Sep 2021 23:48:59 +0200 Subject: [PATCH 05/26] Use api::fs::read_to_string in more user programs --- src/usr/editor.rs | 18 ++++++------------ src/usr/lisp.rs | 6 +++--- src/usr/read.rs | 6 +++--- src/usr/shell.rs | 6 +++--- src/usr/user.rs | 6 +++--- 5 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/usr/editor.rs b/src/usr/editor.rs index 10b4c57ba..672c51f32 100644 --- a/src/usr/editor.rs +++ b/src/usr/editor.rs @@ -1,4 +1,4 @@ -use crate::{sys, usr}; +use crate::{api, sys, usr}; use crate::api::console::Style; use alloc::format; use alloc::string::{String, ToString}; @@ -20,7 +20,6 @@ struct EditorConfig { } pub struct Editor { - file: Option, pathname: String, lines: Vec, x: usize, @@ -39,23 +38,20 @@ impl Editor { let mut lines = Vec::new(); let config = EditorConfig { tab_size: 4 }; - let file = match sys::fs::File::open(pathname) { - Some(mut file) => { - let contents = file.read_to_string(); + match api::fs::read_to_string(pathname) { + Ok(contents) => { for line in contents.split('\n') { lines.push(line.into()); } - Some(file) }, - None => { + Err(_) => { lines.push(String::new()); - sys::fs::File::create(pathname) } }; let pathname = pathname.into(); - Self { file, pathname, lines, x, y, dx, dy, config } + Self { pathname, lines, x, y, dx, dy, config } } pub fn save(&mut self) -> usr::shell::ExitCode { @@ -68,9 +64,7 @@ impl Editor { } } - if let Some(file) = &mut self.file { - file.seek(sys::fs::SeekFrom::Start(0)).unwrap(); - file.write(contents.as_bytes()).unwrap(); + if api::fs::write(&self.pathname, contents.as_bytes()).is_ok() { let status = format!("Wrote {}L to '{}'", n, self.pathname); self.print_status(&status, "Yellow"); usr::shell::ExitCode::CommandSuccessful diff --git a/src/usr/lisp.rs b/src/usr/lisp.rs index f8a005643..67a0356cc 100644 --- a/src/usr/lisp.rs +++ b/src/usr/lisp.rs @@ -1,4 +1,4 @@ -use crate::{sys, usr}; +use crate::{api, usr}; use crate::api::console::Style; use crate::api::prompt::Prompt; use alloc::string::ToString; @@ -547,11 +547,11 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { }, 2 => { let pathname = args[1]; - if let Some(mut file) = sys::fs::File::open(pathname) { + if let Ok(code) = api::fs::read_to_string(pathname) { let mut block = String::new(); let mut opened = 0; let mut closed = 0; - for line in file.read_to_string().split('\n') { + for line in code.split('\n') { let line = strip_comments(line); if !line.is_empty() { opened += line.matches('(').count(); diff --git a/src/usr/read.rs b/src/usr/read.rs index 089bc7be4..6199c2f12 100644 --- a/src/usr/read.rs +++ b/src/usr/read.rs @@ -1,4 +1,4 @@ -use crate::{sys, usr}; +use crate::{api, sys, usr}; use crate::api::syscall; use crate::sys::cmos::CMOS; use alloc::borrow::ToOwned; @@ -77,8 +77,8 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } } else if pathname.ends_with('/') { usr::list::main(args) - } else if let Some(mut file) = sys::fs::File::open(pathname) { - print!("{}", file.read_to_string()); + } else if let Ok(contents) = api::fs::read_to_string(pathname) { + print!("{}", contents); usr::shell::ExitCode::CommandSuccessful } else { println!("File not found '{}'", pathname); diff --git a/src/usr/shell.rs b/src/usr/shell.rs index c05723f04..939dfb3c5 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -1,5 +1,5 @@ +use crate::{api, sys, usr}; use crate::api::prompt::Prompt; -use crate::{sys, usr}; use crate::api::console::Style; use alloc::format; use alloc::vec::Vec; @@ -221,8 +221,8 @@ pub fn main(args: &[&str]) -> ExitCode { }, 2 => { let pathname = args[1]; - if let Some(mut file) = sys::fs::File::open(pathname) { - for line in file.read_to_string().split('\n') { + if let Ok(contents) = api::fs::read_to_string(pathname) { + for line in contents.split('\n') { if !line.is_empty() { exec(line); } diff --git a/src/usr/user.rs b/src/usr/user.rs index f75c25af4..f2d5551f4 100644 --- a/src/usr/user.rs +++ b/src/usr/user.rs @@ -1,4 +1,4 @@ -use crate::{sys, usr}; +use crate::{api, sys, usr}; use crate::api::syscall; use alloc::collections::btree_map::BTreeMap; use alloc::format; @@ -173,8 +173,8 @@ pub fn hash(password: &str) -> String { fn read_hashed_passwords() -> BTreeMap { let mut hashed_passwords = BTreeMap::new(); - if let Some(mut file) = sys::fs::File::open(PASSWORDS) { - for line in file.read_to_string().split('\n') { + if let Ok(contents) = api::fs::read_to_string(PASSWORDS) { + for line in contents.split('\n') { let mut rows = line.split(','); if let Some(username) = rows.next() { if let Some(hash) = rows.next() { From 7005d7a20c0e453a8434e04f035563d21b3419ce Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Thu, 2 Sep 2021 23:52:19 +0200 Subject: [PATCH 06/26] Use syscalls in fs api --- src/api/fs.rs | 81 ++++++++++++++++++++++++---------------------- src/api/syscall.rs | 6 ++++ src/usr/editor.rs | 7 ++-- 3 files changed, 52 insertions(+), 42 deletions(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index 58b2c1d79..80fcd394d 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -1,9 +1,20 @@ use crate::api::syscall; +use crate::sys::fs::OpenFlag; use crate::sys; use alloc::string::{String, ToString}; use alloc::vec; use alloc::vec::Vec; +pub fn open(path: &str) -> Option { + let flags = 0; + syscall::open(path, flags) +} + +pub fn create(path: &str) -> Option { + let flags = OpenFlag::Create as usize; + syscall::open(path, flags) +} + pub fn canonicalize(path: &str) -> Result { match sys::process::env("HOME") { Some(home) => { @@ -20,64 +31,56 @@ pub fn canonicalize(path: &str) -> Result { } pub fn read_to_string(path: &str) -> Result { + let buf = read(path)?; + Ok(String::from_utf8_lossy(&buf).to_string()) +} + +pub fn read(path: &str) -> Result, ()> { let path = match canonicalize(path) { Ok(path) => path, Err(_) => return Err(()), }; if let Some(stat) = syscall::stat(&path) { - if let Some(fh) = syscall::open(&path, 0) { + if let Some(handle) = open(&path) { let mut buf = vec![0; stat.size() as usize]; - if let Some(bytes) = syscall::read(fh, &mut buf) { + if let Some(bytes) = syscall::read(handle, &mut buf) { buf.resize(bytes, 0); - return Ok(String::from_utf8_lossy(&buf).to_string()); + syscall::close(handle); + return Ok(buf) } } } Err(()) - /* - match sys::fs::File::open(&path) { - Some(mut file) => { - Ok(file.read_to_string()) - }, - None => { - Err(()) - } - } - */ } -pub fn read(path: &str) -> Result, ()> { +pub fn write(path: &str, buf: &[u8]) -> Result { let path = match canonicalize(path) { Ok(path) => path, Err(_) => return Err(()), }; - match sys::fs::File::open(&path) { - Some(mut file) => { - let mut buf = vec![0; file.size()]; - file.read(&mut buf); - Ok(buf) - }, - None => { - Err(()) + if let Some(handle) = create(&path) { + if let Some(bytes) = syscall::write(handle, buf) { + syscall::close(handle); + return Ok(bytes) } } + Err(()) } -pub fn write(path: &str, buf: &[u8]) -> Result<(), ()> { - let path = match canonicalize(path) { - Ok(path) => path, - Err(_) => return Err(()), - }; - let mut file = match sys::fs::File::open(&path) { - None => match sys::fs::File::create(&path) { - None => return Err(()), - Some(file) => file, - }, - Some(file) => file, - }; - // TODO: add File::write_all to split buf if needed - match file.write(buf) { - Ok(_) => Ok(()), - Err(_) => Err(()), - } +#[test_case] +fn test_file() { + use crate::sys::fs::{mount_mem, format_mem, dismount}; + mount_mem(); + format_mem(); + + assert_eq!(open("/test"), None); + + // Write file + let input = "Hello, world!".as_bytes(); + assert_eq!(write("/test", &input), Ok(input.len())); + + // Read file + assert_eq!(read("/test"), Ok(input.to_vec())); + + dismount(); } diff --git a/src/api/syscall.rs b/src/api/syscall.rs index c622fb3dc..cb54179a4 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -89,5 +89,11 @@ fn test_file() { assert_eq!(read(5, &mut output), Some(input.len())); assert_eq!(output, input); + close(4); + close(5); + + assert_eq!(open("/test", flags), Some(4)); + + close(4); dismount(); } diff --git a/src/usr/editor.rs b/src/usr/editor.rs index 672c51f32..6e53d0824 100644 --- a/src/usr/editor.rs +++ b/src/usr/editor.rs @@ -1,4 +1,5 @@ -use crate::{api, sys, usr}; +use crate::{sys, usr}; +use crate::api::fs; use crate::api::console::Style; use alloc::format; use alloc::string::{String, ToString}; @@ -38,7 +39,7 @@ impl Editor { let mut lines = Vec::new(); let config = EditorConfig { tab_size: 4 }; - match api::fs::read_to_string(pathname) { + match fs::read_to_string(pathname) { Ok(contents) => { for line in contents.split('\n') { lines.push(line.into()); @@ -64,7 +65,7 @@ impl Editor { } } - if api::fs::write(&self.pathname, contents.as_bytes()).is_ok() { + if fs::write(&self.pathname, contents.as_bytes()).is_ok() { let status = format!("Wrote {}L to '{}'", n, self.pathname); self.print_status(&status, "Yellow"); usr::shell::ExitCode::CommandSuccessful From 0f9f829d06509327302baec1df3cbc8f7e8156ec Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 3 Sep 2021 23:02:25 +0200 Subject: [PATCH 07/26] Move some functions from sys::fs to api::fs --- src/api/fs.rs | 46 +++++++++++++++++++++++++++++++++++++++------- src/sys/fs/mod.rs | 35 +---------------------------------- src/usr/shell.rs | 9 +++++---- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index 80fcd394d..b6c7e17c3 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -1,18 +1,40 @@ use crate::api::syscall; use crate::sys::fs::OpenFlag; use crate::sys; + +use alloc::format; use alloc::string::{String, ToString}; -use alloc::vec; use alloc::vec::Vec; +use alloc::vec; -pub fn open(path: &str) -> Option { - let flags = 0; - syscall::open(path, flags) +pub fn dirname(pathname: &str) -> &str { + let n = pathname.len(); + let i = match pathname.rfind('/') { + Some(0) => 1, + Some(i) => i, + None => n, + }; + &pathname[0..i] } -pub fn create(path: &str) -> Option { - let flags = OpenFlag::Create as usize; - syscall::open(path, flags) +pub fn filename(pathname: &str) -> &str { + let n = pathname.len(); + let i = match pathname.rfind('/') { + Some(i) => i + 1, + None => 0, + }; + &pathname[i..n] +} + +// Transform "foo.txt" into "/path/to/foo.txt" +pub fn realpath(pathname: &str) -> String { + if pathname.starts_with('/') { + pathname.into() + } else { + let dirname = sys::process::dir(); + let sep = if dirname.ends_with('/') { "" } else { "/" }; + format!("{}{}{}", dirname, sep, pathname) + } } pub fn canonicalize(path: &str) -> Result { @@ -30,6 +52,16 @@ pub fn canonicalize(path: &str) -> Result { } } +pub fn open(path: &str) -> Option { + let flags = 0; + syscall::open(path, flags) +} + +pub fn create(path: &str) -> Option { + let flags = OpenFlag::Create as usize; + syscall::open(path, flags) +} + pub fn read_to_string(path: &str) -> Result { let buf = read(path)?; Ok(String::from_utf8_lossy(&buf).to_string()) diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index 64a77034d..36469a524 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -9,13 +9,10 @@ mod read_dir; pub use dir::Dir; pub use file::{File, FileStat, SeekFrom}; pub use block_device::{format_ata, format_mem, is_mounted, mount_ata, mount_mem, dismount}; +pub use crate::api::fs::{dirname, filename, realpath}; use block_bitmap::BlockBitmap; -use crate::sys; -use alloc::format; -use alloc::string::String; - #[repr(u8)] pub enum OpenFlag { Read = 1, @@ -38,36 +35,6 @@ pub enum FileType { File = 1, } -pub fn dirname(pathname: &str) -> &str { - let n = pathname.len(); - let i = match pathname.rfind('/') { - Some(0) => 1, - Some(i) => i, - None => n, - }; - &pathname[0..i] -} - -pub fn filename(pathname: &str) -> &str { - let n = pathname.len(); - let i = match pathname.rfind('/') { - Some(i) => i + 1, - None => 0, - }; - &pathname[i..n] -} - -// Transform "foo.txt" into "/path/to/foo.txt" -pub fn realpath(pathname: &str) -> String { - if pathname.starts_with('/') { - pathname.into() - } else { - let dirname = sys::process::dir(); - let sep = if dirname.ends_with('/') { "" } else { "/" }; - format!("{}{}{}", dirname, sep, pathname) - } -} - // TODO: All this should be done dynamically // We could store the disk size in the superblock area // And we could maybe also have a counter of allocated block in there to make diff --git a/src/usr/shell.rs b/src/usr/shell.rs index 939dfb3c5..6ceb80d66 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -1,4 +1,5 @@ use crate::{api, sys, usr}; +use crate::api::fs; use crate::api::prompt::Prompt; use crate::api::console::Style; use alloc::format; @@ -34,9 +35,9 @@ fn shell_completer(line: &str) -> Vec { } } } else { // Autocomplete path - let pathname = sys::fs::realpath(args[i]); - let dirname = sys::fs::dirname(&pathname); - let filename = sys::fs::filename(&pathname); + let pathname = fs::realpath(args[i]); + let dirname = fs::dirname(&pathname); + let filename = fs::filename(&pathname); let sep = if dirname.ends_with('/') { "" } else { "/" }; if let Some(dir) = sys::fs::Dir::open(dirname) { for entry in dir.read() { @@ -104,7 +105,7 @@ fn change_dir(args: &[&str]) -> ExitCode { ExitCode::CommandSuccessful }, 2 => { - let mut pathname = sys::fs::realpath(args[1]); + let mut pathname = fs::realpath(args[1]); if pathname.len() > 1 { pathname = pathname.trim_end_matches('/').into(); } From 584dab1e67bfe12bb4dfbcc0cd0903de8ed3a5eb Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 8 Sep 2021 10:16:33 +0200 Subject: [PATCH 08/26] Add FileIO for generic read and write --- src/sys/fs/dir.rs | 53 ++++++++++++++++++------------- src/sys/fs/file.rs | 65 +++++++++++++++++++------------------- src/sys/fs/mod.rs | 40 +++++++++++++++++++++++ src/sys/process.rs | 10 +++--- src/sys/syscall/service.rs | 12 ++++--- src/usr/copy.rs | 3 +- src/usr/delete.rs | 2 +- src/usr/find.rs | 2 +- src/usr/httpd.rs | 3 +- src/usr/install.rs | 1 + src/usr/list.rs | 2 +- src/usr/shell.rs | 2 +- src/usr/user.rs | 1 + src/usr/vga.rs | 3 +- 14 files changed, 129 insertions(+), 70 deletions(-) diff --git a/src/sys/fs/dir.rs b/src/sys/fs/dir.rs index dcb20a825..20391d867 100644 --- a/src/sys/fs/dir.rs +++ b/src/sys/fs/dir.rs @@ -1,4 +1,4 @@ -use super::{dirname, filename, realpath}; +use super::{dirname, filename, realpath, FileIO}; use super::dir_entry::DirEntry; use super::read_dir::ReadDir; use super::block_bitmap::BlockBitmap; @@ -71,7 +71,7 @@ impl Dir { } pub fn find(&self, name: &str) -> Option { - for entry in self.read() { + for entry in self.entries() { if entry.name() == name { return Some(entry); } @@ -94,18 +94,18 @@ impl Dir { } // Read the whole dir to add an entry at the end - let mut read_dir = self.read(); - while read_dir.next().is_some() {} + let mut entries = self.entries(); + while entries.next().is_some() {} // Allocate a new block for the dir if no space left for adding the new entry - let space_left = read_dir.block.data().len() - read_dir.block_data_offset(); + let space_left = entries.block.data().len() - entries.block_data_offset(); let entry_len = DirEntry::empty_len() + name.len(); if entry_len > space_left { - match read_dir.block.alloc_next() { + match entries.block.alloc_next() { None => return None, // Disk is full Some(new_block) => { - read_dir.block = new_block; - read_dir.block_data_offset = 0; + entries.block = new_block; + entries.block_data_offset = 0; }, } } @@ -118,8 +118,8 @@ impl Dir { let entry_time = sys::clock::realtime() as u64; let entry_name = truncate(name, u8::MAX as usize); let n = entry_name.len(); - let i = read_dir.block_data_offset(); - let data = read_dir.block.data_mut(); + let i = entries.block_data_offset(); + let data = entries.block.data_mut(); data[i] = entry_kind; data[(i + 1)..(i + 5)].clone_from_slice(&entry_addr.to_be_bytes()); @@ -128,7 +128,7 @@ impl Dir { data[i + 17] = n as u8; data[(i + 18)..(i + 18 + n)].clone_from_slice(&entry_name.as_bytes()); - read_dir.block.write(); + entries.block.write(); Some(DirEntry::new(*self, kind, entry_addr, entry_size, entry_time, name)) } @@ -136,17 +136,17 @@ impl Dir { // Deleting an entry is done by setting the entry address to 0 // TODO: If the entry is a directory, remove its entries recursively pub fn delete_entry(&mut self, name: &str) -> Result<(), ()> { - let mut read_dir = self.read(); - for entry in &mut read_dir { + let mut entries = self.entries(); + for entry in &mut entries { if entry.name() == name { // Zeroing entry addr - let i = read_dir.block_data_offset() - entry.len(); - let data = read_dir.block.data_mut(); + let i = entries.block_data_offset() - entry.len(); + let data = entries.block.data_mut(); data[i + 1] = 0; data[i + 2] = 0; data[i + 3] = 0; data[i + 4] = 0; - read_dir.block.write(); + entries.block.write(); // Freeing entry blocks let mut entry_block = Block::read(entry.addr()); @@ -166,20 +166,20 @@ impl Dir { pub fn update_entry(&mut self, name: &str, size: u32) { let time = sys::clock::realtime() as u64; - let mut read_dir = self.read(); - for entry in &mut read_dir { + let mut entries = self.entries(); + for entry in &mut entries { if entry.name() == name { - let i = read_dir.block_data_offset() - entry.len(); - let data = read_dir.block.data_mut(); + let i = entries.block_data_offset() - entry.len(); + let data = entries.block.data_mut(); data[(i + 5)..(i + 9)].clone_from_slice(&size.to_be_bytes()); data[(i + 9)..(i + 17)].clone_from_slice(&time.to_be_bytes()); - read_dir.block.write(); + entries.block.write(); break; } } } - pub fn read(&self) -> ReadDir { + pub fn entries(&self) -> ReadDir { ReadDir::from(self.clone()) } @@ -195,6 +195,15 @@ impl Dir { } } +impl FileIO for Dir { + fn read(&mut self, _buf: &mut [u8]) -> Result { + Err(()) + } + fn write(&mut self, _buf: &[u8]) -> Result { + Err(()) + } +} + // Truncate to the given number of bytes at most while respecting char boundaries fn truncate(s: &str, max: usize) -> String { s.char_indices().take_while(|(i, _)| *i <= max).map(|(_, c)| c).collect() diff --git a/src/sys/fs/file.rs b/src/sys/fs/file.rs index 383ad2d1e..4fd8662fc 100644 --- a/src/sys/fs/file.rs +++ b/src/sys/fs/file.rs @@ -1,4 +1,4 @@ -use super::{dirname, filename, realpath}; +use super::{dirname, filename, realpath, FileIO}; use super::dir::Dir; use super::block::Block; use super::dir_entry::DirEntry; @@ -108,9 +108,35 @@ impl File { Ok(self.offset) } + // TODO: add `read_to_end(&self, buf: &mut Vec) -> Result` + + // TODO: `return Result` + pub fn read_to_string(&mut self) -> String { + let mut buf = vec![0; self.size()]; + if let Ok(bytes) = self.read(&mut buf) { + buf.resize(bytes, 0); + } + String::from_utf8_lossy(&buf).to_string() + } + + pub fn addr(&self) -> u32 { + self.addr + } + + pub fn delete(pathname: &str) -> Result<(), ()> { + let pathname = realpath(pathname); + let dirname = dirname(&pathname); + let filename = filename(&pathname); + if let Some(mut dir) = Dir::open(dirname) { + dir.delete_entry(filename) + } else { + Err(()) + } + } +} - // TODO: return `Result` - pub fn read(&mut self, buf: &mut [u8]) -> usize { +impl FileIO for File { + fn read(&mut self, buf: &mut [u8]) -> Result { let buf_len = buf.len(); let mut addr = self.addr; let mut bytes = 0; // Number of bytes read @@ -122,7 +148,7 @@ impl File { for i in 0..data_len { if pos == self.offset { if bytes == buf_len || pos as usize == self.size() { - return bytes; + return Ok(bytes); } buf[bytes] = data[i]; bytes += 1; @@ -132,22 +158,12 @@ impl File { } match block.next() { Some(next_block) => addr = next_block.addr(), - None => return bytes, + None => return Ok(bytes), } } } - // TODO: add `read_to_end(&self, buf: &mut Vec) -> Result` - - // TODO: `return Result` - pub fn read_to_string(&mut self) -> String { - let mut buf = vec![0; self.size()]; - let bytes = self.read(&mut buf); - buf.resize(bytes, 0); - String::from_utf8_lossy(&buf).to_string() - } - - pub fn write(&mut self, buf: &[u8]) -> Result { + fn write(&mut self, buf: &[u8]) -> Result { let buf_len = buf.len(); let mut addr = self.addr; let mut bytes = 0; // Number of bytes written @@ -196,21 +212,6 @@ impl File { self.dir.update_entry(&self.name, self.size); Ok(bytes) } - - pub fn addr(&self) -> u32 { - self.addr - } - - pub fn delete(pathname: &str) -> Result<(), ()> { - let pathname = realpath(pathname); - let dirname = dirname(&pathname); - let filename = filename(&pathname); - if let Some(mut dir) = Dir::open(dirname) { - dir.delete_entry(filename) - } else { - Err(()) - } - } } #[test_case] @@ -254,7 +255,7 @@ fn test_file_read() { let mut file = File::open("/test").unwrap(); let mut output = [0u8; 13]; - assert_eq!(file.read(&mut output), input.len()); + assert_eq!(file.read(&mut output), Ok(input.len())); assert_eq!(input, output); super::dismount(); } diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index 36469a524..70ad93cca 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -35,6 +35,46 @@ pub enum FileType { File = 1, } +#[derive(Clone)] +pub enum Resource { + Dir(Dir), + File(File), + Device(Device), +} + +pub trait FileIO { + fn read(&mut self, buf: &mut [u8]) -> Result; + fn write(&mut self, buf: &[u8]) -> Result; +} + +impl FileIO for Resource { + fn read(&mut self, buf: &mut [u8]) -> Result { + match self { + Resource::Dir(io) => io.read(buf), + Resource::File(io) => io.read(buf), + Resource::Device(io) => io.read(buf), + } + } + fn write(&mut self, buf: &[u8]) -> Result { + match self { + Resource::Dir(io) => io.write(buf), + Resource::File(io) => io.write(buf), + Resource::Device(io) => io.write(buf), + } + } +} + +#[derive(Clone)] +pub enum Device { +} + +impl FileIO for Device { + fn read(&mut self, buf: &mut [u8]) -> Result { + } + fn write(&mut self, buf: &[u8]) -> Result { + } +} + // TODO: All this should be done dynamically // We could store the disk size in the superblock area // And we could maybe also have a counter of allocated block in there to make diff --git a/src/sys/process.rs b/src/sys/process.rs index ba0ca25ae..24c5acb2f 100644 --- a/src/sys/process.rs +++ b/src/sys/process.rs @@ -1,4 +1,4 @@ -use crate::sys::fs::File; +use crate::sys::fs::{Resource, Device}; use alloc::collections::btree_map::BTreeMap; use alloc::string::{String, ToString}; use alloc::vec; @@ -19,7 +19,7 @@ pub struct Process { env: BTreeMap, dir: String, user: Option, - file_handles: Vec>, + file_handles: Vec>, } impl Process { @@ -65,7 +65,7 @@ pub fn set_user(user: &str) { PROCESS.lock().user = Some(user.into()) } -pub fn create_file_handle(file: File) -> Result { +pub fn create_file_handle(file: Resource) -> Result { let min = 4; // The first 4 file handles are reserved let max = MAX_FILE_HANDLES; let proc = &mut *PROCESS.lock(); @@ -78,7 +78,7 @@ pub fn create_file_handle(file: File) -> Result { Err(()) } -pub fn update_file_handle(handle: usize, file: File) { +pub fn update_file_handle(handle: usize, file: Resource) { let proc = &mut *PROCESS.lock(); proc.file_handles[handle] = Some(file); } @@ -88,7 +88,7 @@ pub fn delete_file_handle(handle: usize) { proc.file_handles[handle] = None; } -pub fn file_handle(handle: usize) -> Option { +pub fn file_handle(handle: usize) -> Option { let proc = &mut *PROCESS.lock(); proc.file_handles[handle].clone() } diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index aeb88a500..86fda7672 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -1,5 +1,7 @@ use crate::sys; +use crate::sys::fs::Resource; use crate::sys::fs::FileStat; +use crate::sys::fs::FileIO; pub fn sleep(seconds: f64) { unsafe { asm!("sti") }; // Restore interrupts @@ -26,7 +28,8 @@ pub fn stat(path: &str, stat: &mut FileStat) -> isize { pub fn open(path: &str, flags: usize) -> isize { if let Some(file) = sys::fs::open_file(path, flags) { - if let Ok(handle) = sys::process::create_file_handle(file) { + let resource = Resource::File(file); + if let Ok(handle) = sys::process::create_file_handle(resource) { return handle as isize; } } @@ -35,9 +38,10 @@ pub fn open(path: &str, flags: usize) -> isize { pub fn read(handle: usize, buf: &mut [u8]) -> isize { if let Some(mut file) = sys::process::file_handle(handle) { - let bytes = file.read(buf); - sys::process::update_file_handle(handle, file); - return bytes as isize; + if let Ok(bytes) = file.read(buf) { + sys::process::update_file_handle(handle, file); + return bytes as isize; + } } -1 } diff --git a/src/usr/copy.rs b/src/usr/copy.rs index cc5c918a2..56a265076 100644 --- a/src/usr/copy.rs +++ b/src/usr/copy.rs @@ -1,4 +1,5 @@ use crate::{sys, usr}; +use crate::sys::fs::FileIO; use alloc::vec; pub fn main(args: &[&str]) -> usr::shell::ExitCode { @@ -18,7 +19,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { if let Some(mut source_file) = sys::fs::File::open(source) { if let Some(mut dest_file) = sys::fs::File::create(dest) { let mut buf = vec![0; source_file.size()]; - source_file.read(&mut buf); + source_file.read(&mut buf).ok(); match dest_file.write(&buf) { Ok(_) => { usr::shell::ExitCode::CommandSuccessful diff --git a/src/usr/delete.rs b/src/usr/delete.rs index 00392a8e0..8a43b755d 100644 --- a/src/usr/delete.rs +++ b/src/usr/delete.rs @@ -19,7 +19,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } if let Some(dir) = sys::fs::Dir::open(pathname) { - if dir.read().count() == 0 { + if dir.entries().count() == 0 { if sys::fs::Dir::delete(pathname).is_ok() { usr::shell::ExitCode::CommandSuccessful } else { diff --git a/src/usr/find.rs b/src/usr/find.rs index 0fa3080cf..d79aba3d3 100644 --- a/src/usr/find.rs +++ b/src/usr/find.rs @@ -69,7 +69,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { fn print_matching_lines(path: &str, pattern: &str, state: &mut PrintingState) { if let Some(dir) = sys::fs::Dir::open(path) { state.is_recursive = true; - for file in dir.read() { + for file in dir.entries() { let file_path = format!("{}/{}", path, file.name()); if file.is_dir() { print_matching_lines(&file_path, pattern, state); diff --git a/src/usr/httpd.rs b/src/usr/httpd.rs index 3166c4267..b5da4691c 100644 --- a/src/usr/httpd.rs +++ b/src/usr/httpd.rs @@ -1,6 +1,7 @@ use crate::{sys, usr}; use crate::api::syscall; use crate::api::console::Style; +use crate::sys::fs::FileIO; use alloc::collections::vec_deque::VecDeque; use alloc::format; use alloc::string::{String, ToString}; @@ -100,7 +101,7 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { code = 200; res.push_str("HTTP/1.0 200 OK\r\n"); body = format!("

Index of {}

\r\n", path); - let mut files: Vec<_> = dir.read().collect(); + let mut files: Vec<_> = dir.entries().collect(); files.sort_by_key(|f| f.name()); for file in files { let sep = if path == "/" { "" } else { "/" }; diff --git a/src/usr/install.rs b/src/usr/install.rs index 9a6ef8580..f4e99d2d1 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -1,5 +1,6 @@ use crate::{sys, usr}; use crate::api::console::Style; +use crate::sys::fs::FileIO; use alloc::string::String; pub fn main(_args: &[&str]) -> usr::shell::ExitCode { diff --git a/src/usr/list.rs b/src/usr/list.rs index 38eadcc55..f837a0ee8 100644 --- a/src/usr/list.rs +++ b/src/usr/list.rs @@ -36,7 +36,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } if let Some(dir) = sys::fs::Dir::open(path) { - let mut files: Vec<_> = dir.read().collect(); + let mut files: Vec<_> = dir.entries().collect(); match sort { "name" => files.sort_by_key(|f| f.name()), diff --git a/src/usr/shell.rs b/src/usr/shell.rs index 6ceb80d66..779a1c791 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -40,7 +40,7 @@ fn shell_completer(line: &str) -> Vec { let filename = fs::filename(&pathname); let sep = if dirname.ends_with('/') { "" } else { "/" }; if let Some(dir) = sys::fs::Dir::open(dirname) { - for entry in dir.read() { + for entry in dir.entries() { let name = entry.name(); if name.starts_with(filename) { let end = if entry.is_dir() { "/" } else { "" }; diff --git a/src/usr/user.rs b/src/usr/user.rs index f2d5551f4..33b3872d0 100644 --- a/src/usr/user.rs +++ b/src/usr/user.rs @@ -1,5 +1,6 @@ use crate::{api, sys, usr}; use crate::api::syscall; +use crate::sys::fs::FileIO; use alloc::collections::btree_map::BTreeMap; use alloc::format; use alloc::string::String; diff --git a/src/usr/vga.rs b/src/usr/vga.rs index 23572bf8f..80ceaa89b 100644 --- a/src/usr/vga.rs +++ b/src/usr/vga.rs @@ -1,5 +1,6 @@ use crate::{api, sys, usr}; use crate::api::vga::palette; +use crate::sys::fs::FileIO; use alloc::vec; pub fn main(args: &[&str]) -> usr::shell::ExitCode { @@ -12,7 +13,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() == 4 && args[2] == "font" { if let Some(mut file) = sys::fs::File::open(args[3]) { let mut buf = vec![0; file.size()]; - file.read(&mut buf); + file.read(&mut buf).ok(); if let Ok(font) = api::font::from_bytes(&buf) { sys::vga::set_font(&font); } else { From a8ad47e6f416d606ecb9f11d879a1e5551366e17 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 8 Sep 2021 10:17:11 +0200 Subject: [PATCH 09/26] Write to stdout --- src/api/mod.rs | 5 +++-- src/sys/console.rs | 34 ++++++++++++++++++++++++++++++++++ src/sys/fs/mod.rs | 8 ++++++++ src/sys/process.rs | 6 +++++- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 196423c8b..7cc07c7f4 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,8 +1,9 @@ #[macro_export] macro_rules! print { ($($arg:tt)*) => ({ - // TODO: Use syscall instead - $crate::sys::console::print_fmt(format_args!($($arg)*)); + use alloc::format; + let s = format!("{}", format_args!($($arg)*)); + $crate::api::syscall::write(1, s.as_bytes()); }); } diff --git a/src/sys/console.rs b/src/sys/console.rs index d06616e59..bbe4c43cb 100644 --- a/src/sys/console.rs +++ b/src/sys/console.rs @@ -1,4 +1,5 @@ use crate::sys; +use crate::sys::fs::FileIO; use alloc::string::String; use alloc::string::ToString; use core::fmt; @@ -12,6 +13,39 @@ lazy_static! { pub static ref RAW: Mutex = Mutex::new(false); } +#[derive(Clone)] +pub struct Console; + +impl Console { + pub fn new() -> Self { + Self {} + } +} + +impl FileIO for Console { + fn read(&mut self, buf: &mut [u8]) -> Result { + let input = if buf.len() == 1 { + get_char().to_string() + } else { + get_line() + }; + let mut i = 0; + for b in input.bytes() { + i += 1; + if i == buf.len() { + break; + } + buf[i] = b; + } + Ok(i) + } + fn write(&mut self, buf: &[u8]) -> Result { + let s = String::from_utf8_lossy(buf); + print_fmt(format_args!("{}", s)); + Ok(s.len()) + } +} + pub fn cols() -> usize { if cfg!(feature = "video") { sys::vga::cols() diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index 70ad93cca..d8b0548e0 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -10,6 +10,7 @@ pub use dir::Dir; pub use file::{File, FileStat, SeekFrom}; pub use block_device::{format_ata, format_mem, is_mounted, mount_ata, mount_mem, dismount}; pub use crate::api::fs::{dirname, filename, realpath}; +pub use crate::sys::console::Console; use block_bitmap::BlockBitmap; @@ -66,12 +67,19 @@ impl FileIO for Resource { #[derive(Clone)] pub enum Device { + Console(Console) } impl FileIO for Device { fn read(&mut self, buf: &mut [u8]) -> Result { + match self { + Device::Console(io) => io.read(buf), + } } fn write(&mut self, buf: &[u8]) -> Result { + match self { + Device::Console(io) => io.write(buf), + } } } diff --git a/src/sys/process.rs b/src/sys/process.rs index 24c5acb2f..794a8e413 100644 --- a/src/sys/process.rs +++ b/src/sys/process.rs @@ -1,4 +1,5 @@ use crate::sys::fs::{Resource, Device}; +use crate::sys::console::Console; use alloc::collections::btree_map::BTreeMap; use alloc::string::{String, ToString}; use alloc::vec; @@ -28,7 +29,10 @@ impl Process { let env = BTreeMap::new(); let dir = dir.to_string(); let user = user.map(String::from); - let file_handles = vec![None; MAX_FILE_HANDLES]; + let mut file_handles = vec![None; MAX_FILE_HANDLES]; + file_handles[0] = Some(Resource::Device(Device::Console(Console::new()))); + file_handles[1] = Some(Resource::Device(Device::Console(Console::new()))); + file_handles[2] = Some(Resource::Device(Device::Console(Console::new()))); Self { id, env, dir, user, file_handles } } } From 9541d80baaf6c4a68fc982429db55bbc67089e47 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 8 Sep 2021 10:40:27 +0200 Subject: [PATCH 10/26] Add stdout test --- src/api/syscall.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/syscall.rs b/src/api/syscall.rs index cb54179a4..aba355c64 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -95,5 +95,8 @@ fn test_file() { assert_eq!(open("/test", flags), Some(4)); close(4); + + assert!(write(1, b"Hello, World\n").is_some()); + dismount(); } From 026e792f3e063f9fb0c7bb497b80a709be216db7 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 8 Sep 2021 10:41:37 +0200 Subject: [PATCH 11/26] Disable output --- src/api/syscall.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/syscall.rs b/src/api/syscall.rs index aba355c64..9944dc2d6 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -96,7 +96,7 @@ fn test_file() { close(4); - assert!(write(1, b"Hello, World\n").is_some()); + //assert!(write(1, b"Hello, World\n").is_some()); dismount(); } From 597bb9bc0be20a758a4e88e7b3c665e114739c62 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Wed, 8 Sep 2021 11:57:51 +0200 Subject: [PATCH 12/26] Move FileIO to API --- src/api/fs.rs | 5 +++++ src/sys/fs/mod.rs | 7 +------ src/usr/copy.rs | 2 +- src/usr/httpd.rs | 2 +- src/usr/install.rs | 2 +- src/usr/user.rs | 2 +- src/usr/vga.rs | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index b6c7e17c3..a6c276ad2 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -7,6 +7,11 @@ use alloc::string::{String, ToString}; use alloc::vec::Vec; use alloc::vec; +pub trait FileIO { + fn read(&mut self, buf: &mut [u8]) -> Result; + fn write(&mut self, buf: &[u8]) -> Result; +} + pub fn dirname(pathname: &str) -> &str { let n = pathname.len(); let i = match pathname.rfind('/') { diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index d8b0548e0..f23134848 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -9,7 +9,7 @@ mod read_dir; pub use dir::Dir; pub use file::{File, FileStat, SeekFrom}; pub use block_device::{format_ata, format_mem, is_mounted, mount_ata, mount_mem, dismount}; -pub use crate::api::fs::{dirname, filename, realpath}; +pub use crate::api::fs::{dirname, filename, realpath, FileIO}; pub use crate::sys::console::Console; use block_bitmap::BlockBitmap; @@ -43,11 +43,6 @@ pub enum Resource { Device(Device), } -pub trait FileIO { - fn read(&mut self, buf: &mut [u8]) -> Result; - fn write(&mut self, buf: &[u8]) -> Result; -} - impl FileIO for Resource { fn read(&mut self, buf: &mut [u8]) -> Result { match self { diff --git a/src/usr/copy.rs b/src/usr/copy.rs index 56a265076..8aae7d9d3 100644 --- a/src/usr/copy.rs +++ b/src/usr/copy.rs @@ -1,5 +1,5 @@ use crate::{sys, usr}; -use crate::sys::fs::FileIO; +use crate::api::fs::FileIO; use alloc::vec; pub fn main(args: &[&str]) -> usr::shell::ExitCode { diff --git a/src/usr/httpd.rs b/src/usr/httpd.rs index b5da4691c..1e00722ee 100644 --- a/src/usr/httpd.rs +++ b/src/usr/httpd.rs @@ -1,7 +1,7 @@ use crate::{sys, usr}; use crate::api::syscall; use crate::api::console::Style; -use crate::sys::fs::FileIO; +use crate::api::fs::FileIO; use alloc::collections::vec_deque::VecDeque; use alloc::format; use alloc::string::{String, ToString}; diff --git a/src/usr/install.rs b/src/usr/install.rs index f4e99d2d1..7a7af5975 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -1,6 +1,6 @@ use crate::{sys, usr}; use crate::api::console::Style; -use crate::sys::fs::FileIO; +use crate::api::fs::FileIO; use alloc::string::String; pub fn main(_args: &[&str]) -> usr::shell::ExitCode { diff --git a/src/usr/user.rs b/src/usr/user.rs index 33b3872d0..60d9604f2 100644 --- a/src/usr/user.rs +++ b/src/usr/user.rs @@ -1,6 +1,6 @@ use crate::{api, sys, usr}; use crate::api::syscall; -use crate::sys::fs::FileIO; +use crate::api::fs::FileIO; use alloc::collections::btree_map::BTreeMap; use alloc::format; use alloc::string::String; diff --git a/src/usr/vga.rs b/src/usr/vga.rs index 80ceaa89b..731dce494 100644 --- a/src/usr/vga.rs +++ b/src/usr/vga.rs @@ -1,6 +1,6 @@ use crate::{api, sys, usr}; use crate::api::vga::palette; -use crate::sys::fs::FileIO; +use crate::api::fs::FileIO; use alloc::vec; pub fn main(args: &[&str]) -> usr::shell::ExitCode { From 2ae77e712c700b2ff6bc4c187dd55f9c04080cdf Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Thu, 9 Sep 2021 23:15:38 +0200 Subject: [PATCH 13/26] Add io::stdin and io::stdout to API --- src/api/console.rs | 4 ---- src/api/io.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++ src/api/mod.rs | 3 ++- src/api/prompt.rs | 5 ++--- src/sys/console.rs | 12 +++++------ src/sys/time.rs | 2 +- src/usr/editor.rs | 3 ++- src/usr/install.rs | 5 +++-- src/usr/user.rs | 16 +++++++-------- 9 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 src/api/io.rs diff --git a/src/api/console.rs b/src/api/console.rs index 20bfeb9da..8b6ecb88b 100644 --- a/src/api/console.rs +++ b/src/api/console.rs @@ -79,10 +79,6 @@ fn color_to_bg(name: &str) -> Option { color_to_fg(name).map(|fg| fg + 10) } -pub fn read_char() -> Option { - Some(sys::console::get_char()) -} - pub fn is_printable(c: char) -> bool { if cfg!(feature = "video") { c.is_ascii() && sys::vga::is_printable(c as u8) diff --git a/src/api/io.rs b/src/api/io.rs new file mode 100644 index 000000000..8563dd27a --- /dev/null +++ b/src/api/io.rs @@ -0,0 +1,51 @@ +use crate::api::syscall; + +use alloc::vec; +use alloc::string::{String, ToString}; + +pub struct Stdin; +pub struct Stdout; + +impl Stdin { + fn new() -> Self { + Self {} + } + + pub fn read_char(&self) -> Option { + let mut buf = vec![0; 1]; + if let Some(bytes) = syscall::read(0, &mut buf) { + if bytes > 0 { + return Some(buf[0] as char); + } + } + None + } + + pub fn read_line(&self) -> String { + let mut buf = vec![0; 256]; + if let Some(bytes) = syscall::read(0, &mut buf) { + buf.resize(bytes, 0); + String::from_utf8_lossy(&buf).to_string() + } else { + String::new() + } + } +} + +impl Stdout { + fn new() -> Self { + Self {} + } + + pub fn write(&self, s: &str) { + syscall::write(1, s.as_bytes()); + } +} + +pub fn stdout() -> Stdout { + Stdout::new() +} + +pub fn stdin() -> Stdin { + Stdin::new() +} diff --git a/src/api/mod.rs b/src/api/mod.rs index 7cc07c7f4..b574c6a2f 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -3,7 +3,7 @@ macro_rules! print { ($($arg:tt)*) => ({ use alloc::format; let s = format!("{}", format_args!($($arg)*)); - $crate::api::syscall::write(1, s.as_bytes()); + $crate::api::io::stdout().write(&s); }); } @@ -20,6 +20,7 @@ macro_rules! println { pub mod console; pub mod font; pub mod fs; +pub mod io; pub mod prompt; pub mod regex; pub mod syscall; diff --git a/src/api/prompt.rs b/src/api/prompt.rs index 92a3ec04b..2d766deca 100644 --- a/src/api/prompt.rs +++ b/src/api/prompt.rs @@ -1,5 +1,4 @@ -use crate::api::fs; -use crate::api::console; +use crate::api::{console, fs, io}; use alloc::boxed::Box; use alloc::string::{String, ToString}; use alloc::vec::Vec; @@ -31,7 +30,7 @@ impl Prompt { self.cursor = self.offset; self.line = String::new(); let mut parser = Parser::new(); - while let Some(c) = console::read_char() { + while let Some(c) = io::stdin().read_char() { match c { '\x03' => { // End of Text (^C) println!(); diff --git a/src/sys/console.rs b/src/sys/console.rs index bbe4c43cb..afeef9dee 100644 --- a/src/sys/console.rs +++ b/src/sys/console.rs @@ -25,17 +25,17 @@ impl Console { impl FileIO for Console { fn read(&mut self, buf: &mut [u8]) -> Result { let input = if buf.len() == 1 { - get_char().to_string() + read_char().to_string() } else { - get_line() + read_line() }; let mut i = 0; for b in input.bytes() { - i += 1; if i == buf.len() { break; } buf[i] = b; + i += 1; } Ok(i) } @@ -144,8 +144,7 @@ pub fn drain() { }) } -// TODO: Rename to `read_char()` -pub fn get_char() -> char { +pub fn read_char() -> char { sys::console::disable_echo(); sys::console::enable_raw(); loop { @@ -166,8 +165,7 @@ pub fn get_char() -> char { } } -// TODO: Rename to `read_line()` -pub fn get_line() -> String { +pub fn read_line() -> String { loop { sys::time::halt(); let res = interrupts::without_interrupts(|| { diff --git a/src/sys/time.rs b/src/sys/time.rs index 66b6df194..726fd305e 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -30,7 +30,7 @@ pub fn last_rtc_update() -> usize { } pub fn halt() { - x86_64::instructions::hlt(); + x86_64::instructions::interrupts::enable_and_hlt(); } fn rdtsc() -> u64 { diff --git a/src/usr/editor.rs b/src/usr/editor.rs index 6e53d0824..6e8de47e5 100644 --- a/src/usr/editor.rs +++ b/src/usr/editor.rs @@ -1,6 +1,7 @@ use crate::{sys, usr}; use crate::api::fs; use crate::api::console::Style; +use crate::api::io; use alloc::format; use alloc::string::{String, ToString}; use alloc::vec::Vec; @@ -147,7 +148,7 @@ impl Editor { let mut escape = false; let mut csi = false; loop { - let c = sys::console::get_char(); + let c = io::stdin().read_char().unwrap_or('\0'); print!("\x1b[?25l"); // Disable cursor match c { '\x1B' => { // ESC diff --git a/src/usr/install.rs b/src/usr/install.rs index 7a7af5975..5d0b40635 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -1,6 +1,7 @@ use crate::{sys, usr}; use crate::api::console::Style; use crate::api::fs::FileIO; +use crate::api::io; use alloc::string::String; pub fn main(_args: &[&str]) -> usr::shell::ExitCode { @@ -10,7 +11,7 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { println!(); print!("Proceed? [y/N] "); - if sys::console::get_line().trim() == "y" { + if io::stdin().read_line().trim() == "y" { println!(); if !sys::fs::is_mounted() { @@ -20,7 +21,7 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { println!("{}Formatting disk ...{}", csi_color, csi_reset); print!("Enter path of disk to format: "); - let pathname = sys::console::get_line(); + let pathname = io::stdin().read_line(); let res = usr::disk::main(&["disk", "format", pathname.trim_end()]); if res == usr::shell::ExitCode::CommandError { return res; diff --git a/src/usr/user.rs b/src/usr/user.rs index 60d9604f2..51ca82eed 100644 --- a/src/usr/user.rs +++ b/src/usr/user.rs @@ -1,9 +1,10 @@ use crate::{api, sys, usr}; +use crate::api::io; use crate::api::syscall; use crate::api::fs::FileIO; use alloc::collections::btree_map::BTreeMap; use alloc::format; -use alloc::string::String; +use alloc::string::{String, ToString}; use alloc::vec::Vec; use core::convert::TryInto; use core::str; @@ -20,9 +21,9 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { let username: String = if args.len() == 2 { print!("Username: "); - sys::console::get_line().trim_end().into() + io::stdin().read_line().trim_end().to_string() } else { - args[2].into() + args[2].to_string() }; match args[1] { @@ -49,10 +50,9 @@ pub fn login(username: &str) -> usr::shell::ExitCode { Some(hash) => { print!("Password: "); sys::console::disable_echo(); - let mut password = sys::console::get_line(); + let password = io::stdin().read_line().trim_end().to_string(); sys::console::enable_echo(); println!(); - password.pop(); if !check(&password, &hash) { println!(); syscall::sleep(1.0); @@ -87,10 +87,9 @@ pub fn create(username: &str) -> usr::shell::ExitCode { print!("Password: "); sys::console::disable_echo(); - let mut password = sys::console::get_line(); + let password = io::stdin().read_line().trim_end().to_string(); sys::console::enable_echo(); println!(); - password.pop(); if password.is_empty() { return usr::shell::ExitCode::CommandError; @@ -98,10 +97,9 @@ pub fn create(username: &str) -> usr::shell::ExitCode { print!("Confirm: "); sys::console::disable_echo(); - let mut confirm = sys::console::get_line(); + let confirm = io::stdin().read_line().trim_end().to_string(); sys::console::enable_echo(); println!(); - confirm.pop(); if password != confirm { println!("Password confirmation failed"); From 22c67bc3616e768f97aeb6342c49144642cf3130 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 10 Sep 2021 21:25:32 +0200 Subject: [PATCH 14/26] Add a real /dev/random --- src/api/fs.rs | 25 +++++++++++--- src/sys/console.rs | 2 +- src/sys/fs/dir.rs | 6 +++- src/sys/fs/dir_entry.rs | 58 ++++++++++++++++++++++++++++++- src/sys/fs/file.rs | 26 +------------- src/sys/fs/mod.rs | 71 +++++++++++++++++++++++--------------- src/sys/fs/read_dir.rs | 1 + src/sys/random.rs | 24 +++++++++++++ src/sys/syscall/service.rs | 8 ++--- src/usr/install.rs | 16 +++++++++ src/usr/list.rs | 11 ++++-- src/usr/read.rs | 44 +++++++++++++---------- 12 files changed, 206 insertions(+), 86 deletions(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index a6c276ad2..176595f83 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -1,5 +1,5 @@ use crate::api::syscall; -use crate::sys::fs::OpenFlag; +use crate::sys::fs::{OpenFlag, DeviceType}; use crate::sys; use alloc::format; @@ -57,16 +57,30 @@ pub fn canonicalize(path: &str) -> Result { } } -pub fn open(path: &str) -> Option { +pub fn open_file(path: &str) -> Option { let flags = 0; syscall::open(path, flags) } -pub fn create(path: &str) -> Option { +pub fn create_file(path: &str) -> Option { let flags = OpenFlag::Create as usize; syscall::open(path, flags) } +pub fn open_device(path: &str) -> Option { + let flags = OpenFlag::Device as usize; + syscall::open(path, flags) +} + +pub fn create_device(path: &str, kind: DeviceType) -> Option { + let flags = OpenFlag::Create as usize | OpenFlag::Device as usize; + if let Some(handle) = syscall::open(path, flags) { + let buf = [kind as u8; 1]; + return syscall::write(handle, &buf); + } + None +} + pub fn read_to_string(path: &str) -> Result { let buf = read(path)?; Ok(String::from_utf8_lossy(&buf).to_string()) @@ -78,7 +92,8 @@ pub fn read(path: &str) -> Result, ()> { Err(_) => return Err(()), }; if let Some(stat) = syscall::stat(&path) { - if let Some(handle) = open(&path) { + let res = if stat.is_device() { open_device(&path) } else { open_file(&path) }; + if let Some(handle) = res { let mut buf = vec![0; stat.size() as usize]; if let Some(bytes) = syscall::read(handle, &mut buf) { buf.resize(bytes, 0); @@ -95,7 +110,7 @@ pub fn write(path: &str, buf: &[u8]) -> Result { Ok(path) => path, Err(_) => return Err(()), }; - if let Some(handle) = create(&path) { + if let Some(handle) = create_file(&path) { if let Some(bytes) = syscall::write(handle, buf) { syscall::close(handle); return Ok(bytes) diff --git a/src/sys/console.rs b/src/sys/console.rs index afeef9dee..9f72203a6 100644 --- a/src/sys/console.rs +++ b/src/sys/console.rs @@ -13,7 +13,7 @@ lazy_static! { pub static ref RAW: Mutex = Mutex::new(false); } -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct Console; impl Console { diff --git a/src/sys/fs/dir.rs b/src/sys/fs/dir.rs index 20391d867..3d4704bb0 100644 --- a/src/sys/fs/dir.rs +++ b/src/sys/fs/dir.rs @@ -9,7 +9,7 @@ use crate::sys; use alloc::string::String; use core::convert::From; -#[derive(Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub struct Dir { addr: u32, } @@ -88,6 +88,10 @@ impl Dir { self.create_entry(FileType::Dir, name) } + pub fn create_device(&self, name: &str) -> Option { + self.create_entry(FileType::Device, name) + } + fn create_entry(&self, kind: FileType, name: &str) -> Option { if self.find(name).is_some() { return None; diff --git a/src/sys/fs/dir_entry.rs b/src/sys/fs/dir_entry.rs index b571df7e3..72bae5fc6 100644 --- a/src/sys/fs/dir_entry.rs +++ b/src/sys/fs/dir_entry.rs @@ -1,4 +1,4 @@ -use super::FileType; +use super::{dirname, filename, realpath, FileType}; use super::dir::Dir; use alloc::string::String; @@ -13,6 +13,16 @@ pub struct DirEntry { } impl DirEntry { + pub fn open(pathname: &str) -> Option { + let pathname = realpath(pathname); + let dirname = dirname(&pathname); + let filename = filename(&pathname); + if let Some(dir) = Dir::open(dirname) { + return dir.find(filename); + } + None + } + pub fn new(dir: Dir, kind: FileType, addr: u32, size: u32, time: u64, name: &str) -> Self { let name = String::from(name); Self { dir, kind, addr, size, time, name } @@ -30,6 +40,10 @@ impl DirEntry { Self::empty_len() == self.len() } + pub fn kind(&self) -> FileType { + self.kind + } + pub fn is_dir(&self) -> bool { self.kind == FileType::Dir } @@ -38,6 +52,10 @@ impl DirEntry { self.kind == FileType::File } + pub fn is_device(&self) -> bool { + self.kind == FileType::Device + } + pub fn addr(&self) -> u32 { self.addr } @@ -57,4 +75,42 @@ impl DirEntry { pub fn time(&self) -> u64 { self.time } + + pub fn stat(&self) -> FileStat { + FileStat { kind: self.kind, size: self.size, time: self.time } + } +} + +#[derive(Debug)] +pub struct FileStat { + kind: FileType, + size: u32, + time: u64, +} + +impl FileStat { + pub fn new() -> Self { + Self { kind: FileType::File, size: 0, time: 0 } + } + + pub fn size(&self) -> u32 { + self.size + } + + pub fn time(&self) -> u64 { + self.time + } + + // TODO: Duplicated from dir entry + pub fn is_dir(&self) -> bool { + self.kind == FileType::Dir + } + + pub fn is_file(&self) -> bool { + self.kind == FileType::File + } + + pub fn is_device(&self) -> bool { + self.kind == FileType::Device + } } diff --git a/src/sys/fs/file.rs b/src/sys/fs/file.rs index 4fd8662fc..11e737adb 100644 --- a/src/sys/fs/file.rs +++ b/src/sys/fs/file.rs @@ -13,27 +13,7 @@ pub enum SeekFrom { End(i32), } -#[derive(Debug)] -pub struct FileStat { - size: u32, - time: u64, -} - -impl FileStat { - pub fn new() -> Self { - Self { size: 0, time: 0 } - } - - pub fn size(&self) -> u32 { - self.size - } - - pub fn time(&self) -> u64 { - self.time - } -} - -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct File { name: String, addr: u32, @@ -91,10 +71,6 @@ impl File { self.size as usize } - pub fn stat(&self) -> FileStat { - FileStat { size: self.size, time: self.time } - } - pub fn seek(&mut self, pos: SeekFrom) -> Result { let offset = match pos { SeekFrom::Start(i) => i as i32, diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index f23134848..e888b48a5 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -1,42 +1,74 @@ mod block; mod block_bitmap; mod block_device; +mod device; mod dir; mod dir_entry; mod file; mod read_dir; +pub use device::{Device, DeviceType}; pub use dir::Dir; -pub use file::{File, FileStat, SeekFrom}; +pub use dir_entry::FileStat; +pub use file::{File, SeekFrom}; pub use block_device::{format_ata, format_mem, is_mounted, mount_ata, mount_mem, dismount}; pub use crate::api::fs::{dirname, filename, realpath, FileIO}; -pub use crate::sys::console::Console; use block_bitmap::BlockBitmap; +use dir_entry::DirEntry; #[repr(u8)] pub enum OpenFlag { - Read = 1, - Write = 2, + Read = 1, + Write = 2, Create = 4, + Dir = 8, + Device = 16, } -pub fn open_file(path: &str, flags: usize) -> Option { - let res = File::open(path); - if res.is_none() && flags & (OpenFlag::Create as usize) != 0 { - File::create(path) +impl OpenFlag { + fn is_set(self, flags: usize) -> bool { + flags & (self as usize) != 0 + } +} + +pub fn open(path: &str, flags: usize) -> Option { + if OpenFlag::Dir.is_set(flags) { + let res = Dir::open(path); + if res.is_none() && OpenFlag::Create.is_set(flags) { + Dir::create(path) + } else { + res + }.map(|r| Resource::Dir(r)) + } else if OpenFlag::Device.is_set(flags) { + let res = Device::open(path); + if res.is_none() && OpenFlag::Create.is_set(flags) { + Device::create(path) + } else { + res + }.map(|r| Resource::Device(r)) } else { - res + let res = File::open(path); + if res.is_none() && OpenFlag::Create.is_set(flags) { + File::create(path) + } else { + res + }.map(|r| Resource::File(r)) } } +pub fn stat(pathname: &str) -> Option { + DirEntry::open(pathname).map(|e| e.stat()) +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FileType { Dir = 0, File = 1, + Device = 2, } -#[derive(Clone)] +#[derive(Debug, Clone)] pub enum Resource { Dir(Dir), File(File), @@ -51,6 +83,7 @@ impl FileIO for Resource { Resource::Device(io) => io.read(buf), } } + fn write(&mut self, buf: &[u8]) -> Result { match self { Resource::Dir(io) => io.write(buf), @@ -60,24 +93,6 @@ impl FileIO for Resource { } } -#[derive(Clone)] -pub enum Device { - Console(Console) -} - -impl FileIO for Device { - fn read(&mut self, buf: &mut [u8]) -> Result { - match self { - Device::Console(io) => io.read(buf), - } - } - fn write(&mut self, buf: &[u8]) -> Result { - match self { - Device::Console(io) => io.write(buf), - } - } -} - // TODO: All this should be done dynamically // We could store the disk size in the superblock area // And we could maybe also have a counter of allocated block in there to make diff --git a/src/sys/fs/read_dir.rs b/src/sys/fs/read_dir.rs index ceb46f94d..6a07c15e0 100644 --- a/src/sys/fs/read_dir.rs +++ b/src/sys/fs/read_dir.rs @@ -74,6 +74,7 @@ impl Iterator for ReadDir { let entry_kind = match self.read_u8() { 0 => FileType::Dir, 1 => FileType::File, + 2 => FileType::Device, _ => { self.block_data_offset = offset; // Rewind the cursor break; diff --git a/src/sys/random.rs b/src/sys/random.rs index 31f1d9529..177abd5e4 100644 --- a/src/sys/random.rs +++ b/src/sys/random.rs @@ -1,9 +1,33 @@ +use crate::sys::fs::FileIO; + #[cfg(not(debug_assertions))] use rand_chacha::ChaChaRng; #[cfg(not(debug_assertions))] use rand_core::{RngCore, SeedableRng}; use x86_64::instructions::random::RdRand; +#[derive(Debug, Clone)] +pub struct Random; + +impl Random { + pub fn new() -> Self { + Self {} + } +} + +impl FileIO for Random { + fn read(&mut self, buf: &mut [u8]) -> Result { + let n = buf.len(); + for i in 0..n { + buf[i] = get_u64() as u8; + } + Ok(n) + } + fn write(&mut self, _buf: &[u8]) -> Result { + unimplemented!(); + } +} + // FIXME: Compiling this with debug_assertions generate the following error: // LLVM ERROR: Do not know how to split the result of this operator! #[cfg(not(debug_assertions))] diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 86fda7672..4edbb09b2 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -1,5 +1,4 @@ use crate::sys; -use crate::sys::fs::Resource; use crate::sys::fs::FileStat; use crate::sys::fs::FileIO; @@ -18,8 +17,8 @@ pub fn realtime() -> f64 { } pub fn stat(path: &str, stat: &mut FileStat) -> isize { - if let Some(file) = sys::fs::File::open(path) { - *stat = file.stat(); + if let Some(res) = sys::fs::stat(path) { + *stat = res; 0 } else { -1 @@ -27,8 +26,7 @@ pub fn stat(path: &str, stat: &mut FileStat) -> isize { } pub fn open(path: &str, flags: usize) -> isize { - if let Some(file) = sys::fs::open_file(path, flags) { - let resource = Resource::File(file); + if let Some(resource) = sys::fs::open(path, flags) { if let Ok(handle) = sys::process::create_file_handle(resource) { return handle as isize; } diff --git a/src/usr/install.rs b/src/usr/install.rs index 5d0b40635..75a7e31ca 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -1,6 +1,8 @@ use crate::{sys, usr}; use crate::api::console::Style; use crate::api::fs::FileIO; +use crate::api::fs; +use crate::api::syscall; use crate::api::io; use alloc::string::String; @@ -40,6 +42,20 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { create_dir("/usr"); // User directories create_dir("/var"); // Variables + create_dir("/dev/clk"); // Clocks + let pathname = "/dev/console"; + if syscall::stat(pathname).is_none() { + if fs::create_device(pathname, sys::fs::DeviceType::Console).is_some() { + println!("Created '{}'", pathname); + } + } + let pathname = "/dev/random"; + if syscall::stat(pathname).is_none() { + if fs::create_device(pathname, sys::fs::DeviceType::Random).is_some() { + println!("Created '{}'", pathname); + } + } + copy_file("/ini/boot.sh", include_bytes!("../../dsk/ini/boot.sh")); copy_file("/ini/banner.txt", include_bytes!("../../dsk/ini/banner.txt")); copy_file("/ini/version.txt", include_bytes!("../../dsk/ini/version.txt")); diff --git a/src/usr/list.rs b/src/usr/list.rs index f837a0ee8..00cfa11c5 100644 --- a/src/usr/list.rs +++ b/src/usr/list.rs @@ -54,12 +54,19 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } let width = max_size.to_string().len(); - let csi_color = Style::color("Blue"); + let csi_dir_color = Style::color("Blue"); + let csi_dev_color = Style::color("Yellow"); let csi_reset = Style::reset(); for file in files { let date = OffsetDateTime::from_unix_timestamp(file.time() as i64); - let color = if file.is_dir() { csi_color } else { csi_reset }; + let color = if file.is_dir() { + csi_dir_color + } else if file.is_device() { + csi_dev_color + } else { + csi_reset + }; println!("{:width$} {} {}{}{}", file.size(), date.format("%F %H:%M:%S"), color, file.name(), csi_reset, width = width); } usr::shell::ExitCode::CommandSuccessful diff --git a/src/usr/read.rs b/src/usr/read.rs index 6199c2f12..31e4aa471 100644 --- a/src/usr/read.rs +++ b/src/usr/read.rs @@ -1,4 +1,5 @@ use crate::{api, sys, usr}; +use crate::api::fs; use crate::api::syscall; use crate::sys::cmos::CMOS; use alloc::borrow::ToOwned; @@ -29,19 +30,6 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { println!("{:.6}", syscall::uptime()); usr::shell::ExitCode::CommandSuccessful }, - "/dev/random" => { - loop { - // Generate ASCII graphic chars - let i = (sys::random::get_u32() % (0x72 - 0x20)) + 0x20; - if let Some(c) = core::char::from_u32(i) { - print!("{}", c); - } - if sys::console::end_of_text() { - println!(); - return usr::shell::ExitCode::CommandSuccessful; - } - } - }, _ => { if pathname.starts_with("/net/") { // Examples: @@ -75,11 +63,31 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } } } - } else if pathname.ends_with('/') { - usr::list::main(args) - } else if let Ok(contents) = api::fs::read_to_string(pathname) { - print!("{}", contents); - usr::shell::ExitCode::CommandSuccessful + } else if let Some(stat) = syscall::stat(pathname) { + if stat.is_file() { + if let Ok(contents) = api::fs::read_to_string(pathname) { + print!("{}", contents); + usr::shell::ExitCode::CommandSuccessful + } else { + println!("Could not read '{}'", pathname); + usr::shell::ExitCode::CommandError + } + } else if stat.is_dir() { + usr::list::main(args) + } else if stat.is_device() { + loop { + if let Ok(bytes) = fs::read(pathname) { + print!("{}", bytes[0] as char); + } + if sys::console::end_of_text() { + println!(); + return usr::shell::ExitCode::CommandSuccessful; + } + } + } else { + println!("Could not read type of '{}'", pathname); + usr::shell::ExitCode::CommandError + } } else { println!("File not found '{}'", pathname); usr::shell::ExitCode::CommandError From 15f08eb3d005550fd9657299874cbb3c77726c53 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 10 Sep 2021 21:32:08 +0200 Subject: [PATCH 15/26] Fix test --- src/api/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index 176595f83..0f4e7fbad 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -125,7 +125,7 @@ fn test_file() { mount_mem(); format_mem(); - assert_eq!(open("/test"), None); + assert_eq!(open_file("/test"), None); // Write file let input = "Hello, world!".as_bytes(); From ddf5dcd19cea4fc5225553c897907ce04c94111e Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 10 Sep 2021 21:37:17 +0200 Subject: [PATCH 16/26] Add missing device file --- src/sys/fs/device.rs | 76 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/sys/fs/device.rs diff --git a/src/sys/fs/device.rs b/src/sys/fs/device.rs new file mode 100644 index 000000000..f49eb4fd8 --- /dev/null +++ b/src/sys/fs/device.rs @@ -0,0 +1,76 @@ +use super::{dirname, filename, realpath, FileIO}; +use super::dir::Dir; +use super::file::File; +use super::block::Block; + +use crate::sys::console::Console; +use crate::sys::random::Random; + +#[repr(u8)] +pub enum DeviceType { + File = 0, + Console = 1, + Random = 2, +} + +#[derive(Debug, Clone)] +pub enum Device { + File(File), + Console(Console), + Random(Random), +} + +impl Device { + fn new(i: u8) -> Self { + match i { + i if i == DeviceType::Console as u8 => Device::Console(Console::new()), + i if i == DeviceType::Random as u8 => Device::Random(Random::new()), + _ => unimplemented!(), + } + } + + pub fn create(pathname: &str) -> Option { + let pathname = realpath(pathname); + let dirname = dirname(&pathname); + let filename = filename(&pathname); + if let Some(dir) = Dir::open(dirname) { + if let Some(dir_entry) = dir.create_device(filename) { + return Some(Device::File(dir_entry.into())) + } + } + None + } + + pub fn open(pathname: &str) -> Option { + let pathname = realpath(pathname); + let dirname = dirname(&pathname); + let filename = filename(&pathname); + if let Some(dir) = Dir::open(dirname) { + if let Some(dir_entry) = dir.find(filename) { + if dir_entry.is_device() { + let block = Block::read(dir_entry.addr()); + let data = block.data(); + return Some(Self::new(data[0])); + } + } + } + None + } +} + +impl FileIO for Device { + fn read(&mut self, buf: &mut [u8]) -> Result { + match self { + Device::File(io) => io.read(buf), + Device::Console(io) => io.read(buf), + Device::Random(io) => io.read(buf), + } + } + fn write(&mut self, buf: &[u8]) -> Result { + match self { + Device::File(io) => io.write(buf), + Device::Console(io) => io.write(buf), + Device::Random(io) => io.write(buf), + } + } +} From 524d977770ff0a5f729a8ed2c6a78143e4d1f0f2 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 11 Sep 2021 09:50:04 +0200 Subject: [PATCH 17/26] Refactor stdin read --- src/sys/console.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/sys/console.rs b/src/sys/console.rs index 9f72203a6..2ed170953 100644 --- a/src/sys/console.rs +++ b/src/sys/console.rs @@ -24,25 +24,21 @@ impl Console { impl FileIO for Console { fn read(&mut self, buf: &mut [u8]) -> Result { - let input = if buf.len() == 1 { + let s = if buf.len() == 1 { read_char().to_string() } else { read_line() }; - let mut i = 0; - for b in input.bytes() { - if i == buf.len() { - break; - } - buf[i] = b; - i += 1; - } - Ok(i) + let n = s.len(); + buf[0..n].copy_from_slice(s.as_bytes()); + Ok(n) } + fn write(&mut self, buf: &[u8]) -> Result { let s = String::from_utf8_lossy(buf); + let n = s.len(); print_fmt(format_args!("{}", s)); - Ok(s.len()) + Ok(n) } } From 48f4c4dd8c273e0aa47e5742457b0153fd8cdda2 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 11 Sep 2021 09:52:19 +0200 Subject: [PATCH 18/26] Truncate read_line result if larger than buf --- src/sys/console.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sys/console.rs b/src/sys/console.rs index 2ed170953..aa52a0892 100644 --- a/src/sys/console.rs +++ b/src/sys/console.rs @@ -24,11 +24,12 @@ impl Console { impl FileIO for Console { fn read(&mut self, buf: &mut [u8]) -> Result { - let s = if buf.len() == 1 { + let mut s = if buf.len() == 1 { read_char().to_string() } else { read_line() }; + s.truncate(buf.len()); let n = s.len(); buf[0..n].copy_from_slice(s.as_bytes()); Ok(n) From 61b54a0769e285588294d75d82140c4d3cca62cc Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 11 Sep 2021 11:17:42 +0200 Subject: [PATCH 19/26] Use fs::read and fs::write to copy files --- src/usr/copy.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/usr/copy.rs b/src/usr/copy.rs index 8aae7d9d3..f519aab80 100644 --- a/src/usr/copy.rs +++ b/src/usr/copy.rs @@ -1,6 +1,5 @@ -use crate::{sys, usr}; -use crate::api::fs::FileIO; -use alloc::vec; +use crate::usr; +use crate::api::fs; pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() != 3 { @@ -16,21 +15,11 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { return usr::shell::ExitCode::CommandError; } - if let Some(mut source_file) = sys::fs::File::open(source) { - if let Some(mut dest_file) = sys::fs::File::create(dest) { - let mut buf = vec![0; source_file.size()]; - source_file.read(&mut buf).ok(); - match dest_file.write(&buf) { - Ok(_) => { - usr::shell::ExitCode::CommandSuccessful - }, - Err(()) => { - println!("Could not write to '{}'", dest); - usr::shell::ExitCode::CommandError - } - } + if let Ok(contents) = fs::read(source) { + if fs::write(dest, &contents).is_ok() { + usr::shell::ExitCode::CommandSuccessful } else { - println!("Permission denied to write to '{}'", dest); + println!("Could not write to '{}'", dest); usr::shell::ExitCode::CommandError } } else { From 95ab221ee020bd8c4ceb34b41251530f8d594f23 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 11 Sep 2021 11:28:06 +0200 Subject: [PATCH 20/26] Use fs::read for user password database --- src/usr/user.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/usr/user.rs b/src/usr/user.rs index 51ca82eed..4cf184840 100644 --- a/src/usr/user.rs +++ b/src/usr/user.rs @@ -1,7 +1,7 @@ use crate::{api, sys, usr}; +use crate::api::fs; use crate::api::io; use crate::api::syscall; -use crate::api::fs::FileIO; use alloc::collections::btree_map::BTreeMap; use alloc::format; use alloc::string::{String, ToString}; @@ -194,17 +194,10 @@ fn save_hashed_password(username: &str, hash: &str) -> Result { hashed_passwords.remove(username); hashed_passwords.insert(username.into(), hash.into()); - let mut file = match sys::fs::File::open(PASSWORDS) { - None => match sys::fs::File::create(PASSWORDS) { - None => return Err(()), - Some(file) => file, - }, - Some(file) => file, - }; - - let mut contents = String::new(); + let mut csv = String::new(); for (u, h) in hashed_passwords { - contents.push_str(&format!("{},{}\n", u, h)); + csv.push_str(&format!("{},{}\n", u, h)); } - file.write(contents.as_bytes()) + + fs::write(PASSWORDS, csv.as_bytes()) } From 3b233146ce855f8f91cff538bf4a8f0ba20269f1 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 11 Sep 2021 11:28:29 +0200 Subject: [PATCH 21/26] Use fs::read for vga command --- src/usr/vga.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/usr/vga.rs b/src/usr/vga.rs index 731dce494..36fbd4bce 100644 --- a/src/usr/vga.rs +++ b/src/usr/vga.rs @@ -1,7 +1,6 @@ use crate::{api, sys, usr}; use crate::api::vga::palette; -use crate::api::fs::FileIO; -use alloc::vec; +use crate::api::fs; pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() == 1 { @@ -11,9 +10,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { match args[1] { "set" => { if args.len() == 4 && args[2] == "font" { - if let Some(mut file) = sys::fs::File::open(args[3]) { - let mut buf = vec![0; file.size()]; - file.read(&mut buf).ok(); + if let Ok(buf) = fs::read(args[3]) { if let Ok(font) = api::font::from_bytes(&buf) { sys::vga::set_font(&font); } else { @@ -22,8 +19,8 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } } } else if args.len() == 4 && args[2] == "palette" { - if let Some(mut file) = sys::fs::File::open(args[3]) { - if let Ok(palette) = palette::from_csv(&file.read_to_string()) { + if let Ok(csv) = fs::read_to_string(args[3]) { + if let Ok(palette) = palette::from_csv(&csv) { sys::vga::set_palette(palette); // TODO: Instead of calling a kernel function we could // use the following ANSI OSC command to set a palette: From 85368ff16fa965f74d0c31b98a49ec9f12a62c93 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 11 Sep 2021 13:06:31 +0200 Subject: [PATCH 22/26] Use api::syscall::stat instead of sys::fs::File::open --- src/usr/delete.rs | 3 ++- src/usr/find.rs | 3 ++- src/usr/install.rs | 25 +++++++++++-------------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/usr/delete.rs b/src/usr/delete.rs index 8a43b755d..12b8ff7a9 100644 --- a/src/usr/delete.rs +++ b/src/usr/delete.rs @@ -1,4 +1,5 @@ use crate::{sys, usr}; +use crate::api::syscall; pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() != 2 { @@ -30,7 +31,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { println!("Directory '{}' not empty", pathname); usr::shell::ExitCode::CommandError } - } else if sys::fs::File::open(pathname).is_some() { + } else if syscall::stat(pathname).is_some() { if sys::fs::File::delete(pathname).is_ok() { usr::shell::ExitCode::CommandSuccessful } else { diff --git a/src/usr/find.rs b/src/usr/find.rs index d79aba3d3..4a729cc26 100644 --- a/src/usr/find.rs +++ b/src/usr/find.rs @@ -1,5 +1,6 @@ use crate::{sys, usr}; use crate::api::fs; +use crate::api::syscall; use crate::api::regex::Regex; use crate::api::console::Style; @@ -77,7 +78,7 @@ fn print_matching_lines(path: &str, pattern: &str, state: &mut PrintingState) { print_matching_lines_in_file(&file_path, pattern, state); } } - } else if sys::fs::File::open(path).is_some() { + } else if syscall::stat(path).is_some() { print_matching_lines_in_file(&path, pattern, state); } } diff --git a/src/usr/install.rs b/src/usr/install.rs index 75a7e31ca..9c64ad8aa 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -1,9 +1,8 @@ use crate::{sys, usr}; use crate::api::console::Style; -use crate::api::fs::FileIO; use crate::api::fs; -use crate::api::syscall; use crate::api::io; +use crate::api::syscall; use alloc::string::String; pub fn main(_args: &[&str]) -> usr::shell::ExitCode { @@ -99,21 +98,19 @@ fn create_dir(pathname: &str) { } fn copy_file(pathname: &str, buf: &[u8]) { - if sys::fs::File::open(pathname).is_some() { + if syscall::stat(pathname).is_some() { return; } - if let Some(mut file) = sys::fs::File::create(pathname) { - if pathname.ends_with(".txt") { - if let Ok(text) = String::from_utf8(buf.to_vec()) { - let text = text.replace("{x.x.x}", env!("CARGO_PKG_VERSION")); - file.write(text.as_bytes()).unwrap(); - } else { - file.write(buf).unwrap(); - } + if pathname.ends_with(".txt") { + if let Ok(text) = String::from_utf8(buf.to_vec()) { + let text = text.replace("{x.x.x}", env!("CARGO_PKG_VERSION")); + fs::write(pathname, text.as_bytes()).ok(); } else { - file.write(buf).unwrap(); + fs::write(pathname, buf).ok(); } - // TODO: add File::write_all to split buf if needed - println!("Copied '{}'", pathname); + } else { + fs::write(pathname, buf).ok(); } + // TODO: add File::write_all to split buf if needed + println!("Copied '{}'", pathname); } From e9529259a4430b5394b2f2b2401a17dd1dd6aae5 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 12 Sep 2021 09:57:20 +0200 Subject: [PATCH 23/26] Use fs::read and fs::write in httpd --- src/usr/httpd.rs | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/src/usr/httpd.rs b/src/usr/httpd.rs index 1e00722ee..ad07c62fa 100644 --- a/src/usr/httpd.rs +++ b/src/usr/httpd.rs @@ -1,7 +1,7 @@ use crate::{sys, usr}; use crate::api::syscall; +use crate::api::fs; use crate::api::console::Style; -use crate::api::fs::FileIO; use alloc::collections::vec_deque::VecDeque; use alloc::format; use alloc::string::{String, ToString}; @@ -92,10 +92,10 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { res.push_str(&format!("Location: {}\r\n", path.trim_end_matches('/'))); body = "

Moved Permanently

\r\n".to_string(); mime = "text/html"; - } else if let Some(mut file) = sys::fs::File::open(path) { + } else if let Ok(contents) = fs::read_to_string(path) { code = 200; res.push_str("HTTP/1.0 200 OK\r\n"); - body = file.read_to_string().replace("\n", "\r\n"); + body = contents.replace("\n", "\r\n"); mime = "text/plain"; } else if let Some(dir) = sys::fs::Dir::open(path) { code = 200; @@ -130,31 +130,19 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { res.push_str("HTTP/1.0 200 OK\r\n"); } } else { // Write file - let maybe_file = match sys::fs::File::open(path) { - Some(file) => Some(file), - None => sys::fs::File::create(path), - }; - match maybe_file { - Some(mut file) => { - if file.write(contents.as_bytes()).is_ok() { - code = 200; - res.push_str("HTTP/1.0 200 OK\r\n"); - } else { - code = 500; - res.push_str("HTTP/1.0 500 Internal Server Error\r\n"); - } - }, - None => { - code = 403; - res.push_str("HTTP/1.0 403 Forbidden\r\n"); - } + if fs::write(path, contents.as_bytes()).is_ok() { + code = 200; + res.push_str("HTTP/1.0 200 OK\r\n"); + } else { + code = 500; + res.push_str("HTTP/1.0 500 Internal Server Error\r\n"); } } body = "".to_string(); mime = "text/plain"; }, "DELETE" => { - if sys::fs::File::open(path).is_some() { + if syscall::stat(path).is_some() { if sys::fs::File::delete(path).is_ok() { code = 200; res.push_str("HTTP/1.0 200 OK\r\n"); From fd4a59e9e79830abcc1b24be4096f98123dc3564 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 12 Sep 2021 20:05:14 +0200 Subject: [PATCH 24/26] Add RNG to API --- src/api/mod.rs | 1 + src/api/random.rs | 22 ++++++++++++++++++++++ src/usr/host.rs | 5 +++-- src/usr/http.rs | 3 ++- src/usr/tcp.rs | 3 ++- src/usr/user.rs | 3 ++- 6 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 src/api/random.rs diff --git a/src/api/mod.rs b/src/api/mod.rs index b574c6a2f..1fcd91ae1 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -22,6 +22,7 @@ pub mod font; pub mod fs; pub mod io; pub mod prompt; +pub mod random; pub mod regex; pub mod syscall; pub mod vga; diff --git a/src/api/random.rs b/src/api/random.rs new file mode 100644 index 000000000..8a77c64d5 --- /dev/null +++ b/src/api/random.rs @@ -0,0 +1,22 @@ +use crate::api::syscall; +use crate::api::fs; + +pub fn get_u64() -> u64 { + let mut buf = [0; 8]; + if let Some(handle) = fs::open_device("/dev/random") { + if syscall::read(handle, &mut buf).is_some() { + return u64::from_be_bytes(buf); + } + } + 0 +} + +pub fn get_u16() -> u16 { + let mut buf = [0; 2]; + if let Some(handle) = fs::open_device("/dev/random") { + if syscall::read(handle, &mut buf).is_some() { + return u16::from_be_bytes(buf); + } + } + 0 +} diff --git a/src/usr/host.rs b/src/usr/host.rs index 38dca1c0e..621adc9f8 100644 --- a/src/usr/host.rs +++ b/src/usr/host.rs @@ -1,5 +1,6 @@ use crate::{sys, usr}; use crate::api::syscall; +use crate::api::random; use alloc::vec; use alloc::vec::Vec; use bit_field::BitField; @@ -59,7 +60,7 @@ impl Message { pub fn query(qname: &str, qtype: QueryType, qclass: QueryClass) -> Self { let mut datagram = Vec::new(); - let id = sys::random::get_u16(); + let id = random::get_u16(); for b in id.to_be_bytes().iter() { datagram.push(*b); // Transaction ID } @@ -125,7 +126,7 @@ pub fn resolve(name: &str) -> Result { let dns_port = 53; let server = IpEndpoint::new(dns_address, dns_port); - let local_port = 49152 + sys::random::get_u16() % 16384; + let local_port = 49152 + random::get_u16() % 16384; let client = IpEndpoint::new(IpAddress::Unspecified, local_port); let qname = name; diff --git a/src/usr/http.rs b/src/usr/http.rs index 034447898..4671bfcff 100644 --- a/src/usr/http.rs +++ b/src/usr/http.rs @@ -1,5 +1,6 @@ use crate::{sys, usr}; use crate::api::syscall; +use crate::api::random; use alloc::borrow::ToOwned; use alloc::string::{String, ToString}; use alloc::vec; @@ -133,7 +134,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { state = match state { State::Connect if !socket.is_active() => { - let local_port = 49152 + sys::random::get_u16() % 16384; + let local_port = 49152 + random::get_u16() % 16384; if is_verbose { println!("* Connecting to {}:{}", address, url.port); } diff --git a/src/usr/tcp.rs b/src/usr/tcp.rs index a09b1763a..85b2e85d8 100644 --- a/src/usr/tcp.rs +++ b/src/usr/tcp.rs @@ -1,5 +1,6 @@ use crate::{sys, usr}; use crate::api::syscall; +use crate::api::random; use alloc::borrow::ToOwned; use alloc::string::{String, ToString}; use alloc::vec; @@ -94,7 +95,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { state = match state { State::Connect if !socket.is_active() => { - let local_port = 49152 + sys::random::get_u16() % 16384; + let local_port = 49152 + random::get_u16() % 16384; println!("Connecting to {}:{}", address, port); if socket.connect((address, port), local_port).is_err() { println!("Could not connect to {}:{}", address, port); diff --git a/src/usr/user.rs b/src/usr/user.rs index 4cf184840..b23b9e68e 100644 --- a/src/usr/user.rs +++ b/src/usr/user.rs @@ -1,6 +1,7 @@ use crate::{api, sys, usr}; use crate::api::fs; use crate::api::io; +use crate::api::random; use crate::api::syscall; use alloc::collections::btree_map::BTreeMap; use alloc::format; @@ -147,7 +148,7 @@ pub fn hash(password: &str) -> String { // Generating salt for i in 0..2 { - let num = sys::random::get_u64(); + let num = random::get_u64(); let buf = num.to_be_bytes(); let n = buf.len(); for j in 0..n { From a1fbb3b676b2f52f08ef2f697f281a17a8927389 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 13 Sep 2021 20:11:15 +0200 Subject: [PATCH 25/26] Add fs::open_dir and fs::create_dir --- src/api/fs.rs | 10 ++++++++++ src/usr/httpd.rs | 10 +++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index 0f4e7fbad..28b5b254a 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -67,6 +67,16 @@ pub fn create_file(path: &str) -> Option { syscall::open(path, flags) } +pub fn open_dir(path: &str) -> Option { + let flags = OpenFlag::Dir as usize; + syscall::open(path, flags) +} + +pub fn create_dir(path: &str) -> Option { + let flags = OpenFlag::Create as usize | OpenFlag::Dir as usize; + syscall::open(path, flags) +} + pub fn open_device(path: &str) -> Option { let flags = OpenFlag::Device as usize; syscall::open(path, flags) diff --git a/src/usr/httpd.rs b/src/usr/httpd.rs index ad07c62fa..d74268141 100644 --- a/src/usr/httpd.rs +++ b/src/usr/httpd.rs @@ -119,15 +119,15 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { "PUT" => { if path.ends_with('/') { // Write directory let path = path.trim_end_matches('/'); - if sys::fs::Dir::open(path).is_some() { + if syscall::stat(path).is_some() { code = 403; res.push_str("HTTP/1.0 403 Forbidden\r\n"); - } else if sys::fs::Dir::create(path).is_none() { - code = 500; - res.push_str("HTTP/1.0 500 Internal Server Error\r\n"); - } else { + } else if fs::create_dir(path).is_some() { code = 200; res.push_str("HTTP/1.0 200 OK\r\n"); + } else { + code = 500; + res.push_str("HTTP/1.0 500 Internal Server Error\r\n"); } } else { // Write file if fs::write(path, contents.as_bytes()).is_ok() { From fc28b7cba93a336d11bd68527fadc439fd36b604 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 13 Sep 2021 20:16:38 +0200 Subject: [PATCH 26/26] Add fs::exists --- src/api/fs.rs | 4 ++++ src/usr/delete.rs | 4 ++-- src/usr/find.rs | 3 +-- src/usr/httpd.rs | 4 ++-- src/usr/install.rs | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index 28b5b254a..9f2a3284c 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -57,6 +57,10 @@ pub fn canonicalize(path: &str) -> Result { } } +pub fn exists(path: &str) -> bool { + syscall::stat(path).is_some() +} + pub fn open_file(path: &str) -> Option { let flags = 0; syscall::open(path, flags) diff --git a/src/usr/delete.rs b/src/usr/delete.rs index 12b8ff7a9..3f68b54c0 100644 --- a/src/usr/delete.rs +++ b/src/usr/delete.rs @@ -1,5 +1,5 @@ use crate::{sys, usr}; -use crate::api::syscall; +use crate::api::fs; pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() != 2 { @@ -31,7 +31,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { println!("Directory '{}' not empty", pathname); usr::shell::ExitCode::CommandError } - } else if syscall::stat(pathname).is_some() { + } else if fs::exists(pathname) { if sys::fs::File::delete(pathname).is_ok() { usr::shell::ExitCode::CommandSuccessful } else { diff --git a/src/usr/find.rs b/src/usr/find.rs index 4a729cc26..bef495ef6 100644 --- a/src/usr/find.rs +++ b/src/usr/find.rs @@ -1,6 +1,5 @@ use crate::{sys, usr}; use crate::api::fs; -use crate::api::syscall; use crate::api::regex::Regex; use crate::api::console::Style; @@ -78,7 +77,7 @@ fn print_matching_lines(path: &str, pattern: &str, state: &mut PrintingState) { print_matching_lines_in_file(&file_path, pattern, state); } } - } else if syscall::stat(path).is_some() { + } else if fs::exists(path) { print_matching_lines_in_file(&path, pattern, state); } } diff --git a/src/usr/httpd.rs b/src/usr/httpd.rs index d74268141..60c7b2087 100644 --- a/src/usr/httpd.rs +++ b/src/usr/httpd.rs @@ -119,7 +119,7 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { "PUT" => { if path.ends_with('/') { // Write directory let path = path.trim_end_matches('/'); - if syscall::stat(path).is_some() { + if fs::exists(path) { code = 403; res.push_str("HTTP/1.0 403 Forbidden\r\n"); } else if fs::create_dir(path).is_some() { @@ -142,7 +142,7 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { mime = "text/plain"; }, "DELETE" => { - if syscall::stat(path).is_some() { + if fs::exists(path) { if sys::fs::File::delete(path).is_ok() { code = 200; res.push_str("HTTP/1.0 200 OK\r\n"); diff --git a/src/usr/install.rs b/src/usr/install.rs index 9c64ad8aa..ad4215515 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -98,7 +98,7 @@ fn create_dir(pathname: &str) { } fn copy_file(pathname: &str, buf: &[u8]) { - if syscall::stat(pathname).is_some() { + if fs::exists(pathname) { return; } if pathname.ends_with(".txt") {