use std::fs::{File, OpenOptions}; use std::io::{Seek, SeekFrom}; use std::os::unix::fs::FileExt; use std::path::Path; use syscall::error::{Error, Result, EIO}; use crate::disk::Disk; use crate::BLOCK_SIZE; pub struct DiskFile { pub file: File, } trait ResultExt { type T; fn or_eio(self) -> Result; } impl ResultExt for Result { type T = T; fn or_eio(self) -> Result { match self { Ok(t) => Ok(t), Err(err) => { eprintln!("RedoxFS: IO ERROR: {err}"); Err(Error::new(EIO)) } } } } impl ResultExt for std::io::Result { type T = T; fn or_eio(self) -> Result { match self { Ok(t) => Ok(t), Err(err) => { eprintln!("RedoxFS: IO ERROR: {err}"); Err(Error::new(EIO)) } } } } impl DiskFile { pub fn open(path: impl AsRef) -> Result { let file = OpenOptions::new() .read(true) .write(true) .open(path) .or_eio()?; Ok(DiskFile { file }) } pub fn create(path: impl AsRef, size: u64) -> Result { let file = OpenOptions::new() .read(true) .write(true) .create(true) .open(path) .or_eio()?; file.set_len(size).or_eio()?; Ok(DiskFile { file }) } } impl Disk for DiskFile { unsafe fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result { self.file.read_at(buffer, block * BLOCK_SIZE).or_eio() } unsafe fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result { self.file.write_at(buffer, block * BLOCK_SIZE).or_eio() } fn size(&mut self) -> Result { self.file.seek(SeekFrom::End(0)).or_eio() } } impl From for DiskFile { fn from(file: File) -> Self { Self { file } } }