1use bytes::{Bytes, BytesMut};
4use hexz_common::Result;
5use hexz_core::store::StorageBackend;
6use std::fs::File;
7
8#[cfg(unix)]
9fn read_exact_at(file: &File, buffer: &mut [u8], offset: u64) -> std::io::Result<()> {
10 use std::os::unix::fs::FileExt;
11 file.read_exact_at(buffer, offset)
12}
13
14#[cfg(windows)]
15fn read_exact_at(file: &File, buffer: &mut [u8], mut offset: u64) -> std::io::Result<()> {
16 use std::os::windows::fs::FileExt;
17 let mut pos = 0;
18 while pos < buffer.len() {
19 let n = file.seek_read(&mut buffer[pos..], offset)?;
20 if n == 0 {
21 return Err(std::io::Error::new(
22 std::io::ErrorKind::UnexpectedEof,
23 "unexpected eof",
24 ));
25 }
26 pos += n;
27 offset += n as u64;
28 }
29 Ok(())
30}
31
32#[derive(Debug)]
34pub struct FileBackend {
35 inner: File,
36 size: u64,
37}
38
39impl FileBackend {
40 pub fn new(path: &std::path::Path) -> Result<Self> {
42 let file = File::open(path)?;
43 let metadata = file.metadata()?;
44 Ok(Self {
45 inner: file,
46 size: metadata.len(),
47 })
48 }
49}
50
51impl StorageBackend for FileBackend {
52 fn read_exact(&self, offset: u64, len: usize) -> Result<Bytes> {
53 let mut buffer = BytesMut::with_capacity(len);
54 unsafe { buffer.set_len(len) }
56 match read_exact_at(&self.inner, &mut buffer, offset) {
57 Ok(()) => Ok(buffer.freeze()),
58 Err(e) => Err(hexz_common::Error::Io(e)),
59 }
60 }
61
62 fn len(&self) -> u64 {
63 self.size
64 }
65}