extern crate failure;
extern crate mkdirp;
extern crate random_access_storage as random_access;
use failure::Error;
use std::fs;
use std::fs::OpenOptions;
use std::io::{Read, Seek, SeekFrom, Write};
use std::ops::Drop;
use std::path;
#[derive(Debug)]
pub struct Sync {}
impl Sync {
pub fn new(filename: path::PathBuf) -> random_access::Sync<SyncMethods> {
random_access::Sync::new(SyncMethods {
filename,
file: None,
length: 0,
})
}
}
#[derive(Debug)]
pub struct SyncMethods {
filename: path::PathBuf,
file: Option<fs::File>,
length: u64,
}
impl random_access::SyncMethods for SyncMethods {
fn open(&mut self) -> Result<(), Error> {
if let Some(dirname) = self.filename.parent() {
mkdirp::mkdirp(&dirname)?;
}
let file = OpenOptions::new()
.create(true)
.read(true)
.write(true)
.open(&self.filename)?;
file.sync_all()?;
self.file = Some(file);
let metadata = fs::metadata(&self.filename)?;
self.length = metadata.len();
Ok(())
}
fn write(&mut self, offset: usize, data: &[u8]) -> Result<(), Error> {
let mut file = self.file.as_ref().expect("self.file was None.");
file.seek(SeekFrom::Start(offset as u64))?;
file.write_all(&data)?;
file.sync_all()?;
let new_len = (offset + data.len()) as u64;
if new_len > self.length {
self.length = new_len;
}
Ok(())
}
fn read(&mut self, offset: usize, length: usize) -> Result<Vec<u8>, Error> {
ensure!(
(offset + length) as u64 <= self.length,
format!("Read bounds exceeded. {} < {}..{}",
self.length, offset, offset + length)
);
let mut file = self.file.as_ref().expect("self.file was None.");
let mut buffer = vec![0; length];
file.seek(SeekFrom::Start(offset as u64))?;
file.read(&mut buffer[..])?;
Ok(buffer)
}
fn del(&mut self, _offset: usize, _length: usize) -> Result<(), Error> {
panic!("Not implemented yet");
}
}
impl Drop for SyncMethods {
fn drop(&mut self) {
if let Some(file) = &self.file {
file.sync_all().unwrap();
}
}
}