diff options
author | Ben Bridle <ben@derelict.engineering> | 2025-07-08 12:00:02 +1200 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2025-07-08 12:00:23 +1200 |
commit | f2bcc24eec84c4632c88b5a35821f7e642d41dc5 (patch) | |
tree | e45e5e69a52d49f617e23920b37bd769bb067878 | |
parent | 82a10fb3ae8c935e6c325a1b458e7fe6c0b90df6 (diff) | |
download | bedrock-pc-f2bcc24eec84c4632c88b5a35821f7e642d41dc5.zip |
Invalidate the cached directory in the file device after a duration
The most recent directory accessed by the file device is cached to
improve performance when rapidly ascending and descending between
sibling entries. This causes an issue where, in a sandboxed root
directory that contains only files, a program will be unable to
invalidate the cache and any changes to the directory outside the
program will not be seen by the program.
To fix this, the directory cache now only lasts for one second.
-rw-r--r-- | src/devices/file_device.rs | 54 |
1 files changed, 27 insertions, 27 deletions
diff --git a/src/devices/file_device.rs b/src/devices/file_device.rs index 43bb239..73f05cc 100644 --- a/src/devices/file_device.rs +++ b/src/devices/file_device.rs @@ -9,8 +9,8 @@ pub struct FileDevice { pub action_buffer: BedrockPathBuffer, pub path_buffer: BedrockPathBuffer, - pub entry: Option<(Entry, BedrockFilePath)>, - pub cached_dir: Option<(Entry, BedrockFilePath)>, + pub entry: Option<(Entry, BedrockFilePath, Instant)>, + pub cached_dir: Option<(Entry, BedrockFilePath, Instant)>, pub success: bool, pub pointer_write: u32, @@ -141,10 +141,10 @@ impl FileDevice { self.path_buffer.clear(); self.flush(); - if let Some((Entry::Directory(mut dir), path)) = std::mem::take(&mut self.entry) { + if let Some((Entry::Directory(mut dir), path, time)) = std::mem::take(&mut self.entry) { // Prevent the selected child from persisting when loading from cache. dir.deselect_child(); - self.cached_dir = Some((Entry::Directory(dir), path)); + self.cached_dir = Some((Entry::Directory(dir), path, time)); } } @@ -160,17 +160,17 @@ impl FileDevice { if let Ok(file) = open_result { self.close(); self.path_buffer.populate(path.as_buffer()); - self.entry = Some((Entry::File(BufferedFile::new(file)), path)); + self.entry = Some((Entry::File(BufferedFile::new(file)), path, Instant::now())); return Ok(()); }; } Some(EntryType::Directory) => { - // Attempt to use the cached directory. - if let Some((dir, cached_path)) = std::mem::take(&mut self.cached_dir) { - if cached_path == path { + // Attempt to use the cached directory if not too old. + if let Some((dir, cached_path, time)) = std::mem::take(&mut self.cached_dir) { + if cached_path == path && time.elapsed() < Duration::from_secs(1) { self.close(); self.path_buffer.populate(cached_path.as_buffer()); - self.entry = Some((dir, cached_path)); + self.entry = Some((dir, cached_path, time)); return Ok(()); } } @@ -178,7 +178,7 @@ impl FileDevice { if let Some(listing) = DirectoryListing::from_path(&path) { self.close(); self.path_buffer.populate(path.as_buffer()); - self.entry = Some((Entry::Directory(listing), path)); + self.entry = Some((Entry::Directory(listing), path, Instant::now())); return Ok(()); }; } @@ -206,7 +206,7 @@ impl FileDevice { let destination = BedrockFilePath::from_buffer(buffer, &self.base_path); self.success = false; - if let Some((_, source)) = &self.entry { + if let Some((_, source, _)) = &self.entry { if destination_blank { if self.enable_delete { self.success = delete_entry(&source.as_path()); @@ -227,7 +227,7 @@ impl FileDevice { /// Attempt to open the parent directory of the current entry. pub fn ascend_to_parent(&mut self) { - if let Some((_, path)) = &self.entry { + if let Some((_, path, _)) = &self.entry { match path.parent() { Some(parent) => self.success = self.open(parent).is_ok(), None => self.success = false, @@ -242,7 +242,7 @@ impl FileDevice { /// Attempt to open the selected child of the current directory. pub fn descend_to_child(&mut self) { - if let Some((Entry::Directory(dir), _)) = &self.entry { + if let Some((Entry::Directory(dir), _, _)) = &self.entry { match dir.child_path() { Some(child) => self.success = self.open(child).is_ok(), None => self.success = false, @@ -255,7 +255,7 @@ impl FileDevice { /// Return true if the current entry is a directory. pub fn entry_type(&self) -> bool { match self.entry { - Some((Entry::Directory(_), _)) => true, + Some((Entry::Directory(_), _, _)) => true, _ => false, } } @@ -263,13 +263,13 @@ impl FileDevice { /// Read a byte from the path buffer of the selected child. pub fn read_child_path(&mut self) -> u8 { match &mut self.entry { - Some((Entry::Directory(dir), _)) => dir.child_path_buffer().read(), + Some((Entry::Directory(dir), _, _)) => dir.child_path_buffer().read(), _ => 0, } } pub fn set_child_path(&mut self, byte: u8) { - if let Some((Entry::Directory(dir), _)) = &mut self.entry { + if let Some((Entry::Directory(dir), _, _)) = &mut self.entry { dir.child_path_buffer().set_pointer(byte); } } @@ -277,7 +277,7 @@ impl FileDevice { /// Return true if the selected child is a directory. pub fn child_type(&self) -> bool { match &self.entry { - Some((Entry::Directory(dir), _)) => match dir.child_type() { + Some((Entry::Directory(dir), _, _)) => match dir.child_type() { Some(EntryType::Directory) => true, _ => false, } @@ -288,7 +288,7 @@ impl FileDevice { /// Read a byte from the current file. pub fn read_byte(&mut self) -> u8 { match &mut self.entry { - Some((Entry::File(file), _)) => file.read(), + Some((Entry::File(file), _, _)) => file.read(), _ => 0, } } @@ -296,44 +296,44 @@ 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(file), _)) => file.write(byte), + Some((Entry::File(file), _, _)) => file.write(byte), _ => (), } } pub fn pointer(&mut self) -> u32 { match &mut self.entry { - Some((Entry::File(file), _)) => file.pointer(), - Some((Entry::Directory(dir), _)) => dir.selected(), + Some((Entry::File(file), _, _)) => file.pointer(), + Some((Entry::Directory(dir), _, _)) => dir.selected(), _ => 0, } } pub fn commit_pointer(&mut self) { match &mut self.entry { - Some((Entry::File(file), _)) => file.set_pointer(self.pointer_write), - Some((Entry::Directory(dir), _)) => dir.set_selected(self.pointer_write), + Some((Entry::File(file), _, _)) => file.set_pointer(self.pointer_write), + Some((Entry::Directory(dir), _, _)) => dir.set_selected(self.pointer_write), _ => (), } } pub fn length(&mut self) -> u32 { match &mut self.entry { - Some((Entry::File(file), _)) => file.length(), - Some((Entry::Directory(dir), _)) => dir.length(), + Some((Entry::File(file), _, _)) => file.length(), + Some((Entry::Directory(dir), _, _)) => dir.length(), _ => 0, } } pub fn commit_length(&mut self) { match &mut self.entry { - Some((Entry::File(file), _)) => file.set_length(self.length_write), + Some((Entry::File(file), _, _)) => file.set_length(self.length_write), _ => (), } } pub fn flush(&mut self) { - if let Some((Entry::File(buffered_file), _)) = &mut self.entry { + if let Some((Entry::File(buffered_file), _, _)) = &mut self.entry { let _ = buffered_file; } } |