1use memmap::*;
18use plugin::*;
19use std::fs::OpenOptions;
20use std::io;
21use std::ops::Deref;
22use std::path::Path;
23use utils::*;
24enum FileInternals {
25 Map(Mmap),
26 MutMap(MmapMut),
27}
28
29impl FileInternals {
30 fn len(&self) -> usize {
31 match self {
32 FileInternals::Map(m) => return m.len(),
33 FileInternals::MutMap(m) => return m.len(),
34 }
35 }
36 fn as_mut(&mut self) -> Option<&mut MmapMut> {
37 if let FileInternals::MutMap(mutmap) = self {
38 return Some(mutmap);
39 } else {
40 return None;
41 }
42 }
43}
44const METADATA: RIOPluginMetadata = RIOPluginMetadata {
45 name: "FilePlugin",
46 desc: "This IO plugin is used to open normal files.",
47 author: "Oddcoder",
48 license: "LGPL",
49 version: "0.0.1",
50};
51impl Deref for FileInternals {
52 type Target = [u8];
53 fn deref(&self) -> &[u8] {
54 match self {
55 FileInternals::Map(m) => &**m,
56 FileInternals::MutMap(m) => &**m,
57 }
58 }
59}
60impl RIOPluginOperations for FileInternals {
61 fn read(&mut self, raddr: usize, buffer: &mut [u8]) -> Result<(), IoError> {
62 if self.len() < raddr + buffer.len() {
63 return Err(IoError::Parse(io::Error::new(io::ErrorKind::UnexpectedEof, "BufferOverflow")));
64 }
65 buffer.copy_from_slice(&self[raddr..raddr + buffer.len()]);
66 return Ok(());
67 }
68
69 fn write(&mut self, raddr: usize, buf: &[u8]) -> Result<(), IoError> {
70 if let Some(mutmap) = self.as_mut() {
71 if raddr + buf.len() > mutmap.len() {
72 return Err(IoError::Parse(io::Error::new(io::ErrorKind::UnexpectedEof, "BufferOverflow")));
73 }
74 mutmap[raddr..raddr + buf.len()].copy_from_slice(buf);
75 return Ok(());
76 } else {
77 return Err(IoError::Parse(io::Error::new(io::ErrorKind::PermissionDenied, "File Not Writable")));
78 }
79 }
80}
81
82struct FilePlugin {}
83
84impl FilePlugin {
85 fn uri_to_path(uri: &str) -> &Path {
86 let path = uri.trim_start_matches("file://");
87 return Path::new(path);
88 }
89}
90
91impl RIOPlugin for FilePlugin {
92 fn get_metadata(&self) -> &'static RIOPluginMetadata {
93 return &METADATA;
94 }
95
96 fn open(&mut self, uri: &str, flags: IoMode) -> Result<RIOPluginDesc, IoError> {
97 let file: FileInternals;
98 if !flags.contains(IoMode::READ) && flags.contains(IoMode::WRITE) {
99 return Err(IoError::Parse(io::Error::new(io::ErrorKind::PermissionDenied, "Can't Open File for writing without reading")));
100 }
101 if flags.contains(IoMode::READ) && flags.contains(IoMode::COW) {
103 return Err(IoError::Parse(io::Error::new(
104 io::ErrorKind::PermissionDenied,
105 "Can't Open File with permission as Read and Copy-On-Write",
106 )));
107 }
108 if flags.contains(IoMode::COW) {
109 let f = OpenOptions::new().read(true).open(FilePlugin::uri_to_path(uri))?;
110 file = FileInternals::MutMap(unsafe { MmapOptions::new().map_copy(&f)? });
111 } else if flags.contains(IoMode::WRITE) {
112 let f = OpenOptions::new().read(true).write(true).open(FilePlugin::uri_to_path(uri))?;
113 file = FileInternals::MutMap(unsafe { MmapOptions::new().map_mut(&f)? });
114 } else {
115 let f = OpenOptions::new().read(true).open(FilePlugin::uri_to_path(uri))?;
116 file = FileInternals::Map(unsafe { MmapOptions::new().map(&f)? });
117 }
118 let desc = RIOPluginDesc {
119 name: uri.to_owned(),
120 perm: flags,
121 raddr: 0,
122 size: (file.len() as u64),
123 plugin_operations: Box::new(file),
124 };
125 return Ok(desc);
126 }
127
128 fn accept_uri(&self, uri: &str) -> bool {
130 let split: Vec<&str> = uri.split("://").collect();
131 if split.len() == 1 {
132 return true;
133 }
134 if split[0] == "file" {
135 return true;
136 }
137 return false;
138 }
139}
140
141pub fn plugin() -> Box<dyn RIOPlugin> {
142 return Box::new(FilePlugin {});
143}
144
145#[cfg(test)]
146mod default_plugin_tests {
147 use super::*;
148 use test_file::*;
149 #[test]
150 fn test_plugin() {
151 let plugin = plugin();
152 let meta = plugin.get_metadata();
153 assert_eq!(plugin.accept_uri("/bin/ls"), true);
154 assert_eq!(plugin.accept_uri("file:///bin/ls"), true);
155 assert_eq!(plugin.accept_uri("ihex:///bin/ls"), false);
156 assert_eq!(meta.name, METADATA.name);
157 assert_eq!(meta.desc, METADATA.desc);
158 assert_eq!(meta.author, METADATA.author);
159 assert_eq!(meta.license, METADATA.license);
160 assert_eq!(meta.version, METADATA.version);
161 }
162
163 fn test_open_errors_cb(paths: &[&Path]) {
164 let mut plugin = plugin();
165 let custom_path = String::from("file://") + &paths[0].to_string_lossy();
166 plugin.open(&custom_path, IoMode::COW).unwrap();
167 plugin.open(&paths[1].to_string_lossy(), IoMode::READ).unwrap();
168 plugin.open(&paths[2].to_string_lossy(), IoMode::READ | IoMode::WRITE).unwrap();
169 let mut e = plugin.open(&paths[3].to_string_lossy(), IoMode::WRITE);
170 match e {
171 Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::PermissionDenied),
172 _ => assert!(false, "Permission Denied Error should have been generated"),
173 };
174
175 e = plugin.open(&paths[3].to_string_lossy(), IoMode::READ | IoMode::COW);
176 match e {
177 Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::PermissionDenied),
178 _ => assert!(false, "Permission Denied Error should have been generated"),
179 };
180
181 e = plugin.open(&paths[3].to_string_lossy(), IoMode::READ | IoMode::WRITE | IoMode::COW);
182 match e {
183 Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::PermissionDenied),
184 _ => assert!(false, "Permission Denied Error should have been generated"),
185 };
186 }
187 #[test]
188 fn test_open_errors() {
189 operate_on_files(&test_open_errors_cb, &[DATA, DATA, DATA, DATA]);
190 }
191 fn test_read_cb(path: &Path) {
192 let mut plugin = plugin();
193 let mut desc = plugin.open(&path.to_string_lossy(), IoMode::READ).unwrap();
194 let mut buffer: &mut [u8] = &mut [0; 8];
195 desc.plugin_operations.read(desc.raddr as usize, &mut buffer).unwrap();
197 assert_eq!(buffer, [0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d]);
198 desc.plugin_operations.read((desc.raddr + 0x10) as usize, &mut buffer).unwrap();
200 assert_eq!(buffer, [0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1]);
201 desc.plugin_operations.read((desc.raddr + 97) as usize, &mut buffer).unwrap();
203 assert_eq!(buffer, [0x41, 0xc1, 0x02, 0xc3, 0xc5, 0x88, 0x4d, 0xd5]);
204 }
205 #[test]
206 fn test_read() {
207 operate_on_file(&test_read_cb, DATA)
208 }
209
210 fn test_read_errors_cb(path: &Path) {
211 let mut plugin = plugin();
212 let mut desc = plugin.open(&path.to_string_lossy(), IoMode::READ).unwrap();
213 let mut buffer: &mut [u8] = &mut [0; 8];
214 let mut e = desc.plugin_operations.read((desc.raddr + desc.size) as usize, &mut buffer);
216 match e {
217 Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
218 _ => assert!(true, "UnexpectedEof Error should have been generated"),
219 };
220 e = desc.plugin_operations.read((desc.raddr + desc.size - 5) as usize, &mut buffer);
222 match e {
223 Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
224 _ => assert!(true, "UnexpectedEof Error should have been generated"),
225 };
226
227 let mut v: Vec<u8> = vec![0; (desc.size + 8) as usize];
229 buffer = &mut v;
230 e = desc.plugin_operations.read(desc.raddr as usize, &mut buffer);
231 match e {
232 Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
233 _ => assert!(true, "UnexpectedEof Error should have been generated"),
234 };
235 }
236 #[test]
237 fn test_read_errors() {
238 operate_on_file(&test_read_errors_cb, DATA);
239 }
240
241 fn test_write_cb(path: &Path) {
242 let mut plugin = plugin();
243 let mut desc = plugin.open(&path.to_string_lossy(), IoMode::READ | IoMode::WRITE).unwrap();
244 let mut buffer: &mut [u8] = &mut [0; 8];
245 desc.plugin_operations.write(desc.raddr as usize, &buffer).unwrap();
247 desc.plugin_operations.read(desc.raddr as usize, &mut buffer).unwrap();
248 assert_eq!(buffer, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
249 desc.plugin_operations.write((desc.raddr + 0x10) as usize, &buffer).unwrap();
251 desc.plugin_operations.read((desc.raddr + 0x10) as usize, &mut buffer).unwrap();
252 assert_eq!(buffer, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
253 desc.plugin_operations.write((desc.raddr + 97) as usize, &buffer).unwrap();
255 desc.plugin_operations.read((desc.raddr + 97) as usize, &mut buffer).unwrap();
256 assert_eq!(buffer, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
257 }
258
259 #[test]
260 fn test_write() {
261 operate_on_file(&test_write_cb, DATA);
262 }
263
264 fn test_write_errors_cb(path: &Path) {
265 let mut plugin = plugin();
266 let mut desc = plugin.open(&path.to_string_lossy(), IoMode::READ | IoMode::WRITE).unwrap();
267 let mut buffer: &[u8] = &[0; 8];
268 let mut e = desc.plugin_operations.write((desc.raddr + desc.size) as usize, &buffer);
270 match e {
271 Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
272 _ => assert!(true, "UnexpectedEof Error should have been generated"),
273 };
274 e = desc.plugin_operations.write((desc.raddr + desc.size - 5) as usize, &buffer);
276 match e {
277 Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
278 _ => assert!(true, "UnexpectedEof Error should have been generated"),
279 };
280 let v: Vec<u8> = vec![0; (desc.size + 8) as usize];
282 buffer = &v;
283 e = desc.plugin_operations.write(desc.raddr as usize, &mut buffer);
284 match e {
285 Err(IoError::Parse(io_err)) => assert_eq!(io_err.kind(), io::ErrorKind::UnexpectedEof),
286 _ => assert!(true, "UnexpectedEof Error should have been generated"),
287 };
288 }
289 #[test]
290 fn test_write_errors() {
291 operate_on_file(&test_write_errors_cb, DATA);
292 }
293}