1use std::fs::{File, OpenOptions};
2use std::os::unix::io::AsRawFd;
3
4pub struct FlatFileBackend {
6 file: File,
7 path: String,
8 size: u64,
9}
10
11impl FlatFileBackend {
12 pub fn open(path: &str) -> anyhow::Result<Self> {
13 let file = OpenOptions::new().read(true).write(true).open(path)?;
14 let size = file.metadata()?.len();
15 Ok(FlatFileBackend { file, path: path.to_string(), size })
16 }
17
18 pub fn path(&self) -> &str {
19 &self.path
20 }
21
22 pub fn size(&self) -> u64 {
23 self.size
24 }
25
26 pub fn read(&self, offset: u64, buf: &mut [u8]) -> std::io::Result<usize> {
27 let fd = self.file.as_raw_fd();
28 let n = unsafe {
29 libc::pread(
30 fd,
31 buf.as_mut_ptr() as *mut libc::c_void,
32 buf.len(),
33 offset as libc::off_t,
34 )
35 };
36 if n < 0 {
37 Err(std::io::Error::last_os_error())
38 } else {
39 Ok(n as usize)
40 }
41 }
42
43 pub fn write(&self, offset: u64, buf: &[u8]) -> std::io::Result<usize> {
44 let fd = self.file.as_raw_fd();
45 let n = unsafe {
46 libc::pwrite(
47 fd,
48 buf.as_ptr() as *const libc::c_void,
49 buf.len(),
50 offset as libc::off_t,
51 )
52 };
53 if n < 0 {
54 Err(std::io::Error::last_os_error())
55 } else {
56 Ok(n as usize)
57 }
58 }
59
60 pub fn flush(&self) -> std::io::Result<()> {
61 let fd = self.file.as_raw_fd();
62 let ret = unsafe { libc::fsync(fd) };
63 if ret < 0 {
64 Err(std::io::Error::last_os_error())
65 } else {
66 Ok(())
67 }
68 }
69}