use plugin::*;
use serde::{Deserialize, Serialize};
use utils::*;
#[derive(Serialize, Deserialize)]
pub struct RIODesc {
pub(crate) name: String,
pub(crate) perm: IoMode,
pub(crate) hndl: u64,
pub(crate) paddr: u64,
pub(crate) size: u64,
raddr: u64,
#[serde(skip)]
plugin_operations: Box<dyn RIOPluginOperations>,
}
impl RIODesc {
pub(crate) fn raddr(&self) -> u64 {
self.raddr
}
pub(crate) fn open(plugin: &mut dyn RIOPlugin, uri: &str, flags: IoMode) -> Result<RIODesc, IoError> {
let plugin_desc = plugin.open(uri, flags)?;
let desc = RIODesc {
hndl: 0,
name: plugin_desc.name,
perm: plugin_desc.perm,
paddr: 0,
size: plugin_desc.size,
plugin_operations: plugin_desc.plugin_operations,
raddr: plugin_desc.raddr,
};
return Ok(desc);
}
pub(crate) fn reopen(&mut self, plugin: &mut dyn RIOPlugin) -> Result<(), IoError> {
let plugin_desc = plugin.open(&self.name, self.perm)?;
self.plugin_operations = plugin_desc.plugin_operations;
self.raddr = plugin_desc.raddr;
return Ok(());
}
pub(crate) fn read(&mut self, paddr: usize, buffer: &mut [u8]) -> Result<(), IoError> {
return self.plugin_operations.read(paddr - self.paddr as usize + self.raddr as usize as usize, buffer);
}
pub(crate) fn write(&mut self, paddr: usize, buffer: &[u8]) -> Result<(), IoError> {
return self.plugin_operations.write(paddr - self.paddr as usize + self.raddr as usize, buffer);
}
pub fn name(&self) -> &str {
return &self.name;
}
pub fn has_paddr(&self, paddr: u64) -> bool {
return paddr >= self.paddr && paddr < self.paddr + self.size as u64;
}
pub fn paddr_base(&self) -> u64 {
return self.paddr;
}
pub fn size(&self) -> u64 {
return self.size;
}
pub fn perm(&self) -> IoMode {
return self.perm;
}
pub fn hndl(&self) -> u64 {
return self.hndl;
}
}
#[cfg(test)]
mod default_plugin_tests {
use super::*;
use plugins::defaultplugin;
use std::io;
use std::path::Path;
use test_file::*;
fn test_desc_read_cb(path: &Path) {
let mut plugin = defaultplugin::plugin();
let mut desc = RIODesc::open(&mut *plugin, &path.to_string_lossy(), IoMode::READ).unwrap();
desc.paddr = 0x40000;
let mut buffer: &mut [u8] = &mut [0; 8];
desc.read(desc.paddr as usize, &mut buffer).unwrap();
assert_eq!(buffer, [0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d]);
desc.read((desc.paddr + 0x10) as usize, &mut buffer).unwrap();
assert_eq!(buffer, [0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1]);
desc.read((desc.paddr + 97) as usize, &mut buffer).unwrap();
assert_eq!(buffer, [0x41, 0xc1, 0x02, 0xc3, 0xc5, 0x88, 0x4d, 0xd5]);
}
#[test]
fn test_desc_read() {
operate_on_file(&test_desc_read_cb, DATA)
}
fn test_desc_has_paddr_cb(path: &Path) {
let mut plugin = defaultplugin::plugin();
let mut desc = RIODesc::open(&mut *plugin, &path.to_string_lossy(), IoMode::READ).unwrap();
desc.paddr = 0x40000;
assert_eq!(desc.has_paddr(0x40000), true);
assert_eq!(desc.has_paddr(0x5), false);
assert_eq!(desc.has_paddr(0x40000 + DATA.len() as u64), false);
assert_eq!(desc.has_paddr(0x40000 + DATA.len() as u64 - 1), true);
}
#[test]
fn test_desc_has_paddr() {
operate_on_file(&test_desc_has_paddr_cb, DATA);
}
fn test_desc_read_errors_cb(path: &Path) {
let mut plugin = defaultplugin::plugin();
let mut desc = RIODesc::open(&mut *plugin, &path.to_string_lossy(), IoMode::READ).unwrap();
desc.paddr = 0x40000;
let mut buffer: &mut [u8] = &mut [0; 8];
let mut e = desc.read((desc.paddr + desc.size) as usize, &mut buffer);
match e {
Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
_ => assert!(true, "UnexpectedEof Error should have been generated"),
};
e = desc.read((desc.paddr + desc.size - 5) as usize, &mut buffer);
match e {
Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
_ => assert!(true, "UnexpectedEof Error should have been generated"),
};
let mut v: Vec<u8> = vec![0; (desc.size + 8) as usize];
buffer = &mut v;
e = desc.read(desc.paddr as usize, &mut buffer);
match e {
Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
_ => assert!(true, "UnexpectedEof Error should have been generated"),
};
}
#[test]
fn test_desc_read_errors() {
operate_on_file(&test_desc_read_errors_cb, DATA);
}
fn test_desc_write_cb(path: &Path) {
let mut plugin = defaultplugin::plugin();
let mut desc = RIODesc::open(&mut *plugin, &path.to_string_lossy(), IoMode::READ | IoMode::WRITE).unwrap();
let mut buffer: &mut [u8] = &mut [0; 8];
desc.paddr = 0x40000;
desc.write(desc.paddr as usize, &buffer).unwrap();
desc.read(desc.paddr as usize, &mut buffer).unwrap();
assert_eq!(buffer, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
desc.write((desc.paddr + 0x10) as usize, &buffer).unwrap();
desc.read((desc.paddr + 0x10) as usize, &mut buffer).unwrap();
assert_eq!(buffer, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
desc.write((desc.paddr + 97) as usize, &buffer).unwrap();
desc.read((desc.paddr + 97) as usize, &mut buffer).unwrap();
assert_eq!(buffer, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
}
#[test]
fn test_desc_write() {
operate_on_file(&test_desc_write_cb, DATA);
}
fn test_write_errors_cb(path: &Path) {
let mut plugin = defaultplugin::plugin();
let mut desc = RIODesc::open(&mut *plugin, &path.to_string_lossy(), IoMode::READ | IoMode::WRITE).unwrap();
let mut buffer: &[u8] = &[0; 8];
desc.paddr = 0x40000;
let mut e = desc.write((desc.paddr + desc.size) as usize, &buffer);
match e {
Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
_ => assert!(true, "UnexpectedEof Error should have been generated"),
};
e = desc.write((desc.paddr + desc.size - 5) as usize, &buffer);
match e {
Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
_ => assert!(true, "UnexpectedEof Error should have been generated"),
};
let v: Vec<u8> = vec![0; (desc.size + 8) as usize];
buffer = &v;
e = desc.write(desc.paddr as usize, &mut buffer);
match e {
Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
_ => assert!(true, "UnexpectedEof Error should have been generated"),
};
}
#[test]
fn test_write_errors() {
operate_on_file(&test_write_errors_cb, DATA);
}
}