pub struct FrozenFile { /* private fields */ }Expand description
Custom implementation of std::fs::File
§Example
use frozen_core::ffile::{FrozenFile, FrozenFileCfg};
const MID: u8 = 0;
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("tmp_frozen_file");
let cfg = FrozenFileCfg {
module_id: MID,
buffer_size: 0x10,
path: path.to_path_buf(),
initial_available_buffers: 0x0A,
};
let file = FrozenFile::new(cfg.clone()).unwrap();
assert_eq!(file.length().unwrap(), 0x10 * 0x0A);
let mut data = vec![1u8; 0x10];
assert!(file.pwrite(data.as_mut_ptr(), 0).is_ok());
assert!(file.sync().is_ok());
let mut buf = vec![0u8; data.len()];
assert!(file.pread(buf.as_mut_ptr(), 0).is_ok());
assert_eq!(buf, data);
assert!(FrozenFile::new(cfg.clone()).is_err());
assert!(file.delete().is_ok());
assert!(!path.exists());
drop(file);
assert!(FrozenFile::new(cfg).is_ok());Implementations§
Source§impl FrozenFile
impl FrozenFile
Sourcepub fn length(&self) -> FrozenResult<usize>
pub fn length(&self) -> FrozenResult<usize>
Read current length of FrozenFile
Sourcepub fn fd(&self) -> TFileId
pub fn fd(&self) -> TFileId
Get file descriptor for FrozenFile
Sourcepub fn exists(&self) -> FrozenResult<bool>
pub fn exists(&self) -> FrozenResult<bool>
Check if the FrozenFile exists on the fs
Sourcepub fn new(cfg: FrozenFileCfg) -> FrozenResult<Self>
pub fn new(cfg: FrozenFileCfg) -> FrozenResult<Self>
Create a new or open an existing FrozenFile
§FrozenFileCfg
All configs for FrozenFile are stored in FrozenFileCfg
§Important
The provided FrozenFileCfg must remain identical across all reopen cycles of the
FrozenFile.
Changing any of the feilds after initial creation, may violate internal layout invariants and cause the file to be treated as corrupted.
§Multiple Instances
Every instance of FrozenFile tries to acquire an exclusive lock, which protects against
operating with multiple simultenious instances.
If trying to call FrozenFile::new when already called, [FFileErr::Lck] error will be
thrown.
§Example
use frozen_core::ffile::{FrozenFile, FrozenFileCfg};
const MID: u8 = 0;
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("tmp_frozen_file");
let cfg = FrozenFileCfg {
module_id: MID,
buffer_size: 0x10,
path: path.to_path_buf(),
initial_available_buffers: 0x0A,
};
let file = FrozenFile::new(cfg).unwrap();
assert_eq!(file.length().unwrap(), 0x10 * 0x0A);Sourcepub fn sync(&self) -> FrozenResult<()>
pub fn sync(&self) -> FrozenResult<()>
Syncs in-mem data on the storage device
Sourcepub fn sync_range(&self, index: usize, count: usize) -> FrozenResult<()>
pub fn sync_range(&self, index: usize, count: usize) -> FrozenResult<()>
A best-effort call to prompt kernel to start flushing dirty pages in the specified range
This call, by itself, does not guarantee any kind of durability, and must always be paired
with strong sync call i.e. FrozenFile::sync
Sourcepub fn delete(&self) -> FrozenResult<()>
pub fn delete(&self) -> FrozenResult<()>
Delete FrozenFile from fs
§Example
use frozen_core::ffile::{FrozenFile, FrozenFileCfg};
const MID: u8 = 0;
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("tmp_frozen_file");
let cfg = FrozenFileCfg {
module_id: MID,
buffer_size: 0x10,
path: path.to_path_buf(),
initial_available_buffers: 0x0A,
};
let file = FrozenFile::new(cfg).unwrap();
assert!(file.exists().unwrap());
file.delete().unwrap();
assert!(!file.exists().unwrap());Sourcepub fn pread(&self, buf: *mut u8, index: usize) -> FrozenResult<()>
pub fn pread(&self, buf: *mut u8, index: usize) -> FrozenResult<()>
Read a single chunk at given index w/ pread syscall
§Example
use frozen_core::ffile::{FrozenFile, FrozenFileCfg};
const MID: u8 = 0;
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("tmp_frozen_file");
let cfg = FrozenFileCfg {
module_id: MID,
buffer_size: 0x10,
path: path.to_path_buf(),
initial_available_buffers: 0x0A,
};
let file = FrozenFile::new(cfg).unwrap();
let mut data = [7u8; 0x10];
file.pwrite(data.as_mut_ptr(), 2).unwrap();
file.sync().unwrap();
let mut buf = [0u8; 0x10];
file.pread(buf.as_mut_ptr(), 2).unwrap();
assert_eq!(buf, data);Sourcepub fn pwrite(&self, buf: *mut u8, index: usize) -> FrozenResult<()>
pub fn pwrite(&self, buf: *mut u8, index: usize) -> FrozenResult<()>
Write a single chunk at given index w/ pwrite syscall
§Example
use frozen_core::ffile::{FrozenFile, FrozenFileCfg};
const MID: u8 = 0;
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("tmp_frozen_file");
let cfg = FrozenFileCfg {
module_id: MID,
buffer_size: 0x10,
path: path.to_path_buf(),
initial_available_buffers: 0x0A,
};
let file = FrozenFile::new(cfg).unwrap();
let mut data = [9u8; 0x10];
file.pwrite(data.as_mut_ptr(), 4).unwrap();
file.sync().unwrap();
let mut buf = [0u8; 0x10];
file.pread(buf.as_mut_ptr(), 4).unwrap();
assert_eq!(buf, data);Sourcepub fn preadv(&self, bufs: &[*mut u8], index: usize) -> FrozenResult<()>
pub fn preadv(&self, bufs: &[*mut u8], index: usize) -> FrozenResult<()>
Read multiple chunks starting from given index till bufs.len() w/ preadv syscall
§Example
use frozen_core::ffile::{FrozenFile, FrozenFileCfg};
const MID: u8 = 0;
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("tmp_frozen_file");
let cfg = FrozenFileCfg {
module_id: MID,
buffer_size: 0x10,
path: path.to_path_buf(),
initial_available_buffers: 0x0A,
};
let file = FrozenFile::new(cfg).unwrap();
let mut write_bufs = [[1u8; 0x10], [2u8; 0x10]];
let ptrs: Vec<*mut u8> = write_bufs.iter_mut().map(|b| b.as_mut_ptr()).collect();
file.pwritev(&ptrs, 0).unwrap();
file.sync().unwrap();
let mut read_bufs = [[0u8; 0x10], [0u8; 0x10]];
let rptrs: Vec<*mut u8> = read_bufs.iter_mut().map(|b| b.as_mut_ptr()).collect();
file.preadv(&rptrs, 0).unwrap();
assert!(read_bufs[0].iter().all(|b| *b == 1));
assert!(read_bufs[1].iter().all(|b| *b == 2));Sourcepub fn pwritev(&self, bufs: &[*mut u8], index: usize) -> FrozenResult<()>
pub fn pwritev(&self, bufs: &[*mut u8], index: usize) -> FrozenResult<()>
Write multiple chunks starting from given index till bufs.len() w/ pwritev syscall
§Example
use frozen_core::ffile::{FrozenFile, FrozenFileCfg};
const MID: u8 = 0;
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("tmp_frozen_file");
let cfg = FrozenFileCfg {
module_id: MID,
buffer_size: 0x10,
path: path.to_path_buf(),
initial_available_buffers: 0x0A,
};
let file = FrozenFile::new(cfg).unwrap();
let mut bufs = [[3u8; 0x10], [4u8; 0x10]];
let ptrs: Vec<*mut u8> = bufs.iter_mut().map(|b| b.as_mut_ptr()).collect();
file.pwritev(&ptrs, 2).unwrap();
file.sync().unwrap();
let mut a = [0u8; 0x10];
let mut b = [0u8; 0x10];
file.pread(a.as_mut_ptr(), 2).unwrap();
file.pread(b.as_mut_ptr(), 3).unwrap();
assert!(a.iter().all(|v| *v == 3));
assert!(b.iter().all(|v| *v == 4));Sourcepub fn grow(&self, count: usize) -> FrozenResult<()>
pub fn grow(&self, count: usize) -> FrozenResult<()>
Grow file size of FrozenFile by given count of chunks
After successful execution, updated file length will be current_length + (count * buffer_size)
§Example
use frozen_core::ffile::{FrozenFile, FrozenFileCfg};
const MID: u8 = 0;
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("tmp_frozen_file");
let cfg = FrozenFileCfg {
module_id: MID,
buffer_size: 0x10,
path: path.to_path_buf(),
initial_available_buffers: 0x0A,
};
let file = FrozenFile::new(cfg).unwrap();
assert_eq!(file.length().unwrap(), 0x10 * 0x0A);
file.grow(0x20).unwrap();
assert_eq!(file.length().unwrap(), 0x10 * (0x0A + 0x20));Sourcepub fn total_chunks(&self) -> FrozenResult<usize>
pub fn total_chunks(&self) -> FrozenResult<usize>
Fetch total available chunks in FrozenFile from fs
§Working
This call performs a syscall to fetch current length of FrozenFile from fs, as the
current length of the file is not cached anywhere in the pipeline to avoid TOCTAU race
conditions.
§Example
use frozen_core::ffile::{FrozenFile, FrozenFileCfg};
const MID: u8 = 0;
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("tmp_frozen_file");
let cfg = FrozenFileCfg {
module_id: MID,
buffer_size: 0x10,
path: path.to_path_buf(),
initial_available_buffers: 0x0A,
};
let file = FrozenFile::new(cfg).unwrap();
assert_eq!(file.length().unwrap(), 0x10 * 0x0A);
file.grow(0x20).unwrap();
assert_eq!(file.total_chunks().unwrap(), 0x0A + 0x20);