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
|
> 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
|
## Variables
|
||||||
|
|
||||||
- Name of the shell or the script: `$0`
|
- Name of the shell or the script: `$0`
|
||||||
|
|
|
@ -65,6 +65,11 @@ pub fn open_file(path: &str) -> Option<usize> {
|
||||||
syscall::open(path, flags)
|
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> {
|
pub fn create_file(path: &str) -> Option<usize> {
|
||||||
let flags = OpenFlag::Create as usize;
|
let flags = OpenFlag::Create as usize;
|
||||||
syscall::open(path, flags)
|
syscall::open(path, flags)
|
||||||
|
@ -144,12 +149,31 @@ pub fn write(path: &str, buf: &[u8]) -> Result<usize, ()> {
|
||||||
Err(())
|
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, ()> {
|
pub fn reopen(path: &str, handle: usize) -> Result<usize, ()> {
|
||||||
let res = if let Some(info) = syscall::info(path) {
|
let res = if let Some(info) = syscall::info(path) {
|
||||||
if info.is_device() {
|
if info.is_device() {
|
||||||
open_device(path)
|
open_device(path)
|
||||||
} else {
|
} else {
|
||||||
open_file(path)
|
append_file(path)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
create_file(path)
|
create_file(path)
|
||||||
|
|
|
@ -84,7 +84,7 @@ impl File {
|
||||||
let offset = match pos {
|
let offset = match pos {
|
||||||
SeekFrom::Start(i) => i as i32,
|
SeekFrom::Start(i) => i as i32,
|
||||||
SeekFrom::Current(i) => i + self.offset 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?
|
if offset < 0 || offset > self.size as i32 { // TODO: offset > size?
|
||||||
return Err(())
|
return Err(())
|
||||||
|
|
|
@ -29,11 +29,13 @@ pub const VERSION: u8 = 1;
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum OpenFlag {
|
pub enum OpenFlag {
|
||||||
Read = 1,
|
Read = 1,
|
||||||
Write = 2,
|
Write = 2,
|
||||||
Create = 4,
|
Append = 4,
|
||||||
Dir = 8,
|
Create = 8,
|
||||||
Device = 16,
|
Truncate = 16,
|
||||||
|
Dir = 32,
|
||||||
|
Device = 64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpenFlag {
|
impl OpenFlag {
|
||||||
|
@ -58,10 +60,15 @@ pub fn open(path: &str, flags: usize) -> Option<Resource> {
|
||||||
res
|
res
|
||||||
}.map(Resource::Device)
|
}.map(Resource::Device)
|
||||||
} else {
|
} else {
|
||||||
let res = File::open(path);
|
let mut res = File::open(path);
|
||||||
if res.is_none() && OpenFlag::Create.is_set(flags) {
|
if res.is_none() && OpenFlag::Create.is_set(flags) {
|
||||||
File::create(path)
|
File::create(path)
|
||||||
} else {
|
} else {
|
||||||
|
if OpenFlag::Append.is_set(flags) {
|
||||||
|
if let Some(ref mut file) = res {
|
||||||
|
file.seek(SeekFrom::End(0)).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
res
|
res
|
||||||
}.map(Resource::File)
|
}.map(Resource::File)
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,6 +379,7 @@ fn exec_with_config(cmd: &str, config: &mut Config) -> Result<(), ExitCode> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse file handle
|
||||||
let s = args[i].chars().take_while(|c| c.is_numeric()).collect::<String>();
|
let s = args[i].chars().take_while(|c| c.is_numeric()).collect::<String>();
|
||||||
if let Ok(h) = s.parse() {
|
if let Ok(h) = s.parse() {
|
||||||
left_handle = h;
|
left_handle = h;
|
||||||
|
@ -576,20 +577,16 @@ fn test_shell() {
|
||||||
usr::install::copy_files(false);
|
usr::install::copy_files(false);
|
||||||
|
|
||||||
// Redirect standard output
|
// Redirect standard output
|
||||||
exec("print test1 => /test").ok();
|
exec("print test1 => /tmp/test1").ok();
|
||||||
assert_eq!(api::fs::read_to_string("/test"), Ok("test1\n".to_string()));
|
assert_eq!(api::fs::read_to_string("/tmp/test1"), 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()));
|
|
||||||
|
|
||||||
// Redirect standard output explicitely
|
// Redirect standard output explicitely
|
||||||
exec("print test3 1=> /test").ok();
|
exec("print test2 1=> /tmp/test2").ok();
|
||||||
assert_eq!(api::fs::read_to_string("/test"), Ok("test3\n".to_string()));
|
assert_eq!(api::fs::read_to_string("/tmp/test2"), Ok("test2\n".to_string()));
|
||||||
|
|
||||||
// Redirect standard error explicitely
|
// Redirect standard error explicitely
|
||||||
exec("hex /nope 2=> /test").ok();
|
exec("hex /nope 2=> /tmp/test3").ok();
|
||||||
assert!(api::fs::read_to_string("/test").unwrap().contains("File not found '/nope'"));
|
assert!(api::fs::read_to_string("/tmp/test3").unwrap().contains("File not found '/nope'"));
|
||||||
|
|
||||||
let mut config = Config::new();
|
let mut config = Config::new();
|
||||||
exec_with_config("set b 42", &mut config).ok();
|
exec_with_config("set b 42", &mut config).ok();
|
||||||
|
|
Loading…
Reference in New Issue