Skip to content

Commit

Permalink
Merge pull request #46 from 00xc/fs
Browse files Browse the repository at this point in the history
fs: avoid needless allocations
  • Loading branch information
joergroedel committed Jun 19, 2023
2 parents 203e270 + ca877ca commit 9c2228e
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 57 deletions.
56 changes: 30 additions & 26 deletions src/fs/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,25 +142,26 @@ fn uninitialize_fs() {
}
}

fn split_path_allow_empty(path: &str) -> Vec<&str> {
path.split('/').filter(|x| !x.is_empty()).collect()
fn split_path_allow_empty(path: &str) -> impl Iterator<Item = &str> + DoubleEndedIterator {
path.split('/').filter(|x| !x.is_empty())
}

fn split_path(path: &str) -> Result<Vec<&str>, SvsmError> {
let path_items = split_path_allow_empty(path);

if path_items.is_empty() {
return Err(SvsmError::FileSystem(FsError::inval()));
}

fn split_path(path: &str) -> Result<impl Iterator<Item = &str> + DoubleEndedIterator, SvsmError> {
let mut path_items = split_path_allow_empty(path).peekable();
path_items
.peek()
.ok_or(SvsmError::FileSystem(FsError::inval()))?;
Ok(path_items)
}

fn walk_path(path_items: &[&str]) -> Result<Arc<dyn Directory>, SvsmError> {
fn walk_path<'a, I>(path_items: I) -> Result<Arc<dyn Directory>, SvsmError>
where
I: Iterator<Item = &'a str>,
{
let mut current_dir = unsafe { FS_ROOT.root_dir() };

for item in path_items.iter() {
let dir_name = FileName::from(*item);
for item in path_items {
let dir_name = FileName::from(item);
let dir_entry = current_dir.lookup_entry(dir_name)?;
current_dir = match dir_entry {
DirEntry::File(_) => return Err(SvsmError::FileSystem(FsError::file_not_found())),
Expand All @@ -171,11 +172,14 @@ fn walk_path(path_items: &[&str]) -> Result<Arc<dyn Directory>, SvsmError> {
Ok(current_dir)
}

fn walk_path_create(path_items: &[&str]) -> Result<Arc<dyn Directory>, SvsmError> {
fn walk_path_create<'a, I>(path_items: I) -> Result<Arc<dyn Directory>, SvsmError>
where
I: Iterator<Item = &'a str>,
{
let mut current_dir = unsafe { FS_ROOT.root_dir() };

for item in path_items.iter() {
let dir_name = FileName::from(*item);
for item in path_items {
let dir_name = FileName::from(item);
let lookup = current_dir.lookup_entry(dir_name);
let dir_entry = match lookup {
Ok(entry) => entry,
Expand All @@ -192,8 +196,8 @@ fn walk_path_create(path_items: &[&str]) -> Result<Arc<dyn Directory>, SvsmError

pub fn open(path: &str) -> Result<FileHandle, SvsmError> {
let mut path_items = split_path(path)?;
let file_name = FileName::from(path_items.pop().unwrap());
let current_dir = walk_path(&path_items)?;
let file_name = FileName::from(path_items.next_back().unwrap());
let current_dir = walk_path(path_items)?;

let dir_entry = current_dir.lookup_entry(file_name)?;

Expand All @@ -205,8 +209,8 @@ pub fn open(path: &str) -> Result<FileHandle, SvsmError> {

pub fn create(path: &str) -> Result<FileHandle, SvsmError> {
let mut path_items = split_path(path)?;
let file_name = FileName::from(path_items.pop().unwrap());
let current_dir = walk_path(&path_items)?;
let file_name = FileName::from(path_items.next_back().unwrap());
let current_dir = walk_path(path_items)?;
let file = current_dir.create_file(file_name)?;

Ok(FileHandle::new(&file))
Expand All @@ -215,8 +219,8 @@ pub fn create(path: &str) -> Result<FileHandle, SvsmError> {
/// Creates a file with all sub-directories
pub fn create_all(path: &str) -> Result<FileHandle, SvsmError> {
let mut path_items = split_path(path)?;
let file_name = FileName::from(path_items.pop().unwrap());
let current_dir = walk_path_create(&path_items)?;
let file_name = FileName::from(path_items.next_back().unwrap());
let current_dir = walk_path_create(path_items)?;

if file_name.length() == 0 {
return Err(SvsmError::FileSystem(FsError::inval()));
Expand All @@ -229,8 +233,8 @@ pub fn create_all(path: &str) -> Result<FileHandle, SvsmError> {

pub fn mkdir(path: &str) -> Result<(), SvsmError> {
let mut path_items = split_path(path)?;
let dir_name = FileName::from(path_items.pop().unwrap());
let current_dir = walk_path(&path_items)?;
let dir_name = FileName::from(path_items.next_back().unwrap());
let current_dir = walk_path(path_items)?;

current_dir.create_directory(dir_name)?;

Expand All @@ -239,15 +243,15 @@ pub fn mkdir(path: &str) -> Result<(), SvsmError> {

pub fn unlink(path: &str) -> Result<(), SvsmError> {
let mut path_items = split_path(path)?;
let entry_name = FileName::from(path_items.pop().unwrap());
let dir = walk_path(&path_items)?;
let entry_name = FileName::from(path_items.next_back().unwrap());
let dir = walk_path(path_items)?;

dir.unlink(entry_name)
}

pub fn list_dir(path: &str) -> Result<Vec<FileName>, SvsmError> {
let items = split_path_allow_empty(path);
let dir = walk_path(&items)?;
let dir = walk_path(items)?;
Ok(dir.list())
}

Expand Down
102 changes: 71 additions & 31 deletions src/fs/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ use super::*;

extern crate alloc;
use alloc::slice;
use alloc::string::String;
use alloc::vec::Vec;

const PACKIT_MAGIC: [u8; 4] = [0x50, 0x4b, 0x49, 0x54];

#[derive(Clone, Copy, Debug)]
struct PackItHeader {
/// Header Magic (PKIT)
magic: [u8; 4],
Expand Down Expand Up @@ -57,14 +56,68 @@ impl PackItHeader {
}
}

struct FileHeader {
#[derive(Clone, Debug)]
struct FsArchive<'a> {
_hdr: PackItHeader,
data: &'a [u8],
current: usize,
}

impl<'a> FsArchive<'a> {
fn load(data: &'a [u8]) -> Result<Self, SvsmError> {
let _hdr = PackItHeader::load(data)?;
let current = _hdr.len();
Ok(Self {
_hdr,
data,
current,
})
}
}

impl<'a> core::iter::Iterator for FsArchive<'a> {
type Item = Result<FsFile<'a>, SvsmError>;

fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.data.len() {
return None;
}

let hdr = match FileHeader::load(&self.data[self.current..]) {
Ok(hdr) => hdr,
Err(e) => return Some(Err(e)),
};

let Some(start) = self.current.checked_add(hdr.header_size()) else {
return Some(Err(SvsmError::FileSystem(FsError::inval())));
};
let Some(end) = start.checked_add(hdr.file_size()) else {
return Some(Err(SvsmError::FileSystem(FsError::inval())));
};
let Some(data) = self.data.get(start..end) else {
return Some(Err(SvsmError::FileSystem(FsError::inval())));
};

self.current += hdr.total_size();

Some(Ok(FsFile { hdr, data }))
}
}

struct FsFile<'a> {
hdr: FileHeader<'a>,
data: &'a [u8],
}

#[derive(Clone, Debug)]
struct FileHeader<'a> {
name_len: u16,
file_size: u64,
name: String,
name: &'a str,
}

impl FileHeader {
fn load(buf: &[u8]) -> Result<Self, SvsmError> {
impl<'a> FileHeader<'a> {
fn load(buf: &'a [u8]) -> Result<Self, SvsmError> {
if buf.len() < 12 {
log::error!("Unexpected end of archive");
return Err(SvsmError::FileSystem(FsError::inval()));
Expand All @@ -82,7 +135,7 @@ impl FileHeader {
return Err(SvsmError::FileSystem(FsError::inval()));
}

let Ok(name) = String::from_utf8(Vec::from(&buf[12..header_len])) else {
let Ok(name) = core::str::from_utf8(&buf[12..header_len]) else {
log::error!("Invalid filename in archive");
return Err(SvsmError::FileSystem(FsError::inval()));
};
Expand All @@ -100,7 +153,7 @@ impl FileHeader {
}

fn file_name(&self) -> &str {
self.name.as_str()
self.name
}

fn file_size(&self) -> usize {
Expand Down Expand Up @@ -135,32 +188,19 @@ pub fn populate_ram_fs(kernel_fs_start: u64, kernel_fs_end: u64) -> Result<(), S
let vstart = guard.virt_addr().offset(pstart.page_offset());

let data: &[u8] = unsafe { slice::from_raw_parts(vstart.as_ptr(), size) };
let hdr = PackItHeader::load(data)?;

let mut current = hdr.len();
while current < size {
let fh = FileHeader::load(&data[current..])?;

let start = current
.checked_add(fh.header_size())
.ok_or(SvsmError::FileSystem(FsError::inval()))?;
let end = start
.checked_add(fh.file_size())
.ok_or(SvsmError::FileSystem(FsError::inval()))?;

let file = create_all(fh.file_name())?;
let file_data = data
.get(start..end)
.ok_or(SvsmError::FileSystem(FsError::inval()))?;
file.truncate(0)?;
let written = file.write(file_data)?;
if written != fh.file_size() {
log::error!("Incomplete data write to {}", fh.file_name());
let archive = FsArchive::load(data)?;

for file in archive {
let file = file?;
let handle = create_all(file.hdr.file_name())?;
handle.truncate(0)?;
let written = handle.write(file.data)?;
if written != file.hdr.file_size() {
log::error!("Incomplete data write to {}", file.hdr.file_name());
return Err(SvsmError::FileSystem(FsError::inval()));
}

log::info!(" Unpacked {}", fh.file_name());
current += fh.total_size();
log::info!(" Unpacked {}", file.hdr.file_name());
}

log::info!("Unpacking done");
Expand Down

0 comments on commit 9c2228e

Please sign in to comment.