Clean up VFS error handling

This commit is contained in:
Luke Street 2024-11-07 09:00:52 -07:00
parent 9fc56d847f
commit 91aa36c120
3 changed files with 49 additions and 38 deletions

View File

@ -10,7 +10,7 @@ use nodtool::{
nod::{Disc, DiscStream, Fst, NodeKind, OwnedFileStream, PartitionBase, PartitionMeta}, nod::{Disc, DiscStream, Fst, NodeKind, OwnedFileStream, PartitionBase, PartitionMeta},
}; };
use typed_path::Utf8UnixPath; use typed_path::Utf8UnixPath;
use zerocopy::IntoBytes; use zerocopy::{FromZeros, IntoBytes};
use super::{ use super::{
next_non_empty, StaticFile, Vfs, VfsError, VfsFile, VfsFileType, VfsMetadata, VfsResult, next_non_empty, StaticFile, Vfs, VfsError, VfsFile, VfsFileType, VfsMetadata, VfsResult,
@ -252,19 +252,21 @@ impl DiscFile {
Self { inner: DiscFileInner::Stream(file), mtime } Self { inner: DiscFileInner::Stream(file), mtime }
} }
fn convert_to_mapped(&mut self) { fn convert_to_mapped(&mut self) -> io::Result<()> {
match &mut self.inner { match &mut self.inner {
DiscFileInner::Stream(stream) => { DiscFileInner::Stream(stream) => {
let pos = stream.stream_position().unwrap(); let pos = stream.stream_position()?;
stream.seek(SeekFrom::Start(0)).unwrap(); stream.seek(SeekFrom::Start(0))?;
let mut data = vec![0u8; stream.len() as usize]; let mut data = <[u8]>::new_box_zeroed_with_elems(stream.len() as usize)
stream.read_exact(&mut data).unwrap(); .map_err(|_| io::Error::from(io::ErrorKind::OutOfMemory))?;
let mut cursor = Cursor::new(Arc::from(data.as_slice())); stream.read_exact(&mut data)?;
let mut cursor = Cursor::new(Arc::from(data));
cursor.set_position(pos); cursor.set_position(pos);
self.inner = DiscFileInner::Mapped(cursor); self.inner = DiscFileInner::Mapped(cursor);
} }
DiscFileInner::Mapped(_) => {} DiscFileInner::Mapped(_) => {}
}; };
Ok(())
} }
} }
@ -304,7 +306,7 @@ impl Seek for DiscFile {
impl VfsFile for DiscFile { impl VfsFile for DiscFile {
fn map(&mut self) -> io::Result<&[u8]> { fn map(&mut self) -> io::Result<&[u8]> {
self.convert_to_mapped(); self.convert_to_mapped()?;
match &mut self.inner { match &mut self.inner {
DiscFileInner::Stream(_) => unreachable!(), DiscFileInner::Stream(_) => unreachable!(),
DiscFileInner::Mapped(data) => Ok(data.get_ref()), DiscFileInner::Mapped(data) => Ok(data.get_ref()),

View File

@ -55,10 +55,10 @@ impl StdFile {
pub fn new(path: Utf8NativePathBuf) -> Self { StdFile { path, file: None, mmap: None } } pub fn new(path: Utf8NativePathBuf) -> Self { StdFile { path, file: None, mmap: None } }
pub fn file(&mut self) -> io::Result<&mut BufReader<fs::File>> { pub fn file(&mut self) -> io::Result<&mut BufReader<fs::File>> {
if self.file.is_none() { Ok(match self.file {
self.file = Some(BufReader::new(fs::File::open(&self.path)?)); Some(ref mut file) => file,
} None => self.file.insert(BufReader::new(fs::File::open(&self.path)?)),
Ok(self.file.as_mut().unwrap()) })
} }
} }
@ -86,13 +86,15 @@ impl Seek for StdFile {
impl VfsFile for StdFile { impl VfsFile for StdFile {
fn map(&mut self) -> io::Result<&[u8]> { fn map(&mut self) -> io::Result<&[u8]> {
if self.file.is_none() { let file = match self.file {
self.file = Some(BufReader::new(fs::File::open(&self.path)?)); Some(ref mut file) => file,
} None => self.file.insert(BufReader::new(fs::File::open(&self.path)?)),
if self.mmap.is_none() { };
self.mmap = Some(unsafe { memmap2::Mmap::map(self.file.as_ref().unwrap().get_ref())? }); let mmap = match self.mmap {
} Some(ref mmap) => mmap,
Ok(self.mmap.as_ref().unwrap()) None => self.mmap.insert(unsafe { memmap2::Mmap::map(file.get_ref())? }),
};
Ok(mmap)
} }
fn metadata(&mut self) -> io::Result<VfsMetadata> { fn metadata(&mut self) -> io::Result<VfsMetadata> {

View File

@ -23,6 +23,7 @@ use crate::{
pub struct WadFs { pub struct WadFs {
file: Box<dyn VfsFile>, file: Box<dyn VfsFile>,
wad: WadFile, wad: WadFile,
mtime: Option<FileTime>,
} }
enum WadFindResult<'a> { enum WadFindResult<'a> {
@ -34,9 +35,10 @@ enum WadFindResult<'a> {
impl WadFs { impl WadFs {
pub fn new(mut file: Box<dyn VfsFile>) -> io::Result<Self> { pub fn new(mut file: Box<dyn VfsFile>) -> io::Result<Self> {
let mtime = file.metadata()?.mtime;
let wad = process_wad(file.as_mut()) let wad = process_wad(file.as_mut())
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Ok(Self { file, wad }) Ok(Self { file, wad, mtime })
} }
fn find(&self, path: &str) -> Option<WadFindResult> { fn find(&self, path: &str) -> Option<WadFindResult> {
@ -81,7 +83,7 @@ impl Vfs for WadFs {
match result { match result {
WadFindResult::Root => Err(VfsError::IsADirectory), WadFindResult::Root => Err(VfsError::IsADirectory),
WadFindResult::Static(data) => { WadFindResult::Static(data) => {
Ok(Box::new(StaticFile::new(Arc::from(data), self.file.metadata()?.mtime))) Ok(Box::new(StaticFile::new(Arc::from(data), self.mtime)))
} }
WadFindResult::Content(content_index, content) => { WadFindResult::Content(content_index, content) => {
let offset = self.wad.content_offset(content_index); let offset = self.wad.content_offset(content_index);
@ -93,7 +95,7 @@ impl Vfs for WadFs {
&self.wad.title_key, &self.wad.title_key,
&content.iv(), &content.iv(),
), ),
self.file.metadata()?.mtime, self.mtime,
))) )))
} }
WadFindResult::Window(offset, len) => { WadFindResult::Window(offset, len) => {
@ -129,20 +131,23 @@ impl Vfs for WadFs {
} }
fn metadata(&mut self, path: &Utf8UnixPath) -> VfsResult<VfsMetadata> { fn metadata(&mut self, path: &Utf8UnixPath) -> VfsResult<VfsMetadata> {
let mtime = self.file.metadata()?.mtime;
if let Some(result) = self.find(path.as_str()) { if let Some(result) = self.find(path.as_str()) {
match result { match result {
WadFindResult::Root => { WadFindResult::Root => {
Ok(VfsMetadata { file_type: VfsFileType::Directory, len: 0, mtime }) Ok(VfsMetadata { file_type: VfsFileType::Directory, len: 0, mtime: self.mtime })
}
WadFindResult::Static(data) => {
Ok(VfsMetadata { file_type: VfsFileType::File, len: data.len() as u64, mtime })
}
WadFindResult::Content(_, content) => {
Ok(VfsMetadata { file_type: VfsFileType::File, len: content.size.get(), mtime })
} }
WadFindResult::Static(data) => Ok(VfsMetadata {
file_type: VfsFileType::File,
len: data.len() as u64,
mtime: self.mtime,
}),
WadFindResult::Content(_, content) => Ok(VfsMetadata {
file_type: VfsFileType::File,
len: content.size.get(),
mtime: self.mtime,
}),
WadFindResult::Window(_, len) => { WadFindResult::Window(_, len) => {
Ok(VfsMetadata { file_type: VfsFileType::File, len, mtime }) Ok(VfsMetadata { file_type: VfsFileType::File, len, mtime: self.mtime })
} }
} }
} else { } else {
@ -168,19 +173,21 @@ impl WadContent {
Self { inner: WadContentInner::Stream(inner), mtime } Self { inner: WadContentInner::Stream(inner), mtime }
} }
fn convert_to_mapped(&mut self) { fn convert_to_mapped(&mut self) -> io::Result<()> {
match &mut self.inner { match &mut self.inner {
WadContentInner::Stream(stream) => { WadContentInner::Stream(stream) => {
let pos = stream.stream_position().unwrap(); let pos = stream.stream_position()?;
stream.seek(SeekFrom::Start(0)).unwrap(); stream.seek(SeekFrom::Start(0))?;
let mut data = vec![0u8; stream.len() as usize]; let mut data = <[u8]>::new_box_zeroed_with_elems(stream.len() as usize)
stream.read_exact(&mut data).unwrap(); .map_err(|_| io::Error::from(io::ErrorKind::OutOfMemory))?;
let mut cursor = Cursor::new(Arc::from(data.as_slice())); stream.read_exact(&mut data)?;
let mut cursor = Cursor::new(Arc::from(data));
cursor.set_position(pos); cursor.set_position(pos);
self.inner = WadContentInner::Mapped(cursor); self.inner = WadContentInner::Mapped(cursor);
} }
WadContentInner::Mapped(_) => {} WadContentInner::Mapped(_) => {}
}; };
Ok(())
} }
} }
@ -220,7 +227,7 @@ impl Seek for WadContent {
impl VfsFile for WadContent { impl VfsFile for WadContent {
fn map(&mut self) -> io::Result<&[u8]> { fn map(&mut self) -> io::Result<&[u8]> {
self.convert_to_mapped(); self.convert_to_mapped()?;
match &mut self.inner { match &mut self.inner {
WadContentInner::Stream(_) => unreachable!(), WadContentInner::Stream(_) => unreachable!(),
WadContentInner::Mapped(data) => Ok(data.get_ref()), WadContentInner::Mapped(data) => Ok(data.get_ref()),