mirror of https://github.com/vinc/moros.git
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:
parent
0dc7c381f3
commit
e0596f9f77
|
@ -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`
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue