Skip to content

Commit

Permalink
Improve file reading (#296)
Browse files Browse the repository at this point in the history
* Move path canonicalization from API to kernel

* Add api::fs::read_exact

* Add read-bytes to lisp

* Add str function to lisp

* Rename fs::read to fs::read_to_bytes

* Rename fs::read_exact to fs::read

* Add bytes fonction to lisp

* Add progn special form to lisp

* Fix failing test
  • Loading branch information
vinc authored Jan 5, 2022
1 parent e96f250 commit e2ff0ac
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 44 deletions.
46 changes: 16 additions & 30 deletions src/api/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,6 @@ pub fn realpath(pathname: &str) -> String {
}
}

pub fn canonicalize(path: &str) -> Result<String, ()> {
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()
}
Expand Down Expand Up @@ -95,16 +80,25 @@ pub fn create_device(path: &str, kind: DeviceType) -> Option<usize> {
None
}

pub fn read(path: &str, buf: &mut [u8]) -> Result<usize, ()> {
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<String, ()> {
let buf = read(path)?;
let buf = read_to_bytes(path)?;
Ok(String::from_utf8_lossy(&buf).to_string())
}

pub fn read(path: &str) -> Result<Vec<u8>, ()> {
let path = match canonicalize(path) {
Ok(path) => path,
Err(_) => return Err(()),
};
pub fn read_to_bytes(path: &str) -> Result<Vec<u8>, ()> {
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 {
Expand All @@ -120,10 +114,6 @@ pub fn read(path: &str) -> Result<Vec<u8>, ()> {
}

pub fn write(path: &str, buf: &[u8]) -> Result<usize, ()> {
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);
Expand All @@ -134,10 +124,6 @@ pub fn write(path: &str, buf: &[u8]) -> Result<usize, ()> {
}

pub fn reopen(path: &str, handle: usize) -> Result<usize, ()> {
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)
Expand Down Expand Up @@ -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();
}
9 changes: 3 additions & 6 deletions src/api/process.rs
Original file line number Diff line number Diff line change
@@ -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(())
}
19 changes: 19 additions & 0 deletions src/sys/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)]
Expand Down Expand Up @@ -99,6 +103,21 @@ impl FileIO for Resource {
}
}

pub fn canonicalize(path: &str) -> Result<String, ()> {
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
}
Expand Down
18 changes: 15 additions & 3 deletions src/sys/syscall/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/usr/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/usr/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
2 changes: 1 addition & 1 deletion src/usr/hex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
35 changes: 35 additions & 0 deletions src/usr/lisp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Exp, Err> {
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<Exp, Err> {
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<Exp, Err> {
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<Exp, Err> {
ensure_length_eq!(args, 1);
let s = string(&args[0])?;
Expand Down Expand Up @@ -432,6 +458,14 @@ fn eval_mapcar_args(args: &[Exp], env: &mut Env) -> Result<Exp, Err> {
}
}

fn eval_progn_args(args: &[Exp], env: &mut Env) -> Result<Exp, Err> {
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<Exp, Err> {
ensure_length_eq!(args, 1);
let path = string(&args[0])?;
Expand Down Expand Up @@ -466,6 +500,7 @@ fn eval_built_in_form(exp: &Exp, args: &[Exp], env: &mut Env) -> Option<Result<E

"defun" | "defn" => 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,
}
Expand Down
2 changes: 1 addition & 1 deletion src/usr/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion src/usr/vga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit e2ff0ac

Please sign in to comment.