Add file append (#387)

* Add file append

* Fix off by one error

* Use append in reopen for shell redirections

* Add documentation

* Update tests
This commit is contained in:
Vincent Ollivier 2022-08-14 01:12:52 +02:00 committed by GitHub
parent 0dc7c381f3
commit e0596f9f77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 50 additions and 18 deletions

View File

@ -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`

View File

@ -65,6 +65,11 @@ pub fn open_file(path: &str) -> Option<usize> {
syscall::open(path, flags)
}
pub fn append_file(path: &str) -> Option<usize> {
let flags = OpenFlag::Append as usize;
syscall::open(path, flags)
}
pub fn create_file(path: &str) -> Option<usize> {
let flags = OpenFlag::Create as usize;
syscall::open(path, flags)
@ -144,12 +149,31 @@ pub fn write(path: &str, buf: &[u8]) -> Result<usize, ()> {
Err(())
}
pub fn append(path: &str, buf: &[u8]) -> Result<usize, ()> {
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<usize, ()> {
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)

View File

@ -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(())

View File

@ -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<Resource> {
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)
}

View File

@ -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::<String>();
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();