diff --git a/doc/shell.md b/doc/shell.md index 062192e..60f3c70 100644 --- a/doc/shell.md +++ b/doc/shell.md @@ -126,6 +126,10 @@ Which is more efficient than doing: > print hello -> write /tmp/hello +NOTE: A redirection will append to a file without truncating it first as Unix +does, so it is more equivalent to `>>` than `>` for now. This may change in +the future with the addition of a `=>>` symbol. + ## Variables - Name of the shell or the script: `$0` diff --git a/src/api/fs.rs b/src/api/fs.rs index 7abcf9f..e23e54d 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -65,6 +65,11 @@ pub fn open_file(path: &str) -> Option { syscall::open(path, flags) } +pub fn append_file(path: &str) -> Option { + let flags = OpenFlag::Append as usize; + syscall::open(path, flags) +} + pub fn create_file(path: &str) -> Option { let flags = OpenFlag::Create as usize; syscall::open(path, flags) @@ -144,12 +149,31 @@ pub fn write(path: &str, buf: &[u8]) -> Result { Err(()) } +pub fn append(path: &str, buf: &[u8]) -> Result { + let res = if let Some(info) = syscall::info(path) { + if info.is_device() { + open_device(path) + } else { + append_file(path) + } + } else { + create_file(path) + }; + if let Some(handle) = res { + if let Some(bytes) = syscall::write(handle, buf) { + syscall::close(handle); + return Ok(bytes); + } + } + Err(()) +} + pub fn reopen(path: &str, handle: usize) -> Result { let res = if let Some(info) = syscall::info(path) { if info.is_device() { open_device(path) } else { - open_file(path) + append_file(path) } } else { create_file(path) diff --git a/src/sys/fs/file.rs b/src/sys/fs/file.rs index d73b3d3..5a6564c 100644 --- a/src/sys/fs/file.rs +++ b/src/sys/fs/file.rs @@ -84,7 +84,7 @@ impl File { let offset = match pos { SeekFrom::Start(i) => i as i32, SeekFrom::Current(i) => i + self.offset as i32, - SeekFrom::End(i) => i + self.size as i32 - 1, + SeekFrom::End(i) => i + self.size as i32, }; if offset < 0 || offset > self.size as i32 { // TODO: offset > size? return Err(()) diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index 3732e8d..99e5459 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -29,11 +29,13 @@ pub const VERSION: u8 = 1; #[derive(Clone, Copy)] #[repr(u8)] pub enum OpenFlag { - Read = 1, - Write = 2, - Create = 4, - Dir = 8, - Device = 16, + Read = 1, + Write = 2, + Append = 4, + Create = 8, + Truncate = 16, + Dir = 32, + Device = 64, } impl OpenFlag { @@ -58,10 +60,15 @@ pub fn open(path: &str, flags: usize) -> Option { res }.map(Resource::Device) } else { - let res = File::open(path); + let mut res = File::open(path); if res.is_none() && OpenFlag::Create.is_set(flags) { File::create(path) } else { + if OpenFlag::Append.is_set(flags) { + if let Some(ref mut file) = res { + file.seek(SeekFrom::End(0)).ok(); + } + } res }.map(Resource::File) } diff --git a/src/usr/shell.rs b/src/usr/shell.rs index 7e07e40..4f5ec34 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -379,6 +379,7 @@ fn exec_with_config(cmd: &str, config: &mut Config) -> Result<(), ExitCode> { continue; } + // Parse file handle let s = args[i].chars().take_while(|c| c.is_numeric()).collect::(); if let Ok(h) = s.parse() { left_handle = h; @@ -576,20 +577,16 @@ fn test_shell() { usr::install::copy_files(false); // Redirect standard output - exec("print test1 => /test").ok(); - assert_eq!(api::fs::read_to_string("/test"), Ok("test1\n".to_string())); - - // Overwrite content of existing file - exec("print test2 => /test").ok(); - assert_eq!(api::fs::read_to_string("/test"), Ok("test2\n".to_string())); + exec("print test1 => /tmp/test1").ok(); + assert_eq!(api::fs::read_to_string("/tmp/test1"), Ok("test1\n".to_string())); // Redirect standard output explicitely - exec("print test3 1=> /test").ok(); - assert_eq!(api::fs::read_to_string("/test"), Ok("test3\n".to_string())); + exec("print test2 1=> /tmp/test2").ok(); + assert_eq!(api::fs::read_to_string("/tmp/test2"), Ok("test2\n".to_string())); // Redirect standard error explicitely - exec("hex /nope 2=> /test").ok(); - assert!(api::fs::read_to_string("/test").unwrap().contains("File not found '/nope'")); + exec("hex /nope 2=> /tmp/test3").ok(); + assert!(api::fs::read_to_string("/tmp/test3").unwrap().contains("File not found '/nope'")); let mut config = Config::new(); exec_with_config("set b 42", &mut config).ok();