diff options
author | Ben Bridle <ben@derelict.engineering> | 2024-08-07 17:09:14 +1200 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2024-08-07 17:09:14 +1200 |
commit | 38d40a2c5d4b553f524d87755b8e2e0e47928b8a (patch) | |
tree | 01fd01820be4219ca9f3dc7ad6e61eb183ade963 /src/devices/file/directory_listing.rs | |
parent | 65b53003e8de9543ba25a3b3d3cace399b92dc1d (diff) | |
download | bedrock-pc-38d40a2c5d4b553f524d87755b8e2e0e47928b8a.zip |
Refactor the file device
This is the Windows side of the refactoring job. The windows crate has
been added as a dependency in order to get a list of available drives
by drive letter, and a virtual top-level root directory has been
implemented in the Windows code to make it possible for programs to
hierarchically navigate between available drives.
Diffstat (limited to 'src/devices/file/directory_listing.rs')
-rw-r--r-- | src/devices/file/directory_listing.rs | 76 |
1 files changed, 49 insertions, 27 deletions
diff --git a/src/devices/file/directory_listing.rs b/src/devices/file/directory_listing.rs index 0cbbde9..febc5c2 100644 --- a/src/devices/file/directory_listing.rs +++ b/src/devices/file/directory_listing.rs @@ -2,12 +2,13 @@ use super::*; pub struct DirectoryListing { - children: Vec<DirectoryChild>, + children: Vec<BedrockFilePath>, length: u32, selected: Option<u32>, name_buffer: CircularPathBuffer, } + impl DirectoryListing { pub fn from_path(path: &BedrockFilePath) -> Option<Self> { macro_rules! unres { @@ -17,32 +18,29 @@ impl DirectoryListing { ($option:expr) => { match $option { Some(v) => v, None => continue} }; } - let mut children = Vec::new(); - 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; + #[cfg(target_family = "windows")] { + if path.as_path().components().count() == 0 { + return Some(Self::construct_virtual_root()) } + } - 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 { + let mut children = Vec::new(); + if let Ok(dir_listing) = std::fs::read_dir(path.as_path()) { + 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.is_hidden() { continue; - }; + } - let child = DirectoryChild { path: entry_path, entry_type }; - children.push(child); + children.push(entry_path); + } } children.sort(); @@ -52,8 +50,32 @@ impl DirectoryListing { Some( Self { children, length, selected, name_buffer } ) } + /// Generate entries for a virtual root directory. + #[cfg(target_family = "windows")] + fn construct_virtual_root() -> Self { + let mut children = Vec::new(); + let base = PathBuf::from(""); + let drive_bits = unsafe { + windows::Win32::Storage::FileSystem::GetLogicalDrives() + }; + for i in 0..26 { + if drive_bits & (0x1 << i) != 0 { + let letter: char = (b'A' + i).into(); + let path = PathBuf::from(format!("{letter}:/")); + if let Some(drive) = BedrockFilePath::from_path(&path, &base) { + children.push(drive); + } + } + } + + let length = children.len() as u32; + let selected = None; + let name_buffer = CircularPathBuffer::new(); + Self { children, length, selected, name_buffer } + } + /// Attempts to return a directory child by index. - pub fn get(&self, index: u32) -> Option<&DirectoryChild> { + pub fn get(&self, index: u32) -> Option<&BedrockFilePath> { self.children.get(index as usize) } @@ -69,7 +91,7 @@ impl DirectoryListing { /// Attempts to select a child by index. pub fn set_selected(&mut self, index: u32) { if let Some(child) = self.get(index) { - let buffer = child.path.as_buffer(); + let buffer = child.as_buffer(); self.name_buffer.populate(buffer); self.selected = Some(index); } else { @@ -83,11 +105,11 @@ impl DirectoryListing { } pub fn child_type(&self) -> Option<EntryType> { - self.selected.and_then(|s| self.get(s).and_then(|i| Some(i.entry_type))) + self.selected.and_then(|s| self.get(s).and_then(|i| i.entry_type())) } pub fn child_path(&self) -> Option<BedrockFilePath> { - self.selected.and_then(|s| self.get(s).and_then(|i| Some(i.path.clone()))) + self.selected.and_then(|s| self.get(s).and_then(|i| Some(i.clone()))) } } |