summaryrefslogtreecommitdiff
path: root/src/devices/file/directory_listing.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/file/directory_listing.rs')
-rw-r--r--src/devices/file/directory_listing.rs121
1 files changed, 43 insertions, 78 deletions
diff --git a/src/devices/file/directory_listing.rs b/src/devices/file/directory_listing.rs
index 341f353..0cbbde9 100644
--- a/src/devices/file/directory_listing.rs
+++ b/src/devices/file/directory_listing.rs
@@ -1,5 +1,6 @@
use super::*;
+
pub struct DirectoryListing {
children: Vec<DirectoryChild>,
length: u32,
@@ -8,51 +9,50 @@ pub struct DirectoryListing {
}
impl DirectoryListing {
- pub fn from_path(path: &Path, base: &Path) -> Result<Self, ()> {
- macro_rules! continue_on_err {
+ pub fn from_path(path: &BedrockFilePath) -> Option<Self> {
+ macro_rules! unres {
($result:expr) => { match $result { Ok(v) => v, Err(_) => continue} };
}
+ macro_rules! unopt {
+ ($option:expr) => { match $option { Some(v) => v, None => continue} };
+ }
let mut children = Vec::new();
- if let Ok(iter_dir) = std::fs::read_dir(path) {
- for (i, entry_result) in iter_dir.enumerate() {
- if i == u16::MAX as usize {
- eprintln!("Warning, {path:?} contains more than 65536 entries.")
- };
- let entry = continue_on_err!(entry_result);
- let path = continue_on_err!(remove_base(&entry.path(), &base));
- #[cfg(target_family = "unix")]
- let byte_path = path.as_os_str().as_bytes();
- #[cfg(target_family = "windows")]
- let byte_path = path.as_os_str().as_encoded_bytes();
- if byte_path.len() > 255 {
+ let dir_listing = std::fs::read_dir(path.as_path()).ok()?;
+ for (i, entry_result) in dir_listing.enumerate() {
+ // Firebreak to prevent emulator from consuming an absurd amount
+ // of memory when opening too large of a directory.
+ if i == (u16::MAX as usize) {
+ break;
+ }
+
+ let entry = unres!(entry_result);
+ let entry_path = unopt!(BedrockFilePath::from_path(&entry.path(), path.base()));
+ if entry_path.filename_is_dot_prefixed() {
+ continue;
+ }
+ let metadata = unres!(std::fs::metadata(&entry.path()));
+ let entry_type =
+ if metadata.is_file() {
+ EntryType::File
+ } else if metadata.is_dir() {
+ EntryType::Directory
+ } else {
continue;
};
- if filename_dot_prefixed(&path) {
- continue;
- }
- let metadata = continue_on_err!(std::fs::metadata(&entry.path()));
- children.push( DirectoryChild {
- byte_path: Vec::from(byte_path),
- entry_type: if metadata.is_file() {
- EntryType::File
- } else if metadata.is_dir() {
- EntryType::Directory
- } else {
- continue;
- },
- } )
- }
- children.sort_unstable();
- let length = u32::try_from(children.len()).unwrap_or(u32::MAX);
- let selected = None;
- let name_buffer = CircularPathBuffer::new();
- Ok(Self { children, length, selected, name_buffer } )
- } else {
- Err(())
+
+ let child = DirectoryChild { path: entry_path, entry_type };
+ children.push(child);
}
+
+ children.sort();
+ let length = u32::try_from(children.len()).ok()?;
+ let selected = None;
+ let name_buffer = CircularPathBuffer::new();
+ Some( Self { children, length, selected, name_buffer } )
}
+ /// Attempts to return a directory child by index.
pub fn get(&self, index: u32) -> Option<&DirectoryChild> {
self.children.get(index as usize)
}
@@ -61,13 +61,16 @@ impl DirectoryListing {
self.length
}
+ /// Returns the index of the selected child, or zero if no child is selected.
pub fn selected(&self) -> u32 {
self.selected.unwrap_or(0)
}
+ /// Attempts to select a child by index.
pub fn set_selected(&mut self, index: u32) {
- if let Some(info) = self.get(index) {
- self.name_buffer.populate(&info.byte_path.clone());
+ if let Some(child) = self.get(index) {
+ let buffer = child.path.as_buffer();
+ self.name_buffer.populate(buffer);
self.selected = Some(index);
} else {
self.name_buffer.clear();
@@ -83,46 +86,8 @@ impl DirectoryListing {
self.selected.and_then(|s| self.get(s).and_then(|i| Some(i.entry_type)))
}
- pub fn child_path(&self) -> Option<PathBuf> {
- self.selected.and_then(|s| self.get(s).and_then(|i| {
- Some(bytes_to_path(&i.byte_path))
- }))
- }
-}
-
-pub fn remove_base(absolute_path: &Path, base_path: &Path) -> Result<PathBuf, ()> {
- if let Ok(relative) = absolute_path.strip_prefix(base_path) {
- let mut baseless_path = PathBuf::from("/");
- for component in relative.components() {
- match component {
- Component::Normal(s) => baseless_path.push(s),
- Component::ParentDir => return Err(()),
- Component::CurDir => continue,
- Component::RootDir => continue,
- Component::Prefix(_) => continue,
- }
- }
- return Ok(baseless_path);
+ pub fn child_path(&self) -> Option<BedrockFilePath> {
+ self.selected.and_then(|s| self.get(s).and_then(|i| Some(i.path.clone())))
}
- return Err(());
}
-// Returns true if a dot character directly follows the right-most
-// forward-slash character in the path.
-fn filename_dot_prefixed(path: &Path) -> bool {
- #[cfg(target_family = "unix")]
- let bytes = path.as_os_str().as_bytes();
- #[cfg(target_family = "windows")]
- let bytes = path.as_os_str().as_encoded_bytes();
- // Find position of final forward-slash byte.
- let mut final_slash = None;
- for (i, byte) in bytes.iter().enumerate() {
- if *byte == b'/' { final_slash = Some(i) }
- }
- if let Some(i) = final_slash {
- if let Some(b'.') = bytes.get(i+1) {
- return true;
- }
- }
- return false;
-}