mkdrv now lists all files by alphabetical order (which isn't accurate yet, but works for now).

`mkdrv` now correctly pads the file to a multiple of sector size.
This commit is contained in:
Filipe Rodrigues 2021-04-05 16:26:23 +01:00
parent a5506c6688
commit 925948b6b5
3 changed files with 56 additions and 32 deletions

View File

@ -8,9 +8,11 @@ pub use error::{DirListNewError, NextError};
// Imports
use dcb_drv::{dir::entry::DirEntryWriterKind, DirEntryWriter, DirWriter, DirWriterLister, FileWriter};
use fs::FileType;
use std::{
cmp::Ordering,
convert::{TryFrom, TryInto},
fs,
fs::{self, DirEntry},
io::Seek,
path::Path,
time::SystemTime,
@ -19,26 +21,44 @@ use std::{
/// Directory list
#[derive(Debug)]
pub struct DirLister {
/// Directory read
dir: fs::ReadDir,
/// Number of entries
entries_len: u32,
/// All entries
entries: Vec<DirEntry>,
}
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)
// Read the directory entries
let mut entries = 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)?;
.collect::<Result<Vec<_>, _>>()
.map_err(|err| DirListNewError::ReadEntries(path.to_path_buf(), err))?;
// And read the directory
let dir = fs::read_dir(path).map_err(|err| DirListNewError::ReadDir(path.to_path_buf(), err))?;
// If there are too many entries, return Err
if u32::try_from(entries.len()).is_err() {
return Err(DirListNewError::TooManyEntries);
}
Ok(Self { dir, entries_len })
// Then sort them by type and then name
entries.sort_by(|lhs, rhs| {
// Get if they're a directory
// Note: If we can't read it, we just say it's a directory
let lhs_is_dir = lhs.file_type().as_ref().map_or(false, FileType::is_dir);
let rhs_is_dir = rhs.file_type().as_ref().map_or(false, FileType::is_dir);
// Sort directories first
match (lhs_is_dir, rhs_is_dir) {
(true, false) => return Ordering::Less,
(false, true) => return Ordering::Greater,
_ => (),
}
// Then compare by name
// TODO: Avoid allocations here?
lhs.file_name().cmp(&rhs.file_name())
});
Ok(Self { entries })
}
}
@ -47,21 +67,19 @@ impl DirWriterLister for DirLister {
type FileReader = fs::File;
fn entries_len(&self) -> u32 {
self.entries_len
// Note: We makes sure it's less than `u32::MAX` in the constructor
self.entries.len().try_into().expect("Too many entries")
}
}
impl Iterator for DirLister {
impl IntoIterator for DirLister {
type Item = Result<DirEntryWriter<Self>, <Self as DirWriterLister>::Error>;
fn next(&mut self) -> Option<Self::Item> {
// Get the next entry
let entry = self.dir.next()?;
type IntoIter = impl Iterator<Item = Self::Item>;
// Then read it
let res = try {
fn into_iter(self) -> Self::IntoIter {
self.entries.into_iter().map(|entry| {
// 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
@ -100,16 +118,14 @@ impl Iterator for DirLister {
true => {
let entries = Self::new(&path).map_err(NextError::OpenDir)?;
log::info!("{} ({} entries)", path.display(), entries.entries_len);
log::info!("{} ({} entries)", path.display(), entries.entries.len());
let dir = DirWriter::new(entries);
DirEntryWriterKind::Dir(dir)
},
};
DirEntryWriter::new(name, date, kind)
};
Some(res)
Ok(DirEntryWriter::new(name, date, kind))
})
}
}

View File

@ -11,6 +11,10 @@ pub enum DirListNewError {
#[error("Unable to read directory {}", _0.display())]
ReadDir(PathBuf, #[source] io::Error),
/// Unable to read entry
#[error("Unable to read entry in {}", _0.display())]
ReadEntries(PathBuf, #[source] io::Error),
/// Too many entries in directory
#[error("Too many entries in directory")]
TooManyEntries,
@ -19,10 +23,6 @@ pub enum DirListNewError {
/// 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),

View File

@ -1,7 +1,7 @@
//! `.DRV` packer
// Features
#![feature(try_blocks, seek_stream_len)]
#![feature(try_blocks, seek_stream_len, min_type_alias_impl_trait)]
// Modules
mod cli;
@ -34,5 +34,13 @@ fn pack_filesystem(input_dir: &Path, output_file: &Path) -> Result<(), anyhow::E
// Create the filesystem writer
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")
DrvFsWriter::write_fs(&mut output_file, root_entries).context("Unable to write filesystem")?;
// Then pad the file to a sector `2048` if it isn't already
let len = output_file.metadata().context("Unable to get output file metadata")?.len();
if len % 2048 != 0 {
output_file.set_len(2048 * ((len + 2047) / 2048)).context("Unable to set file length")?;
}
Ok(())
}