rustybit_lib/storage/
file_storage.rs

1use std::fs::File;
2use std::io::ErrorKind;
3use std::os::unix::fs::FileExt;
4use std::path::PathBuf;
5
6use anyhow::Context;
7
8use super::{FileInfo, Storage};
9
10pub struct FileStorage {
11    files: Vec<(PathBuf, File)>,
12}
13
14impl FileStorage {
15    pub fn new(paths: &[FileInfo]) -> anyhow::Result<Self> {
16        let mut files = Vec::with_capacity(paths.len());
17        for file_info in paths.iter() {
18            std::fs::create_dir_all(
19                file_info
20                    .path
21                    .parent()
22                    .with_context(|| format!("bug: a file with no parrent? {:?}", file_info.path))?,
23            )
24            .with_context(|| {
25                format!(
26                    "error while creating parent directories for a file: {:?}",
27                    file_info.path
28                )
29            })?;
30            let f = std::fs::OpenOptions::new()
31                .create(true)
32                .truncate(false)
33                .write(true)
34                .read(true)
35                .open(&file_info.path)
36                .with_context(|| format!("error while opening/creating a file: {:?}", file_info.path))?;
37
38            f.set_len(file_info.length).with_context(|| {
39                format!(
40                    "error while setting the file's length: {:?}, {}",
41                    file_info.path, file_info.length
42                )
43            })?;
44
45            files.push((file_info.path.clone(), f));
46        }
47        Ok(FileStorage { files })
48    }
49}
50
51impl Storage for FileStorage {
52    #[tracing::instrument(err, skip(self, buf))]
53    fn write_all(&mut self, file_idx: usize, offset: u64, buf: &[u8]) -> anyhow::Result<()> {
54        let file = &mut self
55            .files
56            .get(file_idx)
57            .map(|(_, file)| file)
58            .context("bug: non-existing file index?")?;
59        file.write_all_at(buf, offset)
60            .context("error while writing to the provided offset")?;
61
62        Ok(())
63    }
64
65    #[tracing::instrument(err, skip(self, buf))]
66    fn read_exact(&mut self, file_idx: usize, offset: u64, buf: &mut [u8]) -> anyhow::Result<bool> {
67        let file = &mut self
68            .files
69            .get(file_idx)
70            .map(|(_, file)| file)
71            .context("bug: non-existing file index?")?;
72        if let Err(e) = file.read_exact_at(buf, offset) {
73            match e.kind() {
74                ErrorKind::UnexpectedEof => return Ok(false),
75                _ => return Err(e).context("error while reading from file at the offset"),
76            }
77        };
78
79        Ok(true)
80    }
81}