summaryrefslogtreecommitdiff
path: root/src/devices/file.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/file.rs')
-rw-r--r--src/devices/file.rs201
1 files changed, 82 insertions, 119 deletions
diff --git a/src/devices/file.rs b/src/devices/file.rs
index d53db0b..26e14da 100644
--- a/src/devices/file.rs
+++ b/src/devices/file.rs
@@ -1,42 +1,23 @@
+mod bedrock_file_path;
mod buffered_file;
mod circular_path_buffer;
-mod directory_entry;
+mod directory_child;
mod directory_listing;
mod entry;
mod operations;
+pub use bedrock_file_path::*;
pub use buffered_file::*;
pub use circular_path_buffer::*;
-pub use directory_entry::*;
+pub use directory_child::*;
pub use directory_listing::*;
pub use entry::*;
use operations::*;
-#[cfg(target_family = "unix")]
-use std::os::unix::ffi::OsStrExt;
-use std::fs::{OpenOptions, metadata};
use std::path::{Component, Path, PathBuf};
-fn is_blank_path(path: &Path) -> bool {
- path == PathBuf::new()
-}
-
-fn bytes_to_path(bytes: &[u8]) -> PathBuf {
- #[cfg(target_family = "unix")]
- let os_string: std::ffi::OsString = {
- std::os::unix::ffi::OsStringExt::from_vec(Vec::from(bytes))
- };
- #[cfg(target_family = "windows")]
- let os_string: std::ffi::OsString = {
- let wide: Vec<u16> = bytes.iter().map(|b| *b as u16).collect();
- std::os::windows::ffi::OsStringExt::from_wide(&wide)
- };
- os_string.into()
-}
pub struct FileDevice {
- /// The path to which the file device is confined. Files and directories
- /// outside of this directory cannot be accessed.
pub base_path: PathBuf,
pub default_path: PathBuf,
@@ -44,108 +25,104 @@ pub struct FileDevice {
pub move_buffer: CircularPathBuffer,
pub name_buffer: CircularPathBuffer,
- pub entry: Option<(Entry, PathBuf)>,
+ pub entry: Option<(Entry, BedrockFilePath)>,
- pub op_success: bool,
- pub new_pointer: u32,
- pub new_length: u32,
+ pub success: bool,
+ pub pointer: u32,
+ pub length: u32,
+ pub enable_read: bool,
+ pub enable_write: bool,
pub enable_create: bool,
pub enable_move: bool,
pub enable_delete: bool,
- pub enable_read: bool,
- pub enable_write: bool,
}
impl FileDevice {
pub fn new() -> Self {
+ #[cfg(target_family = "unix")]
+ let default_base: PathBuf = PathBuf::from("/");
+ #[cfg(target_family = "windows")]
+ let default_base: PathBuf = PathBuf::from("");
+
Self {
- base_path: PathBuf::from("/"),
+ base_path: default_base,
default_path: match std::env::current_dir() {
Ok(dir) => PathBuf::from(dir),
- Err(_) => PathBuf::from("/"),
+ Err(_) => PathBuf::from(""),
},
+
open_buffer: CircularPathBuffer::new(),
move_buffer: CircularPathBuffer::new(),
name_buffer: CircularPathBuffer::new(),
entry: None,
- op_success: false,
- new_pointer: 0,
- new_length: 0,
+ success: false,
+ pointer: 0,
+ length: 0,
+ enable_read: true,
+ enable_write: true,
enable_create: true,
enable_move: true,
enable_delete: false,
- enable_read: true,
- enable_write: true,
}
}
+ /// Commit any pending writes to the currently-open file.
pub fn flush_entry(&mut self) {
if let Some((Entry::File(buffered_file), _)) = &mut self.entry {
buffered_file.flush();
}
}
+ /// Safely close the currently-open entry, cleaning up entry variables.
pub fn close_entry(&mut self) {
self.open_buffer.clear();
self.move_buffer.clear();
self.name_buffer.clear();
self.flush_entry();
self.entry = None;
- self.new_pointer = 0;
- self.new_length = 0;
+ self.pointer = 0;
+ self.length = 0;
}
+ /// Process a byte received from the OPEN port.
pub fn write_to_open_port(&mut self, byte: u8) {
- if let Some(relative_path) = self.open_buffer.push_byte(byte) {
+ if let Some(buffer) = self.open_buffer.push_byte(byte) {
self.close_entry();
- if !is_blank_path(&relative_path) {
- if let Ok(path) = self.attach_base(&relative_path) {
- let _ = self.open_entry(&path);
- };
+ if let Some(path) = BedrockFilePath::from_buffer(buffer, &self.base_path) {
+ self.success = self.open_entry(path).is_ok();
}
}
}
- pub fn set_name_pointer(&mut self, byte: u8) {
- self.name_buffer.set_pointer(byte);
- }
-
- /// Open the entry at the given path.
- pub fn open_entry(&mut self, path: &Path) -> Result<(), ()> {
- macro_rules! raise_on_err {
- ($res:expr) => {match $res {Ok(v)=>v, Err(_)=>return Err(())} } }
-
- if !path.starts_with(&self.base_path) { return Err(()); }
- let metadata = raise_on_err!(metadata(&path));
+ /// Opens the entry at the given path.
+ pub fn open_entry(&mut self, path: BedrockFilePath) -> Result<(), ()> {
+ macro_rules! unres {
+ ($result:expr) => { match $result {Ok(v)=>v,Err(_)=>return Err(())} };
+ }
+ let absolute_path = path.as_path();
+ let metadata = unres!(std::fs::metadata(&absolute_path));
if metadata.is_file() {
- let open_result = OpenOptions::new()
+ let open_result = std::fs::OpenOptions::new()
.read(self.enable_read)
.write(self.enable_write)
- .open(&path);
+ .open(&absolute_path);
+ // Keep the current entry open if we can't open the new path.
if let Ok(file) = open_result {
self.close_entry();
- let file_entry = Entry::File(BufferedFile::new(file));
- self.entry = Some((file_entry, path.to_owned()));
- let relative = remove_base(&path, &self.base_path).unwrap();
- #[cfg(target_family = "unix")]
- self.name_buffer.populate(relative.as_os_str().as_bytes());
- #[cfg(target_family = "windows")]
- self.name_buffer.populate(relative.as_os_str().as_encoded_bytes());
+ self.name_buffer.populate(path.as_buffer());
+ self.entry = Some((Entry::File(BufferedFile::new(file)), path));
return Ok(());
};
} else if metadata.is_dir() {
- if let Ok(listing) = DirectoryListing::from_path(&path, &self.base_path) {
- let dir_entry = Entry::Directory(listing);
- self.entry = Some((dir_entry, path.to_owned()));
- let relative = remove_base(&path, &self.base_path).unwrap();
- #[cfg(target_family = "unix")]
- self.name_buffer.populate(relative.as_os_str().as_bytes());
- #[cfg(target_family = "windows")]
- self.name_buffer.populate(relative.as_os_str().as_encoded_bytes());
+ // Keep the current entry open if we can't open the new path.
+ if let Some(listing) = path.directory_listing() {
+ self.close_entry();
+ self.name_buffer.populate(path.as_buffer());
+ self.entry = Some((Entry::Directory(listing), path));
return Ok(());
};
};
@@ -153,58 +130,60 @@ impl FileDevice {
}
pub fn write_to_move_port(&mut self, byte: u8) {
- if let Some(dest) = self.move_buffer.push_byte(byte) {
+ if let Some(buffer) = self.move_buffer.push_byte(byte) {
+ let blank_destination = buffer[0] == 0x00;
+ let destination = BedrockFilePath::from_buffer(buffer, &self.base_path);
+ self.success = false;
+
if let Some((_, source)) = &self.entry {
- if is_blank_path(&dest) {
- match self.enable_delete {
- true => self.op_success = delete_entry(&source),
- false => self.op_success = false,
+ if blank_destination {
+ if self.enable_delete {
+ self.success = delete_entry(&source.as_path());
}
- } else if let Ok(destination) = self.attach_base(&dest) {
- match self.enable_move {
- true => self.op_success = move_entry(&source, &destination),
- false => self.op_success = false,
+ } else if let Some(dest) = destination {
+ if self.enable_move {
+ self.success = move_entry(&source.as_path(), &dest.as_path());
}
}
- } else {
- if is_blank_path(&dest) {
- self.op_success = false;
- } else if let Ok(destination) = self.attach_base(&dest) {
- match self.enable_create {
- true => self.op_success = create_file(&destination),
- false => self.op_success = false,
- }
+ } else if let Some(dest) = destination {
+ if self.enable_create {
+ self.success = create_file(&dest.as_path());
}
}
+
self.close_entry();
}
}
/// Attempt to open the parent directory of the current entry.
pub fn ascend_to_parent(&mut self) {
+ self.success = false;
if let Some((_, path)) = &self.entry {
if let Some(parent_path) = path.parent() {
- self.op_success = self.open_entry(&parent_path.to_owned()).is_ok();
- } else {
- self.op_success = false;
+ self.success = self.open_entry(parent_path).is_ok();
}
} else {
- self.op_success = self.open_entry(&self.default_path.to_owned()).is_ok();
+ if let Some(default) = BedrockFilePath::from_path(&self.default_path, &self.base_path) {
+ self.success = self.open_entry(default).is_ok();
+ }
}
}
- /// Attempt to open the currently-selected child.
+ /// Attempt to open the currently-selected child of the current directory.
pub fn descend_to_child(&mut self) {
+ self.success = false;
if let Some((Entry::Directory(listing), _)) = &self.entry {
if let Some(child_path) = listing.child_path() {
- if let Ok(child_path) = self.attach_base(&child_path) {
- self.op_success = self.open_entry(&child_path).is_ok();
- }
+ self.success = self.open_entry(child_path).is_ok();
};
}
}
- /// Return true if the currently-open entry is a directory.
+ pub fn set_name_pointer(&mut self, value: u8) {
+ self.name_buffer.set_pointer(value);
+ }
+
+ /// Returns true if the currently-open entry is a directory.
pub fn entry_type(&self) -> bool {
match self.entry {
Some((Entry::Directory(_), _)) => true,
@@ -212,7 +191,7 @@ impl FileDevice {
}
}
- /// Return true if the currently-selected child is a directory.
+ /// Reads a byte from the name buffer of the currently-selected child.
pub fn read_child_name(&mut self) -> u8 {
if let Some((Entry::Directory(listing), _)) = &mut self.entry {
listing.child_name().read_byte()
@@ -227,7 +206,7 @@ impl FileDevice {
}
}
- /// Return true if the currently-selected child is a directory.
+ /// Returns true if the currently-selected child is a directory.
pub fn child_type(&self) -> bool {
if let Some((Entry::Directory(listing), _)) = &self.entry {
match listing.child_type() {
@@ -240,6 +219,7 @@ impl FileDevice {
}
}
+ /// Reads a byte from the currently-open file.
pub fn read_byte(&mut self) -> u8 {
match &mut self.entry {
Some((Entry::File(buffered_file), _)) => buffered_file.read_byte(),
@@ -247,6 +227,7 @@ impl FileDevice {
}
}
+ /// Writes a byte to the currently-open file.
pub fn write_byte(&mut self, byte: u8) {
match &mut self.entry {
Some((Entry::File(buffered_file), _)) => buffered_file.write_byte(byte),
@@ -263,7 +244,7 @@ impl FileDevice {
}
pub fn commit_pointer(&mut self) {
- let pointer = std::mem::take(&mut self.new_pointer);
+ let pointer = std::mem::take(&mut self.pointer);
match &mut self.entry {
Some((Entry::File(buffered_file), _)) => buffered_file.set_pointer(pointer),
Some((Entry::Directory(listing), _)) => listing.set_selected(pointer),
@@ -280,30 +261,12 @@ impl FileDevice {
}
pub fn commit_length(&mut self) {
- let length = std::mem::take(&mut self.new_length);
+ let length = std::mem::take(&mut self.length);
match &mut self.entry {
Some((Entry::File(buffered_file), _)) => buffered_file.set_length(length),
_ => (),
}
}
-
- fn attach_base(&self, relative_path: &Path) -> Result<PathBuf, ()> {
- let mut full_path = self.base_path.clone();
- let mut has_root = false;
- for component in relative_path.components() {
- match component {
- Component::Normal(s) => full_path.push(s),
- Component::ParentDir => return Err(()),
- Component::CurDir => continue,
- Component::RootDir => has_root = true,
- Component::Prefix(_) => continue,
- }
- };
- match has_root {
- true => Ok(full_path),
- false => Err(())
- }
- }
}
impl Drop for FileDevice {