From 43e1a12b5bce11b4a28a53acca243e35c2be6d3e Mon Sep 17 00:00:00 2001 From: evuez Date: Wed, 3 Apr 2024 22:43:16 +0200 Subject: Initial commit --- src/client/fs/fh.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/client/fs/fh.rs (limited to 'src/client/fs/fh.rs') 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, + size: usize, + tmp: Option<(PathBuf, BufWriter)>, + reader: Option>, + dirty: bool, +} + +impl FileHandle { + pub fn empty() -> std::io::Result { + 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) -> std::io::Result { + // 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) -> 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 { + 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 { + 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}"); + } + } +} -- cgit v1.2.3