aboutsummaryrefslogtreecommitdiff
path: root/src/client/fs/fh.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/fs/fh.rs')
-rw-r--r--src/client/fs/fh.rs110
1 files changed, 110 insertions, 0 deletions
diff --git a/src/client/fs/fh.rs b/src/client/fs/fh.rs
new file mode 100644
index 0000000..b1e8739
--- /dev/null
+++ b/src/client/fs/fh.rs
@@ -0,0 +1,110 @@
+use crate::{common::temp_file, server::Stream};
+use log::error;
+use std::{
+ fs::{self, File},
+ io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write},
+ ops::Index,
+ path::PathBuf,
+ slice::SliceIndex,
+};
+
+pub struct FileHandle {
+ buffer: Vec<u8>,
+ size: usize,
+ tmp: Option<(PathBuf, BufWriter<File>)>,
+ reader: Option<BufReader<File>>,
+ dirty: bool,
+}
+
+impl FileHandle {
+ pub fn empty() -> std::io::Result<Self> {
+ let (temp_path, temp_file) = temp_file()?;
+
+ Ok(Self {
+ buffer: Vec::new(),
+ size: 0,
+ tmp: Some((temp_path, BufWriter::new(temp_file))),
+ reader: None,
+ dirty: false,
+ })
+ }
+
+ pub fn new_rw(reader: BufReader<File>) -> std::io::Result<Self> {
+ // TODO: Copy read to tmp
+ let (temp_path, temp_file) = temp_file()?;
+
+ Ok(Self {
+ buffer: Vec::new(),
+ size: 0,
+ tmp: Some((temp_path, BufWriter::new(temp_file))),
+ reader: Some(reader),
+ dirty: false,
+ })
+ }
+
+ pub fn new_ro(reader: BufReader<File>) -> Self {
+ Self {
+ buffer: Vec::new(),
+ size: 0,
+ tmp: None,
+ reader: Some(reader),
+ dirty: false,
+ }
+ }
+
+ pub fn is_dirty(&self) -> bool {
+ self.dirty
+ }
+
+ pub fn write(&mut self, data: &[u8], offset: usize) -> Option<usize> {
+ let Some((_, ref mut tmp)) = self.tmp else {
+ error!("Tried to write to a RO file handle");
+ return None;
+ };
+
+ tmp.seek(SeekFrom::Start(offset as u64))
+ .inspect_err(|e| error!("Seek error: {e}"))
+ .ok()?;
+ let written = tmp
+ .write(data)
+ .inspect_err(|e| error!("Write error: {e}"))
+ .ok()?;
+
+ self.dirty = true;
+
+ Some(written)
+ }
+
+ pub fn read(&mut self, offset: usize, size: usize) -> Vec<u8> {
+ let Some(mut reader) = self.reader else {
+ error!("Tried to read from an empty file handle");
+ return Vec::new();
+ };
+
+ let mut buf = Vec::with_capacity(size);
+
+ // TODO: error handling...
+ reader.seek(SeekFrom::Start(offset as u64)).unwrap();
+ reader.read_exact(&mut buf).unwrap();
+
+ buf
+ }
+
+ pub fn clear(&mut self) {
+ self.tmp.as_mut().map(|b| b.1.flush());
+ self.buffer.clear();
+ self.dirty = false;
+ }
+}
+
+impl Drop for FileHandle {
+ fn drop(&mut self) {
+ let Some((ref temp_path, _)) = self.tmp else {
+ return;
+ };
+
+ if let Err(e) = fs::remove_file(temp_path) {
+ error!("Couldn't delete temp file {temp_path:?}: {e}");
+ }
+ }
+}