diff options
author | evuez <julien@mulga.net> | 2024-04-03 22:43:16 +0200 |
---|---|---|
committer | evuez <julien@mulga.net> | 2024-04-03 22:43:16 +0200 |
commit | 43e1a12b5bce11b4a28a53acca243e35c2be6d3e (patch) | |
tree | 07d64823718bfee063ab7b3d5721ac1e950ae17c /src/client/fs/fh.rs | |
download | carton-43e1a12b5bce11b4a28a53acca243e35c2be6d3e.tar.gz |
Initial commit
Diffstat (limited to 'src/client/fs/fh.rs')
-rw-r--r-- | src/client/fs/fh.rs | 110 |
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}"); + } + } +} |