diff --git a/src/api/fs.rs b/src/api/fs.rs index cb5e8cc1..d096a778 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -42,21 +42,6 @@ pub fn realpath(pathname: &str) -> String { } } -pub fn canonicalize(path: &str) -> Result { - match sys::process::env("HOME") { - Some(home) => { - if path.starts_with('~') { - Ok(path.replace('~', &home)) - } else { - Ok(path.to_string()) - } - }, - None => { - Ok(path.to_string()) - } - } -} - pub fn exists(path: &str) -> bool { syscall::stat(path).is_some() } @@ -95,16 +80,25 @@ pub fn create_device(path: &str, kind: DeviceType) -> Option { None } +pub fn read(path: &str, buf: &mut [u8]) -> Result { + if let Some(stat) = syscall::stat(&path) { + let res = if stat.is_device() { open_device(&path) } else { open_file(&path) }; + if let Some(handle) = res { + if let Some(bytes) = syscall::read(handle, buf) { + syscall::close(handle); + return Ok(bytes); + } + } + } + Err(()) +} + pub fn read_to_string(path: &str) -> Result { - let buf = read(path)?; + let buf = read_to_bytes(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(()), - }; +pub fn read_to_bytes(path: &str) -> Result, ()> { if let Some(stat) = syscall::stat(&path) { let res = if stat.is_device() { open_device(&path) } else { open_file(&path) }; if let Some(handle) = res { @@ -120,10 +114,6 @@ 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(()), - }; if let Some(handle) = create_file(&path) { if let Some(bytes) = syscall::write(handle, buf) { syscall::close(handle); @@ -134,10 +124,6 @@ pub fn write(path: &str, buf: &[u8]) -> Result { } pub fn reopen(path: &str, handle: usize) -> Result { - let path = match canonicalize(path) { - Ok(path) => path, - Err(_) => return Err(()), - }; let res = if let Some(stat) = syscall::stat(&path) { if stat.is_device() { open_device(&path) @@ -168,7 +154,7 @@ fn test_file() { assert_eq!(write("/test", &input), Ok(input.len())); // Read file - assert_eq!(read("/test"), Ok(input.to_vec())); + assert_eq!(read_to_bytes("/test"), Ok(input.to_vec())); dismount(); } diff --git a/src/api/process.rs b/src/api/process.rs index e0923063..823e1420 100644 --- a/src/api/process.rs +++ b/src/api/process.rs @@ -1,12 +1,9 @@ use crate::api::syscall; -use crate::api::fs; pub fn spawn(path: &str) -> Result<(), ()> { - if let Ok(path) = fs::canonicalize(path) { - if syscall::stat(&path).is_some() { - syscall::spawn(&path); - return Ok(()); - } + if syscall::stat(&path).is_some() { + syscall::spawn(&path); + return Ok(()); } Err(()) } diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index c8ab0476..6bf3927c 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -8,6 +8,8 @@ mod file; mod read_dir; mod super_block; +use crate::sys; + pub use bitmap_block::BITMAP_SIZE; pub use device::{Device, DeviceType}; pub use dir::Dir; @@ -20,6 +22,8 @@ pub use crate::sys::ata::BLOCK_SIZE; use dir_entry::DirEntry; use super_block::SuperBlock; +use alloc::string::{String, ToString}; + pub const VERSION: u8 = 1; #[derive(Clone, Copy)] @@ -99,6 +103,21 @@ impl FileIO for Resource { } } +pub fn canonicalize(path: &str) -> Result { + match sys::process::env("HOME") { + Some(home) => { + if path.starts_with('~') { + Ok(path.replace('~', &home)) + } else { + Ok(path.to_string()) + } + }, + None => { + Ok(path.to_string()) + } + } +} + pub fn disk_size() -> usize { (SuperBlock::read().block_count as usize) * BLOCK_SIZE } diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 0c11d665..f009d9a6 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -22,7 +22,11 @@ pub fn realtime() -> f64 { } pub fn stat(path: &str, stat: &mut FileStat) -> isize { - if let Some(res) = sys::fs::stat(path) { + let path = match sys::fs::canonicalize(path) { + Ok(path) => path, + Err(_) => return -1, + }; + if let Some(res) = sys::fs::stat(&path) { *stat = res; 0 } else { @@ -31,7 +35,11 @@ pub fn stat(path: &str, stat: &mut FileStat) -> isize { } pub fn open(path: &str, flags: usize) -> isize { - if let Some(resource) = sys::fs::open(path, flags) { + let path = match sys::fs::canonicalize(path) { + Ok(path) => path, + Err(_) => return -1, + }; + if let Some(resource) = sys::fs::open(&path, flags) { if let Ok(handle) = sys::process::create_file_handle(resource) { return handle as isize; } @@ -72,7 +80,11 @@ pub fn close(handle: usize) { } pub fn spawn(path: &str) -> isize { - if let Some(mut file) = sys::fs::File::open(path) { + let path = match sys::fs::canonicalize(path) { + Ok(path) => path, + Err(_) => return -1, + }; + if let Some(mut file) = sys::fs::File::open(&path) { let mut buf = vec![0; file.size()]; if let Ok(bytes) = file.read(&mut buf) { buf.resize(bytes, 0); diff --git a/src/usr/copy.rs b/src/usr/copy.rs index 97da85d1..c9850e6d 100644 --- a/src/usr/copy.rs +++ b/src/usr/copy.rs @@ -15,7 +15,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { return usr::shell::ExitCode::CommandError; } - if let Ok(contents) = fs::read(source) { + if let Ok(contents) = fs::read_to_bytes(source) { if fs::write(dest, &contents).is_ok() { usr::shell::ExitCode::CommandSuccessful } else { diff --git a/src/usr/elf.rs b/src/usr/elf.rs index f58ee3c8..6e4b2245 100644 --- a/src/usr/elf.rs +++ b/src/usr/elf.rs @@ -12,7 +12,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { let reset = Style::reset(); let pathname = args[1]; - if let Ok(buf) = fs::read(pathname) { + if let Ok(buf) = fs::read_to_bytes(pathname) { let bin = buf.as_slice(); if let Ok(obj) = object::File::parse(bin) { println!("ELF entry address: {:#x}", obj.entry()); diff --git a/src/usr/hex.rs b/src/usr/hex.rs index 5e9afe13..64b8cdec 100644 --- a/src/usr/hex.rs +++ b/src/usr/hex.rs @@ -8,7 +8,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { return usr::shell::ExitCode::CommandError; } let pathname = args[1]; - if let Ok(buf) = fs::read(pathname) { // TODO: read chunks + if let Ok(buf) = fs::read_to_bytes(pathname) { // TODO: read chunks print_hex(&buf); usr::shell::ExitCode::CommandSuccessful } else { diff --git a/src/usr/lisp.rs b/src/usr/lisp.rs index 83a2a0b3..6695bfd6 100644 --- a/src/usr/lisp.rs +++ b/src/usr/lisp.rs @@ -256,6 +256,32 @@ fn default_env<'a>() -> Env<'a> { let contents = fs::read_to_string(&path).or(Err(Err::Reason("Could not read file".to_string())))?; Ok(Exp::Str(contents)) })); + data.insert("read-bytes".to_string(), Exp::Func(|args: &[Exp]| -> Result { + ensure_length_eq!(args, 2); + let path = string(&args[0])?; + let len = float(&args[1])?; + let mut buf = vec![0; len as usize]; + let bytes = fs::read(&path, &mut buf).or(Err(Err::Reason("Could not read file".to_string())))?; + buf.resize(bytes, 0); + Ok(Exp::List(buf.iter().map(|b| Exp::Num(*b as f64)).collect())) + })); + data.insert("bytes".to_string(), Exp::Func(|args: &[Exp]| -> Result { + ensure_length_eq!(args, 1); + let s = string(&args[0])?; + let buf = s.as_bytes(); + Ok(Exp::List(buf.iter().map(|b| Exp::Num(*b as f64)).collect())) + })); + data.insert("str".to_string(), Exp::Func(|args: &[Exp]| -> Result { + ensure_length_eq!(args, 1); + match &args[0] { + Exp::List(list) => { + let buf = list_of_floats(list)?.iter().map(|b| *b as u8).collect(); + let s = String::from_utf8(buf).or(Err(Err::Reason("Could not convert to valid UTF-8 string".to_string())))?; + Ok(Exp::Str(s)) + } + _ => Err(Err::Reason("Expected arg to be a list".to_string())) + } + })); data.insert("lines".to_string(), Exp::Func(|args: &[Exp]| -> Result { ensure_length_eq!(args, 1); let s = string(&args[0])?; @@ -432,6 +458,14 @@ fn eval_mapcar_args(args: &[Exp], env: &mut Env) -> Result { } } +fn eval_progn_args(args: &[Exp], env: &mut Env) -> Result { + let mut res = Ok(Exp::List(vec![])); + for arg in args { + res = Ok(eval(&arg, env)?); + } + res +} + fn eval_load_args(args: &[Exp], env: &mut Env) -> Result { ensure_length_eq!(args, 1); let path = string(&args[0])?; @@ -466,6 +500,7 @@ fn eval_built_in_form(exp: &Exp, args: &[Exp], env: &mut Env) -> Option Some(eval_defun_args(args, env)), "mapcar" | "map" => Some(eval_mapcar_args(args, env)), + "progn" | "do" => Some(eval_progn_args(args, env)), "load" => Some(eval_load_args(args, env)), _ => None, } diff --git a/src/usr/read.rs b/src/usr/read.rs index 4b0b38b7..ef5a9ba2 100644 --- a/src/usr/read.rs +++ b/src/usr/read.rs @@ -76,7 +76,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { usr::list::main(args) } else if stat.is_device() { loop { - if let Ok(bytes) = fs::read(pathname) { + if let Ok(bytes) = fs::read_to_bytes(pathname) { print!("{}", bytes[0] as char); } if sys::console::end_of_text() { diff --git a/src/usr/vga.rs b/src/usr/vga.rs index a0a69519..dac89c28 100644 --- a/src/usr/vga.rs +++ b/src/usr/vga.rs @@ -10,7 +10,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { match args[1] { "set" => { if args.len() == 4 && args[2] == "font" { - if let Ok(buf) = fs::read(args[3]) { + if let Ok(buf) = fs::read_to_bytes(args[3]) { if let Ok(font) = api::font::from_bytes(&buf) { sys::vga::set_font(&font); } else {