Implement searching for an inode by name (#1)
`Synced<Ext2>` now provides the method `find_inode`, which searches for an inode by absolute path. New errors that can occur during searching were added. This commit concludes feature #1, `fopen`.
This commit is contained in:
parent
f06ed46397
commit
057b3cc7e9
28
src/error.rs
28
src/error.rs
|
@ -1,5 +1,5 @@
|
||||||
use core::fmt::{self, Display};
|
use core::fmt::{self, Display};
|
||||||
use alloc::String;
|
use alloc::{String, Vec};
|
||||||
|
|
||||||
#[cfg(any(test, not(feature = "no_std")))]
|
#[cfg(any(test, not(feature = "no_std")))]
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -23,6 +23,19 @@ pub enum Error {
|
||||||
by_blocks: u32,
|
by_blocks: u32,
|
||||||
by_inodes: u32,
|
by_inodes: u32,
|
||||||
},
|
},
|
||||||
|
InodeNotFound {
|
||||||
|
inode: u32,
|
||||||
|
},
|
||||||
|
NotADirectory {
|
||||||
|
inode: u32,
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
|
NotAbsolute {
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
|
NotFound {
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
#[cfg(any(test, not(feature = "no_std")))]
|
#[cfg(any(test, not(feature = "no_std")))]
|
||||||
Io {
|
Io {
|
||||||
inner: io::Error,
|
inner: io::Error,
|
||||||
|
@ -49,6 +62,19 @@ impl Display for Error {
|
||||||
by_blocks,
|
by_blocks,
|
||||||
by_inodes,
|
by_inodes,
|
||||||
} => write!(f, "conflicting block group count data; by blocks: {}, by inodes: {}", by_blocks, by_inodes),
|
} => write!(f, "conflicting block group count data; by blocks: {}, by inodes: {}", by_blocks, by_inodes),
|
||||||
|
Error::InodeNotFound {
|
||||||
|
inode,
|
||||||
|
} => write!(f, "couldn't find inode no. {}", &inode),
|
||||||
|
Error::NotADirectory {
|
||||||
|
inode,
|
||||||
|
ref name,
|
||||||
|
} => write!(f, "inode no. {} at: {} is not a directory", inode, &name),
|
||||||
|
Error::NotAbsolute {
|
||||||
|
ref name,
|
||||||
|
} => write!(f, "{} is not an absolute path", &name),
|
||||||
|
Error::NotFound {
|
||||||
|
ref name,
|
||||||
|
} => write!(f, "couldn't find {}", &name),
|
||||||
#[cfg(any(test, not(feature = "no_std")))]
|
#[cfg(any(test, not(feature = "no_std")))]
|
||||||
Error::Io {
|
Error::Io {
|
||||||
ref inner,
|
ref inner,
|
||||||
|
|
120
src/fs/sync.rs
120
src/fs/sync.rs
|
@ -1,7 +1,8 @@
|
||||||
use core::fmt::{self, Debug};
|
use core::fmt::{self, Debug};
|
||||||
use core::nonzero::NonZero;
|
use core::nonzero::NonZero;
|
||||||
|
use core::iter::Iterator;
|
||||||
|
|
||||||
use alloc::Vec;
|
use alloc::{String, Vec};
|
||||||
use alloc::arc::Arc;
|
use alloc::arc::Arc;
|
||||||
|
|
||||||
use spin::{Mutex, MutexGuard};
|
use spin::{Mutex, MutexGuard};
|
||||||
|
@ -42,6 +43,77 @@ impl<S: SectorSize, V: Volume<u8, S>> Synced<Ext2<S, V>> {
|
||||||
Ext2::new(volume).map(|inner| Synced::with_inner(inner))
|
Ext2::new(volume).map(|inner| Synced::with_inner(inner))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_inode(
|
||||||
|
&self,
|
||||||
|
abs_path: &[u8],
|
||||||
|
) -> Result<(Inode<S, V>, Address<S>), Error> {
|
||||||
|
pub fn inner<'a, S, V, I>(
|
||||||
|
fs: &Synced<Ext2<S, V>>,
|
||||||
|
inode: (u32, Inode<S, V>, Address<S>),
|
||||||
|
mut path: I,
|
||||||
|
abs_path: &[u8],
|
||||||
|
) -> Result<(Inode<S, V>, Address<S>), Error>
|
||||||
|
where
|
||||||
|
S: SectorSize,
|
||||||
|
V: Volume<u8, S>,
|
||||||
|
I: Iterator<Item = &'a [u8]>,
|
||||||
|
{
|
||||||
|
let name = match path.next() {
|
||||||
|
Some(name) => name,
|
||||||
|
None => return Ok((inode.1, inode.2)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut dir = match inode.1.directory() {
|
||||||
|
Some(dir) => dir,
|
||||||
|
None => {
|
||||||
|
return Err(Error::NotADirectory {
|
||||||
|
inode: inode.0,
|
||||||
|
name: String::from_utf8_lossy(abs_path).into_owned(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let num = match dir.find(|entry| {
|
||||||
|
entry.is_err() || entry.as_ref().unwrap().name == name
|
||||||
|
}) {
|
||||||
|
Some(Ok(entry)) => entry.inode,
|
||||||
|
Some(Err(err)) => return Err(err),
|
||||||
|
None => {
|
||||||
|
return Err(Error::NotFound {
|
||||||
|
name: String::from_utf8_lossy(abs_path).into_owned(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let inode = match fs.inode_nth(num) {
|
||||||
|
Some((inode, addr)) => (num as u32, inode, addr),
|
||||||
|
None => {
|
||||||
|
return Err(Error::InodeNotFound {
|
||||||
|
inode: inode.0 as u32,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inner(fs, inode, path, abs_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if abs_path.len() == 0 || abs_path[0] != b'/' {
|
||||||
|
return Err(Error::NotAbsolute {
|
||||||
|
name: String::from_utf8_lossy(abs_path).into_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if abs_path == b"/" {
|
||||||
|
return Ok(self.root_inode());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut path = abs_path.split(|byte| *byte == b'/');
|
||||||
|
path.next();
|
||||||
|
let (root, addr) = self.root_inode();
|
||||||
|
|
||||||
|
inner(self, (2, root, addr), path, abs_path)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn root_inode(&self) -> (Inode<S, V>, Address<S>) {
|
pub fn root_inode(&self) -> (Inode<S, V>, Address<S>) {
|
||||||
self.inode_nth(2).unwrap()
|
self.inode_nth(2).unwrap()
|
||||||
}
|
}
|
||||||
|
@ -166,6 +238,29 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
|
||||||
Ok(offset)
|
Ok(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize, Error> {
|
||||||
|
let total_size = self.size();
|
||||||
|
let capacity = buf.capacity();
|
||||||
|
if capacity < total_size {
|
||||||
|
buf.reserve_exact(total_size - capacity);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
buf.set_len(total_size);
|
||||||
|
}
|
||||||
|
let size = self.read(&mut buf[..]);
|
||||||
|
size.and_then(|size| {
|
||||||
|
unsafe {
|
||||||
|
buf.set_len(size);
|
||||||
|
}
|
||||||
|
Ok(size)
|
||||||
|
}).or_else(|err| {
|
||||||
|
unsafe {
|
||||||
|
buf.set_len(0);
|
||||||
|
}
|
||||||
|
Err(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn blocks(&self) -> InodeBlocks<S, V> {
|
pub fn blocks(&self) -> InodeBlocks<S, V> {
|
||||||
InodeBlocks {
|
InodeBlocks {
|
||||||
inode: self.clone(),
|
inode: self.clone(),
|
||||||
|
@ -174,8 +269,7 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn directory(&self) -> Option<Directory<S, V>> {
|
pub fn directory(&self) -> Option<Directory<S, V>> {
|
||||||
use sys::inode::TypePerm;
|
if self.is_dir() {
|
||||||
if unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) } {
|
|
||||||
Some(Directory {
|
Some(Directory {
|
||||||
blocks: self.blocks(),
|
blocks: self.blocks(),
|
||||||
offset: 0,
|
offset: 0,
|
||||||
|
@ -190,6 +284,11 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_dir(&self) -> bool {
|
||||||
|
use sys::inode::TypePerm;
|
||||||
|
unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn block(&self, index: usize) -> Option<NonZero<u32>> {
|
pub fn block(&self, index: usize) -> Option<NonZero<u32>> {
|
||||||
self.try_block(index).ok().and_then(|block| block)
|
self.try_block(index).ok().and_then(|block| block)
|
||||||
}
|
}
|
||||||
|
@ -585,4 +684,19 @@ mod tests {
|
||||||
let (root, _) = fs.root_inode();
|
let (root, _) = fs.root_inode();
|
||||||
walk(&fs, root, String::new());
|
walk(&fs, root, String::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn find() {
|
||||||
|
use std::str;
|
||||||
|
let file = RefCell::new(File::open("ext2.img").unwrap());
|
||||||
|
let fs = Synced::<Ext2<Size512, _>>::new(file).unwrap();
|
||||||
|
|
||||||
|
let found = fs.find_inode(b"/home/funky/README.md");
|
||||||
|
|
||||||
|
assert!(found.is_ok());
|
||||||
|
let (inode, _) = found.unwrap();
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
assert!(inode.read_to_end(&mut vec).is_ok());
|
||||||
|
println!("{}", str::from_utf8(&vec).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue