Merge pull request #17 from batonius/netcfg_commit
Change netcfg to validate on write and commit on fsync
This commit is contained in:
+2
-2
@@ -65,9 +65,9 @@ impl Domains {
|
||||
pub fn update_nameserver(&mut self) {
|
||||
if let Ok(mut file) = File::open("netcfg:resolv/nameserver") {
|
||||
let mut nameserver = String::new();
|
||||
if let Ok(_) = file.read_to_string(&mut nameserver) {
|
||||
if file.read_to_string(&mut nameserver).is_ok() {
|
||||
if let Some(line) = nameserver.lines().next() {
|
||||
if let Ok(ip) = Ipv4Addr::from_str(&line) {
|
||||
if let Ok(ip) = Ipv4Addr::from_str(line) {
|
||||
trace!("Changing nameserver to {}", ip);
|
||||
self.nameserver = ip;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::rc::Rc;
|
||||
use std::mem;
|
||||
use std::str::FromStr;
|
||||
use std::str;
|
||||
use syscall::data::Stat;
|
||||
@@ -45,19 +46,29 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
|
||||
cfg_node!{
|
||||
"resolv" => {
|
||||
"nameserver" => {
|
||||
rw [dns_config, notifier]
|
||||
rw [dns_config, notifier] (Option<Ipv4Address>, None)
|
||||
|| {
|
||||
format!("{}\n", dns_config.borrow().name_server)
|
||||
}
|
||||
|name_server| {
|
||||
let ip = Ipv4Address::from_str(name_server.trim())
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !ip.is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
|cur_value, line| {
|
||||
if cur_value.is_none() {
|
||||
let ip = Ipv4Address::from_str(line.trim())
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !ip.is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
*cur_value = Some(ip);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
dns_config.borrow_mut().name_server = ip;
|
||||
notifier.borrow_mut().schedule_notify("resolv/nameserver");
|
||||
Ok(0)
|
||||
}
|
||||
|cur_value| {
|
||||
if let Some(ip) = *cur_value {
|
||||
dns_config.borrow_mut().name_server = ip;
|
||||
notifier.borrow_mut().schedule_notify("resolv/nameserver");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -72,49 +83,90 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
|
||||
}
|
||||
},
|
||||
"add" => {
|
||||
wo [iface, notifier] |routes| {
|
||||
let default_gw = parse_default_gw(routes)?;
|
||||
iface.borrow_mut().set_ipv4_gateway(Some(default_gw));
|
||||
notifier.borrow_mut().schedule_notify("route/list");
|
||||
Ok(0)
|
||||
wo [iface, notifier] (Option<Ipv4Address>, None)
|
||||
|cur_value, line| {
|
||||
if cur_value.is_none() {
|
||||
let default_gw = parse_default_gw(line)?;
|
||||
if !default_gw.is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
*cur_value = Some(default_gw);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
}
|
||||
|cur_value| {
|
||||
if let Some(default_gw) = *cur_value {
|
||||
iface.borrow_mut().set_ipv4_gateway(Some(default_gw));
|
||||
notifier.borrow_mut().schedule_notify("route/list");
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
}
|
||||
},
|
||||
"rm" => {
|
||||
wo [iface, notifier] |routes| {
|
||||
let default_gw = parse_default_gw(routes)?;
|
||||
let mut iface = iface.borrow_mut();
|
||||
if iface.ipv4_gateway() != Some(default_gw) {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
wo [iface, notifier] (Option<Ipv4Address>, None)
|
||||
|cur_value, line| {
|
||||
if cur_value.is_none() {
|
||||
let default_gw = parse_default_gw(line)?;
|
||||
if !default_gw.is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
*cur_value = Some(default_gw);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
iface.set_ipv4_gateway(None);
|
||||
notifier.borrow_mut().schedule_notify("route/list");
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|cur_value| {
|
||||
if let Some(default_gw) = *cur_value {
|
||||
let mut iface = iface.borrow_mut();
|
||||
if iface.ipv4_gateway() != Some(default_gw) {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
iface.set_ipv4_gateway(None);
|
||||
notifier.borrow_mut().schedule_notify("route/list");
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"ifaces" => {
|
||||
"eth0" => {
|
||||
"mac" => {
|
||||
rw [iface, notifier]
|
||||
rw [iface, notifier] (Option<EthernetAddress>, None)
|
||||
|| {
|
||||
format!("{}\n", iface.borrow().ethernet_addr())
|
||||
}
|
||||
|mac| {
|
||||
let mac = mac.lines().next()
|
||||
.ok_or_else(|| SyscallError::new(syscall::EINVAL))?;
|
||||
let mac = EthernetAddress::from_str(mac).
|
||||
map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !mac.is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
|cur_value, line| {
|
||||
if cur_value.is_none() {
|
||||
let mac = EthernetAddress::from_str(line).
|
||||
map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !mac.is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
*cur_value = Some(mac);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EINVAL))
|
||||
}
|
||||
iface.borrow_mut().set_ethernet_addr(mac);
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/mac");
|
||||
Ok(0)
|
||||
}
|
||||
|cur_value| {
|
||||
if let Some(mac) = *cur_value {
|
||||
iface.borrow_mut().set_ethernet_addr(mac);
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/mac");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
"addr" => {
|
||||
"list" => {
|
||||
ro [iface] || {
|
||||
ro [iface]
|
||||
|| {
|
||||
let mut ips = String::new();
|
||||
for cidr in iface.borrow().ip_addrs() {
|
||||
ips += &format!("{}\n", cidr);
|
||||
@@ -122,37 +174,71 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
|
||||
ips
|
||||
}
|
||||
},
|
||||
"set" => {
|
||||
wo [iface, notifier] (Vec<IpCidr>, Vec::new())
|
||||
|cur_value, line| {
|
||||
let cidr = IpCidr::from_str(line)
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !cidr.address().is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
cur_value.push(cidr);
|
||||
Ok(())
|
||||
}
|
||||
|cur_value| {
|
||||
if !cur_value.is_empty() {
|
||||
let mut iface = iface.borrow_mut();
|
||||
let mut cidrs = vec![];
|
||||
mem::swap(cur_value, &mut cidrs);
|
||||
iface.update_ip_addrs(|s| {
|
||||
*s = From::from(cidrs);
|
||||
});
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
"add" => {
|
||||
wo [iface, notifier] |input| {
|
||||
wo [iface, notifier] (Vec<IpCidr>, Vec::new())
|
||||
|cur_value, line| {
|
||||
let cidr = IpCidr::from_str(line)
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !cidr.address().is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
cur_value.push(cidr);
|
||||
Ok(())
|
||||
}
|
||||
|cur_value| {
|
||||
let mut iface = iface.borrow_mut();
|
||||
let mut cidrs = iface.ip_addrs().to_vec();
|
||||
for cidr in input.lines() {
|
||||
let cidr = IpCidr::from_str(cidr)
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !cidr.address().is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
cidrs.insert(0, cidr);
|
||||
for cidr in cur_value {
|
||||
cidrs.insert(0, *cidr);
|
||||
}
|
||||
iface.update_ip_addrs(|s| {
|
||||
*s = From::from(cidrs);
|
||||
});
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
|
||||
Ok(0)
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
"rm" => {
|
||||
wo [iface, notifier] |input| {
|
||||
wo [iface, notifier] (Vec<IpCidr>, Vec::new())
|
||||
|cur_value, line| {
|
||||
let cidr = IpCidr::from_str(line)
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !cidr.address().is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
cur_value.push(cidr);
|
||||
Ok(())
|
||||
}
|
||||
|cur_value| {
|
||||
let mut iface = iface.borrow_mut();
|
||||
let mut cidrs = iface.ip_addrs().to_vec();
|
||||
for cidr in input.lines() {
|
||||
let cidr = IpCidr::from_str(cidr)
|
||||
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
|
||||
if !cidr.address().is_unicast() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
for cidr in cur_value {
|
||||
let pre_retain_len = cidrs.len();
|
||||
cidrs.retain(|&c| c != cidr);
|
||||
cidrs.retain(|&c| c != *cidr);
|
||||
if pre_retain_len == cidrs.len() {
|
||||
return Err(SyscallError::new(syscall::EINVAL));
|
||||
}
|
||||
@@ -161,7 +247,7 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
|
||||
*s = From::from(cidrs);
|
||||
});
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
|
||||
Ok(0)
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -178,11 +264,59 @@ type DNSConfigRef = Rc<RefCell<DNSConfig>>;
|
||||
|
||||
struct NetCfgFile {
|
||||
path: String,
|
||||
cfg_node: CfgNodeRef,
|
||||
is_dir: bool,
|
||||
is_writable: bool,
|
||||
is_readable: bool,
|
||||
node_writer: Option<Box<NodeWriter>>,
|
||||
read_buf: Vec<u8>,
|
||||
write_buf: Vec<u8>,
|
||||
pos: usize,
|
||||
uid: u32,
|
||||
done: bool,
|
||||
}
|
||||
|
||||
impl NetCfgFile {
|
||||
fn commit(&mut self) -> SyscallResult<()> {
|
||||
if let Some(ref mut node_writer) = self.node_writer {
|
||||
if !self.write_buf.is_empty() {
|
||||
let line = str::from_utf8(&self.write_buf)
|
||||
.or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
|
||||
node_writer.write_line(line)?;
|
||||
}
|
||||
node_writer.commit()?;
|
||||
self.write_buf.clear();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn consume_lines(&mut self) -> SyscallResult<()> {
|
||||
if let Some(ref mut node_writer) = self.node_writer {
|
||||
let mut swap_with = None;
|
||||
{
|
||||
let mut lines = self.write_buf.split(|&c| c == b'\n');
|
||||
if let Some(mut cur_line) = lines.next() {
|
||||
let mut consumed = false;
|
||||
for next_line in lines {
|
||||
let line = str::from_utf8(cur_line)
|
||||
.or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
|
||||
trace!("writing line {}", line);
|
||||
node_writer.write_line(line)?;
|
||||
cur_line = next_line;
|
||||
consumed = true;
|
||||
}
|
||||
if consumed {
|
||||
swap_with = Some(From::from(cur_line))
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ref mut new_vec) = swap_with {
|
||||
mem::swap(&mut self.write_buf, new_vec);
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EBADF))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NetCfgScheme {
|
||||
@@ -243,7 +377,8 @@ impl SchemeMut for NetCfgScheme {
|
||||
.ok_or_else(|| SyscallError::new(syscall::EINVAL))?;
|
||||
current_node = next_node;
|
||||
}
|
||||
let read_buf = Vec::from(current_node.borrow().read());
|
||||
let current_node = current_node.borrow();
|
||||
let read_buf = Vec::from(current_node.read());
|
||||
let fd = self.next_fd;
|
||||
trace!("open {} {}", fd, path);
|
||||
self.next_fd += 1;
|
||||
@@ -251,11 +386,15 @@ impl SchemeMut for NetCfgScheme {
|
||||
fd,
|
||||
NetCfgFile {
|
||||
path: path.to_owned(),
|
||||
cfg_node: current_node,
|
||||
is_dir: current_node.is_dir(),
|
||||
is_writable: current_node.is_writable(),
|
||||
is_readable: current_node.is_readable(),
|
||||
node_writer: if current_node.is_writable() { current_node.new_writer() } else { None },
|
||||
uid,
|
||||
pos: 0,
|
||||
read_buf,
|
||||
write_buf: vec![],
|
||||
done: false,
|
||||
},
|
||||
);
|
||||
Ok(fd)
|
||||
@@ -263,13 +402,10 @@ impl SchemeMut for NetCfgScheme {
|
||||
|
||||
fn close(&mut self, fd: usize) -> SyscallResult<usize> {
|
||||
trace!("close {}", fd);
|
||||
if let Some(file) = self.files.remove(&fd) {
|
||||
if let Some(mut file) = self.files.remove(&fd) {
|
||||
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
|
||||
let node = file.cfg_node.borrow();
|
||||
if node.is_writable() {
|
||||
let value = str::from_utf8(&file.write_buf)
|
||||
.or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
|
||||
node.write(value)
|
||||
if !file.done {
|
||||
file.commit().map(|_| 0)
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
@@ -283,6 +419,10 @@ impl SchemeMut for NetCfgScheme {
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
if file.done {
|
||||
return Err(SyscallError::new(syscall::EBADF));
|
||||
}
|
||||
|
||||
if file.uid != 0 {
|
||||
return Err(SyscallError::new(syscall::EACCES));
|
||||
}
|
||||
@@ -290,7 +430,15 @@ impl SchemeMut for NetCfgScheme {
|
||||
if (WRITE_BUFFER_MAX_SIZE - file.write_buf.len()) < buf.len() {
|
||||
return Err(SyscallError::new(syscall::EMSGSIZE));
|
||||
}
|
||||
|
||||
file.write_buf.extend_from_slice(buf);
|
||||
|
||||
if let Err(e) = file.consume_lines() {
|
||||
trace!("Failed write {} {}", fd, e);
|
||||
file.done = true;
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
@@ -312,17 +460,16 @@ impl SchemeMut for NetCfgScheme {
|
||||
let file = self.files
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
let cfg_node = file.cfg_node.borrow();
|
||||
|
||||
stat.st_mode = if cfg_node.is_dir() {
|
||||
stat.st_mode = if file.is_dir {
|
||||
MODE_DIR
|
||||
} else {
|
||||
MODE_FILE
|
||||
};
|
||||
if cfg_node.is_writable() {
|
||||
if file.is_writable {
|
||||
stat.st_mode |= 0o222;
|
||||
}
|
||||
if cfg_node.is_readable() {
|
||||
if file.is_readable {
|
||||
stat.st_mode |= 0o444;
|
||||
}
|
||||
stat.st_uid = 0;
|
||||
@@ -343,4 +490,18 @@ impl SchemeMut for NetCfgScheme {
|
||||
}
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
fn fsync(&mut self, fd: usize) -> SyscallResult<usize> {
|
||||
let file = self.files
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
if !file.done {
|
||||
let res = file.commit().map(|_| 0);
|
||||
file.done = true;
|
||||
res
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EBADF))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,54 @@ use syscall::Result as SyscallResult;
|
||||
|
||||
pub type CfgNodeRef = Rc<RefCell<CfgNode>>;
|
||||
|
||||
pub trait NodeWriter {
|
||||
fn write_line(&mut self, &str) -> SyscallResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn commit(&mut self) -> SyscallResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SimpleWriter<T, WL, C>
|
||||
where
|
||||
WL: 'static + Fn(&mut T, &str) -> SyscallResult<()>,
|
||||
C: 'static + Fn(&mut T) -> SyscallResult<()>,
|
||||
{
|
||||
data: T,
|
||||
write_line: WL,
|
||||
commit: C,
|
||||
}
|
||||
|
||||
impl<T, WL, C> NodeWriter for SimpleWriter<T, WL, C>
|
||||
where
|
||||
WL: 'static + Fn(&mut T, &str) -> SyscallResult<()>,
|
||||
C: 'static + Fn(&mut T) -> SyscallResult<()>,
|
||||
{
|
||||
fn write_line(&mut self, line: &str) -> SyscallResult<()> {
|
||||
(self.write_line)(&mut self.data, line)
|
||||
}
|
||||
|
||||
fn commit(&mut self) -> SyscallResult<()> {
|
||||
(self.commit)(&mut self.data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, WL, C> SimpleWriter<T, WL, C>
|
||||
where
|
||||
WL: 'static + Fn(&mut T, &str) -> SyscallResult<()>,
|
||||
C: 'static + Fn(&mut T) -> SyscallResult<()>,
|
||||
{
|
||||
pub fn new_boxed(data: T, write_line: WL, commit: C) -> Box<Self> {
|
||||
Box::new(SimpleWriter {
|
||||
data,
|
||||
write_line,
|
||||
commit,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CfgNode {
|
||||
fn is_dir(&self) -> bool {
|
||||
false
|
||||
@@ -22,11 +70,11 @@ pub trait CfgNode {
|
||||
String::new()
|
||||
}
|
||||
|
||||
fn write(&self, _buf: &str) -> SyscallResult<usize> {
|
||||
Ok(0)
|
||||
fn open(&self, _file: &str) -> Option<CfgNodeRef> {
|
||||
None
|
||||
}
|
||||
|
||||
fn open(&self, _file: &str) -> Option<CfgNodeRef> {
|
||||
fn new_writer(&self) -> Option<Box<NodeWriter>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -56,21 +104,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WONode<F>
|
||||
pub struct WONode<W>
|
||||
where
|
||||
F: Fn(&str) -> SyscallResult<usize>,
|
||||
W: 'static + Fn() -> Box<NodeWriter>,
|
||||
{
|
||||
write_fun: F,
|
||||
new_writer: W,
|
||||
}
|
||||
|
||||
impl<F> CfgNode for WONode<F>
|
||||
impl<W> CfgNode for WONode<W>
|
||||
where
|
||||
F: Fn(&str) -> SyscallResult<usize>,
|
||||
W: 'static + Fn() -> Box<NodeWriter>,
|
||||
{
|
||||
fn write(&self, buf: &str) -> SyscallResult<usize> {
|
||||
(self.write_fun)(buf)
|
||||
}
|
||||
|
||||
fn is_readable(&self) -> bool {
|
||||
false
|
||||
}
|
||||
@@ -78,53 +122,57 @@ where
|
||||
fn is_writable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> WONode<F>
|
||||
where
|
||||
F: 'static + Fn(&str) -> SyscallResult<usize>,
|
||||
{
|
||||
pub fn new_ref(write_fun: F) -> CfgNodeRef {
|
||||
Rc::new(RefCell::new(WONode { write_fun }))
|
||||
fn new_writer(&self) -> Option<Box<NodeWriter>> {
|
||||
Some((self.new_writer)())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RWNode<F, G>
|
||||
impl<W> WONode<W>
|
||||
where
|
||||
F: Fn() -> String,
|
||||
G: Fn(&str) -> SyscallResult<usize>,
|
||||
W: 'static + Fn() -> Box<NodeWriter>,
|
||||
{
|
||||
read_fun: F,
|
||||
write_fun: G,
|
||||
pub fn new_ref(new_writer: W) -> CfgNodeRef {
|
||||
Rc::new(RefCell::new(WONode { new_writer }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, G> CfgNode for RWNode<F, G>
|
||||
pub struct RWNode<F, W>
|
||||
where
|
||||
F: Fn() -> String,
|
||||
G: Fn(&str) -> SyscallResult<usize>,
|
||||
W: 'static + Fn() -> Box<NodeWriter>,
|
||||
{
|
||||
read_fun: F,
|
||||
new_writer: W,
|
||||
}
|
||||
|
||||
impl<F, W> CfgNode for RWNode<F, W>
|
||||
where
|
||||
F: Fn() -> String,
|
||||
W: 'static + Fn() -> Box<NodeWriter>,
|
||||
{
|
||||
fn read(&self) -> String {
|
||||
(self.read_fun)()
|
||||
}
|
||||
|
||||
fn write(&self, buf: &str) -> SyscallResult<usize> {
|
||||
(self.write_fun)(buf)
|
||||
}
|
||||
|
||||
fn is_writable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn new_writer(&self) -> Option<Box<NodeWriter>> {
|
||||
Some((self.new_writer)())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, G> RWNode<F, G>
|
||||
impl<F, W> RWNode<F, W>
|
||||
where
|
||||
F: 'static + Fn() -> String,
|
||||
G: 'static + Fn(&str) -> SyscallResult<usize>,
|
||||
W: 'static + Fn() -> Box<NodeWriter>,
|
||||
{
|
||||
pub fn new_ref(read_fun: F, write_fun: G) -> CfgNodeRef {
|
||||
pub fn new_ref(read_fun: F, new_writer: W) -> CfgNodeRef {
|
||||
Rc::new(RefCell::new(RWNode {
|
||||
read_fun,
|
||||
write_fun,
|
||||
new_writer,
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -170,23 +218,46 @@ macro_rules! cfg_node {
|
||||
RONode::new_ref(move|| $b)
|
||||
}
|
||||
};
|
||||
(wo [ $($c:ident),* ] |$i:ident| $b:block ) => {
|
||||
(wo [ $($c:ident),* ] ( $et:ty , $e:expr ) |$data_i:ident, $line_i:ident|
|
||||
$write_line:block |$data_i2:ident| $commit:block) => {
|
||||
{
|
||||
$(let $c = $c.clone();)*
|
||||
WONode::new_ref(move |$i: &str| $b)
|
||||
$(#[allow(unused_variables)] let $c = $c.clone();)*;
|
||||
let new_writer = move || -> Box<NodeWriter> {
|
||||
let write_line = {
|
||||
$(#[allow(unused_variables)] let $c = $c.clone();)*;
|
||||
move |$data_i: &mut $et, $line_i: &str| $write_line
|
||||
};
|
||||
let commit = {
|
||||
$(#[allow(unused_variables)] let $c = $c.clone();)*;
|
||||
move |$data_i2: &mut $et| $commit
|
||||
};
|
||||
let data: $et = $e;
|
||||
SimpleWriter::new_boxed(data, write_line, commit)
|
||||
};
|
||||
WONode::new_ref(new_writer)
|
||||
}
|
||||
};
|
||||
(rw [ $($c:ident),* ] || $rb:block |$i:ident| $wb:block ) => {
|
||||
(rw [ $($c:ident),* ] ( $et:ty , $e:expr ) || $read_fun:block |$data_i:ident, $line_i:ident|
|
||||
$write_line:block |$data_i2:ident| $commit:block) => {
|
||||
{
|
||||
let read_fun = {
|
||||
$(#[allow(unused_variables)] let $c = $c.clone();)*
|
||||
move || $rb
|
||||
$(#[allow(unused_variables)] let $c = $c.clone();)*;
|
||||
move || $read_fun
|
||||
};
|
||||
let write_fun = {
|
||||
$(#[allow(unused_variables)] let $c = $c.clone();)*
|
||||
move |$i: &str| $wb
|
||||
$(#[allow(unused_variables)] let $c = $c.clone();)*;
|
||||
let new_writer = move || -> Box<NodeWriter> {
|
||||
let write_line = {
|
||||
$(#[allow(unused_variables)] let $c = $c.clone();)*;
|
||||
move |$data_i: &mut $et, $line_i: &str| $write_line
|
||||
};
|
||||
let commit = {
|
||||
$(#[allow(unused_variables)] let $c = $c.clone();)*;
|
||||
move |$data_i2: &mut $et| $commit
|
||||
};
|
||||
let data: $et = $e;
|
||||
SimpleWriter::new_boxed(data, write_line, commit)
|
||||
};
|
||||
RWNode::new_ref(read_fun, write_fun)
|
||||
RWNode::new_ref(read_fun, new_writer)
|
||||
}
|
||||
};
|
||||
($($e:expr => { $($t:tt)* }),* $(,)*) => {
|
||||
|
||||
Reference in New Issue
Block a user