mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-05 08:43:46 +00:00
Made DirWriterLister now require the number of entries.
Refactored `drv-packer`.
This commit is contained in:
parent
1b3ca80cb3
commit
5fc311ff49
@ -31,10 +31,10 @@ pub struct DrvFsWriter;
|
||||
impl DrvFsWriter {
|
||||
/// Creates a `.DRV` filesystem
|
||||
pub fn write_fs<W: io::Write + io::Seek, L: DirWriterLister>(
|
||||
writer: &mut W, root_entries: L, root_entries_len: u32,
|
||||
writer: &mut W, root_entries: L,
|
||||
) -> Result<(), WriteFsError<L::Error>> {
|
||||
// Get the root and write it
|
||||
let root = DirWriter::new(root_entries, root_entries_len);
|
||||
let root = DirWriter::new(root_entries);
|
||||
root.write_entries(writer).map_err(WriteFsError::RootDir)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -26,6 +26,9 @@ where
|
||||
|
||||
/// Error type for each entry
|
||||
type Error: std::error::Error + 'static;
|
||||
|
||||
/// Returns the number of entries in this lister
|
||||
fn entries_len(&self) -> u32;
|
||||
}
|
||||
|
||||
/// Directory writer
|
||||
@ -33,20 +36,17 @@ where
|
||||
pub struct DirWriter<L: DirWriterLister> {
|
||||
/// Writer list
|
||||
entries: L,
|
||||
|
||||
/// Number of entries
|
||||
entries_len: u32,
|
||||
}
|
||||
|
||||
impl<L: DirWriterLister> DirWriter<L> {
|
||||
/// Creates a new directory writer
|
||||
pub fn new(entries: L, entries_len: u32) -> Self {
|
||||
Self { entries, entries_len }
|
||||
pub fn new(entries: L) -> Self {
|
||||
Self { entries }
|
||||
}
|
||||
|
||||
/// Returns the number of entries
|
||||
pub fn entries_len(&self) -> u32 {
|
||||
self.entries_len
|
||||
self.entries.entries_len()
|
||||
}
|
||||
|
||||
/// Returns this directory's size
|
||||
|
||||
116
dcb-tools/drv-packer/src/dir_lister.rs
Normal file
116
dcb-tools/drv-packer/src/dir_lister.rs
Normal file
@ -0,0 +1,116 @@
|
||||
//! Directory lister
|
||||
|
||||
// Modules
|
||||
pub mod error;
|
||||
|
||||
// Exports
|
||||
pub use error::{DirListNewError, NextError};
|
||||
|
||||
// Imports
|
||||
use dcb_io::drv::{dir::entry::DirEntryWriterKind, DirEntryWriter, DirWriter, DirWriterLister, FileWriter};
|
||||
use std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
fs,
|
||||
io::Seek,
|
||||
path::Path,
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
/// Directory list
|
||||
#[derive(Debug)]
|
||||
pub struct DirLister {
|
||||
/// Directory read
|
||||
dir: fs::ReadDir,
|
||||
|
||||
/// Number of entries
|
||||
entries_len: u32,
|
||||
}
|
||||
|
||||
impl DirLister {
|
||||
/// Creates a new iterator from a path
|
||||
pub fn new(path: &Path) -> Result<Self, DirListNewError> {
|
||||
// Get the length
|
||||
let len = fs::read_dir(path)
|
||||
.map_err(|err| DirListNewError::ReadDir(path.to_path_buf(), err))?
|
||||
.count();
|
||||
let entries_len = u32::try_from(len).map_err(|_err| DirListNewError::TooManyEntries)?;
|
||||
|
||||
// And read the directory
|
||||
let dir = fs::read_dir(path).map_err(|err| DirListNewError::ReadDir(path.to_path_buf(), err))?;
|
||||
|
||||
Ok(Self { dir, entries_len })
|
||||
}
|
||||
}
|
||||
|
||||
impl DirWriterLister for DirLister {
|
||||
type DirList = Self;
|
||||
type Error = NextError;
|
||||
type FileReader = fs::File;
|
||||
|
||||
fn entries_len(&self) -> u32 {
|
||||
self.entries_len
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for DirLister {
|
||||
type Item = Result<DirEntryWriter<<Self as DirWriterLister>::DirList>, <Self as DirWriterLister>::Error>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// Get the next entry
|
||||
let entry = self.dir.next()?;
|
||||
|
||||
// Then read it
|
||||
let res = try {
|
||||
// Read the entry and it's metadata
|
||||
let entry = entry.map_err(NextError::ReadEntry)?;
|
||||
let metadata = entry.metadata().map_err(NextError::ReadMetadata)?;
|
||||
let path = entry.path();
|
||||
let name = path
|
||||
.file_stem()
|
||||
.ok_or(NextError::NoEntryName)?
|
||||
.try_into()
|
||||
.map_err(NextError::InvalidEntryName)?;
|
||||
let secs_since_epoch = metadata
|
||||
.modified()
|
||||
.map_err(NextError::EntryDate)?
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map_err(NextError::EntryDateSinceEpoch)?
|
||||
.as_secs();
|
||||
let date = chrono::NaiveDateTime::from_timestamp(i64::try_from(secs_since_epoch).map_err(|_err| NextError::EntryDateI64Secs)?, 0);
|
||||
|
||||
// Check if it's a directory or file
|
||||
let kind = match metadata.is_file() {
|
||||
true => {
|
||||
let mut file = fs::File::open(&path).map_err(NextError::OpenFile)?;
|
||||
let size = file
|
||||
.stream_len()
|
||||
.map_err(NextError::FileSize)?
|
||||
.try_into()
|
||||
.map_err(|_err| NextError::FileTooBig)?;
|
||||
let extension = path
|
||||
.extension()
|
||||
.ok_or(NextError::NoFileExtension)?
|
||||
.try_into()
|
||||
.map_err(NextError::InvalidFileExtension)?;
|
||||
|
||||
log::info!("{} ({} bytes)", path.display(), size);
|
||||
|
||||
let file = FileWriter::new(extension, file, size);
|
||||
DirEntryWriterKind::File(file)
|
||||
},
|
||||
false => {
|
||||
let entries = Self::new(&path).map_err(NextError::OpenDir)?;
|
||||
|
||||
log::info!("{} ({} entries)", path.display(), entries.entries_len);
|
||||
|
||||
let dir = DirWriter::new(entries);
|
||||
DirEntryWriterKind::Dir(dir)
|
||||
},
|
||||
};
|
||||
|
||||
DirEntryWriter::new(name, date, kind)
|
||||
};
|
||||
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
73
dcb-tools/drv-packer/src/dir_lister/error.rs
Normal file
73
dcb-tools/drv-packer/src/dir_lister/error.rs
Normal file
@ -0,0 +1,73 @@
|
||||
//! Errors
|
||||
|
||||
// Imports
|
||||
use std::{io, path::PathBuf};
|
||||
|
||||
/// Error for [`DirList::new`]
|
||||
// TODO: Rename
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum DirListNewError {
|
||||
/// Unable to read directory
|
||||
#[error("Unable to read directory {}", _0.display())]
|
||||
ReadDir(PathBuf, #[source] io::Error),
|
||||
|
||||
/// Too many entries in directory
|
||||
#[error("Too many entries in directory")]
|
||||
TooManyEntries,
|
||||
}
|
||||
|
||||
/// Error for [`Iterator::Item`]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum NextError {
|
||||
/// Unable to read entry
|
||||
#[error("Unable to read entry")]
|
||||
ReadEntry(#[source] io::Error),
|
||||
|
||||
/// Unable to read entry metadata
|
||||
#[error("Unable to read entry metadata")]
|
||||
ReadMetadata(#[source] io::Error),
|
||||
|
||||
/// Entry had no name
|
||||
#[error("Entry had no name")]
|
||||
NoEntryName,
|
||||
|
||||
/// Invalid file name
|
||||
#[error("Invalid file name")]
|
||||
InvalidEntryName(#[source] dcb_util::ascii_str_arr::FromBytesError<0x10>),
|
||||
|
||||
/// File had no file name
|
||||
#[error("file had no file name")]
|
||||
NoFileExtension,
|
||||
|
||||
/// Invalid extension
|
||||
#[error("Invalid extension")]
|
||||
InvalidFileExtension(#[source] dcb_util::ascii_str_arr::FromBytesError<0x3>),
|
||||
|
||||
/// Unable to get entry date
|
||||
#[error("Unable to get entry date")]
|
||||
EntryDate(#[source] io::Error),
|
||||
|
||||
/// Unable to get entry date as time since epoch
|
||||
#[error("Unable to get entry date as time since epoch")]
|
||||
EntryDateSinceEpoch(#[source] std::time::SystemTimeError),
|
||||
|
||||
/// Unable to get entry date as `i64` seconds since epoch
|
||||
#[error("Unable to get entry date as `i64` seconds since epoch")]
|
||||
EntryDateI64Secs,
|
||||
|
||||
/// Unable to open file
|
||||
#[error("Unable to open file")]
|
||||
OpenFile(#[source] io::Error),
|
||||
|
||||
/// Unable to get file size
|
||||
#[error("Unable to get file size")]
|
||||
FileSize(#[source] io::Error),
|
||||
|
||||
/// File was too big
|
||||
#[error("File was too big")]
|
||||
FileTooBig,
|
||||
|
||||
/// Unable to open directory
|
||||
#[error("Unable to open directory")]
|
||||
OpenDir(#[source] self::DirListNewError),
|
||||
}
|
||||
@ -5,18 +5,13 @@
|
||||
|
||||
// Modules
|
||||
mod cli;
|
||||
mod dir_lister;
|
||||
mod logger;
|
||||
|
||||
// Imports
|
||||
use anyhow::Context;
|
||||
use dcb_io::drv::{dir::entry::DirEntryWriterKind, DirEntryWriter, DirWriter, DirWriterLister, DrvFsWriter, FileWriter};
|
||||
use std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
fs,
|
||||
io::{self, Seek},
|
||||
path::{Path, PathBuf},
|
||||
time::SystemTime,
|
||||
};
|
||||
use dcb_io::drv::DrvFsWriter;
|
||||
use std::{fs, path::Path};
|
||||
|
||||
|
||||
fn main() -> Result<(), anyhow::Error> {
|
||||
@ -38,166 +33,6 @@ fn pack_filesystem(input_dir: &Path, output_file: &Path) -> Result<(), anyhow::E
|
||||
let mut output_file = fs::File::create(output_file).context("Unable to create output file")?;
|
||||
|
||||
// Create the filesystem writer
|
||||
let (root_entries, root_entries_len) = DirLister::new(input_dir).context("Unable to read root directory")?;
|
||||
DrvFsWriter::write_fs(&mut output_file, root_entries, root_entries_len).context("Unable to write filesystem")
|
||||
}
|
||||
|
||||
/// Directory list
|
||||
#[derive(Debug)]
|
||||
struct DirLister {
|
||||
/// Directory read
|
||||
dir: fs::ReadDir,
|
||||
}
|
||||
|
||||
impl DirLister {
|
||||
/// Creates a new iterator from a path
|
||||
fn new(path: &Path) -> Result<(Self, u32), DirListNewError> {
|
||||
// Get the length
|
||||
let len = fs::read_dir(path)
|
||||
.map_err(|err| DirListNewError::ReadDir(path.to_path_buf(), err))?
|
||||
.count();
|
||||
let len = u32::try_from(len).map_err(|_err| DirListNewError::TooManyEntries)?;
|
||||
|
||||
// And read the directory
|
||||
let dir = fs::read_dir(path).map_err(|err| DirListNewError::ReadDir(path.to_path_buf(), err))?;
|
||||
|
||||
Ok((Self { dir }, len))
|
||||
}
|
||||
}
|
||||
|
||||
/// Error for [`DirList::new`]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum DirListNewError {
|
||||
/// Unable to read directory
|
||||
#[error("Unable to read directory {}", _0.display())]
|
||||
ReadDir(PathBuf, #[source] io::Error),
|
||||
|
||||
/// Too many entries in directory
|
||||
#[error("Too many entries in directory")]
|
||||
TooManyEntries,
|
||||
}
|
||||
|
||||
/// Error for [`Iterator::Item`]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum NextError {
|
||||
/// Unable to read entry
|
||||
#[error("Unable to read entry")]
|
||||
ReadEntry(#[source] io::Error),
|
||||
|
||||
/// Unable to read entry metadata
|
||||
#[error("Unable to read entry metadata")]
|
||||
ReadMetadata(#[source] io::Error),
|
||||
|
||||
/// Entry had no name
|
||||
#[error("Entry had no name")]
|
||||
NoEntryName,
|
||||
|
||||
/// Invalid file name
|
||||
#[error("Invalid file name")]
|
||||
InvalidEntryName(#[source] dcb_util::ascii_str_arr::FromBytesError<0x10>),
|
||||
|
||||
/// File had no file name
|
||||
#[error("file had no file name")]
|
||||
NoFileExtension,
|
||||
|
||||
/// Invalid extension
|
||||
#[error("Invalid extension")]
|
||||
InvalidFileExtension(#[source] dcb_util::ascii_str_arr::FromBytesError<0x3>),
|
||||
|
||||
/// Unable to get entry date
|
||||
#[error("Unable to get entry date")]
|
||||
EntryDate(#[source] io::Error),
|
||||
|
||||
/// Unable to get entry date as time since epoch
|
||||
#[error("Unable to get entry date as time since epoch")]
|
||||
EntryDateSinceEpoch(#[source] std::time::SystemTimeError),
|
||||
|
||||
/// Unable to get entry date as `i64` seconds since epoch
|
||||
#[error("Unable to get entry date as `i64` seconds since epoch")]
|
||||
EntryDateI64Secs,
|
||||
|
||||
/// Unable to open file
|
||||
#[error("Unable to open file")]
|
||||
OpenFile(#[source] io::Error),
|
||||
|
||||
/// Unable to get file size
|
||||
#[error("Unable to get file size")]
|
||||
FileSize(#[source] io::Error),
|
||||
|
||||
/// File was too big
|
||||
#[error("File was too big")]
|
||||
FileTooBig,
|
||||
|
||||
/// Unable to open directory
|
||||
#[error("Unable to open directory")]
|
||||
OpenDir(#[source] DirListNewError),
|
||||
}
|
||||
|
||||
impl DirWriterLister for DirLister {
|
||||
type DirList = Self;
|
||||
type Error = NextError;
|
||||
type FileReader = std::fs::File;
|
||||
}
|
||||
|
||||
impl Iterator for DirLister {
|
||||
type Item = Result<DirEntryWriter<<Self as DirWriterLister>::DirList>, <Self as DirWriterLister>::Error>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// Get the next entry
|
||||
let entry = self.dir.next()?;
|
||||
|
||||
// Then read it
|
||||
let res = try {
|
||||
// Read the entry and it's metadata
|
||||
let entry = entry.map_err(NextError::ReadEntry)?;
|
||||
let metadata = entry.metadata().map_err(NextError::ReadMetadata)?;
|
||||
let path = entry.path();
|
||||
let name = path
|
||||
.file_stem()
|
||||
.ok_or(NextError::NoEntryName)?
|
||||
.try_into()
|
||||
.map_err(NextError::InvalidEntryName)?;
|
||||
let secs_since_epoch = metadata
|
||||
.modified()
|
||||
.map_err(NextError::EntryDate)?
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map_err(NextError::EntryDateSinceEpoch)?
|
||||
.as_secs();
|
||||
let date = chrono::NaiveDateTime::from_timestamp(i64::try_from(secs_since_epoch).map_err(|_err| NextError::EntryDateI64Secs)?, 0);
|
||||
|
||||
// Check if it's a directory or file
|
||||
let kind = match metadata.is_file() {
|
||||
true => {
|
||||
let mut file = std::fs::File::open(&path).map_err(NextError::OpenFile)?;
|
||||
let size = file
|
||||
.stream_len()
|
||||
.map_err(NextError::FileSize)?
|
||||
.try_into()
|
||||
.map_err(|_err| NextError::FileTooBig)?;
|
||||
let extension = path
|
||||
.extension()
|
||||
.ok_or(NextError::NoFileExtension)?
|
||||
.try_into()
|
||||
.map_err(NextError::InvalidFileExtension)?;
|
||||
|
||||
log::info!("{} ({} bytes)", path.display(), size);
|
||||
|
||||
let file = FileWriter::new(extension, file, size);
|
||||
DirEntryWriterKind::File(file)
|
||||
},
|
||||
false => {
|
||||
let (entries, entries_len) = Self::new(&path).map_err(NextError::OpenDir)?;
|
||||
|
||||
log::info!("{} ({} entries)", path.display(), entries_len);
|
||||
|
||||
let dir = DirWriter::new(entries, entries_len);
|
||||
DirEntryWriterKind::Dir(dir)
|
||||
},
|
||||
};
|
||||
|
||||
DirEntryWriter::new(name, date, kind)
|
||||
};
|
||||
|
||||
Some(res)
|
||||
}
|
||||
let root_entries = dir_lister::DirLister::new(input_dir).context("Unable to create new dir lister for root directory")?;
|
||||
DrvFsWriter::write_fs(&mut output_file, root_entries).context("Unable to write filesystem")
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user