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 alloc::String;
|
||||
use alloc::{String, Vec};
|
||||
|
||||
#[cfg(any(test, not(feature = "no_std")))]
|
||||
use std::io;
|
||||
|
@ -23,6 +23,19 @@ pub enum Error {
|
|||
by_blocks: 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")))]
|
||||
Io {
|
||||
inner: io::Error,
|
||||
|
@ -49,6 +62,19 @@ impl Display for Error {
|
|||
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")))]
|
||||
Error::Io {
|
||||
ref inner,
|
||||
|
|
120
src/fs/sync.rs
120
src/fs/sync.rs
|
@ -1,7 +1,8 @@
|
|||
use core::fmt::{self, Debug};
|
||||
use core::nonzero::NonZero;
|
||||
use core::iter::Iterator;
|
||||
|
||||
use alloc::Vec;
|
||||
use alloc::{String, Vec};
|
||||
use alloc::arc::Arc;
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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>) {
|
||||
self.inode_nth(2).unwrap()
|
||||
}
|
||||
|
@ -166,6 +238,29 @@ impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
|
|||
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> {
|
||||
InodeBlocks {
|
||||
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>> {
|
||||
use sys::inode::TypePerm;
|
||||
if unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) } {
|
||||
if self.is_dir() {
|
||||
Some(Directory {
|
||||
blocks: self.blocks(),
|
||||
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>> {
|
||||
self.try_block(index).ok().and_then(|block| block)
|
||||
}
|
||||
|
@ -585,4 +684,19 @@ mod tests {
|
|||
let (root, _) = fs.root_inode();
|
||||
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