diff --git a/Cargo.toml b/Cargo.toml index 8330f1e..190a96d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ authors = ["Szymon Walter "] bitflags = "1.0" rlibc = { version = "1.0", optional = true } spin = "0.4" +genfs = "^0.1.4" [features] default = ["no_std"] diff --git a/src/error.rs b/src/error.rs index 2d9091d..161b39d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,5 @@ use core::fmt::{self, Display}; -use alloc::{String, Vec}; +use alloc::String; #[cfg(any(test, not(feature = "no_std")))] use std::io; diff --git a/src/fs/sync.rs b/src/fs/sync.rs index e783c08..9a864d5 100644 --- a/src/fs/sync.rs +++ b/src/fs/sync.rs @@ -6,6 +6,7 @@ use alloc::{String, Vec}; use alloc::arc::Arc; use spin::{Mutex, MutexGuard}; +use genfs::*; use error::Error; use sector::{Address, SectorSize}; @@ -43,82 +44,11 @@ impl> Synced> { Ext2::new(volume).map(|inner| Synced::with_inner(inner)) } - pub fn find_inode( - &self, - abs_path: &[u8], - ) -> Result<(Inode, Address), Error> { - pub fn inner<'a, S, V, I>( - fs: &Synced>, - inode: (u32, Inode, Address), - mut path: I, - abs_path: &[u8], - ) -> Result<(Inode, Address), Error> - where - S: SectorSize, - V: Volume, - I: Iterator, - { - 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, Address) { + pub fn root_inode(&self) -> Inode { self.inode_nth(2).unwrap() } - pub fn inode_nth(&self, index: usize) -> Option<(Inode, Address)> { + pub fn inode_nth(&self, index: usize) -> Option> { self.inodes_nth(index).next() } @@ -148,6 +78,172 @@ impl> Synced> { } } +impl> Fs for Synced> { + type Path = [u8]; + type PathOwned = Vec; + type File = Inode; + type Dir = Directory; + type DirEntry = DirectoryEntry; + type Metadata = (); // TODO + type Permissions = (); // TODO + type Error = Error; + + fn open( + &self, + abs_path: &Self::Path, + _options: &OpenOptions, + ) -> Result { + fn inner<'a, S, V, I>( + fs: &Synced>, + inode: Inode, + mut path: I, + abs_path: &[u8], + ) -> Result, Error> + where + S: SectorSize, + V: Volume, + I: Iterator, + { + let name = match path.next() { + Some(name) => name, + None => return Ok(inode), + }; + + let mut dir = + inode.directory().ok_or_else(|| Error::NotADirectory { + inode: inode.num, + name: String::from_utf8_lossy(abs_path).into_owned(), + })?; + + let entry = dir.find(|entry| { + entry.is_err() || entry.as_ref().unwrap().name == name + }).ok_or_else(|| Error::NotFound { + name: String::from_utf8_lossy(abs_path).into_owned(), + })??; + + let inode = fs.inode_nth(entry.inode) + .ok_or(Error::InodeNotFound { inode: inode.num })?; + + 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 = self.root_inode(); + + inner(self, root, path, abs_path) + } + + fn remove_file(&mut self, _path: &Self::Path) -> Result<(), Self::Error> { + unimplemented!() + } + + fn metadata( + &self, + _path: &Self::Path, + ) -> Result { + unimplemented!() + } + + fn symlink_metadata( + &self, + _path: &Self::Path, + ) -> Result { + unimplemented!() + } + + fn rename( + &mut self, + _from: &Self::Path, + _to: &Self::Path, + ) -> Result<(), Self::Error> { + unimplemented!() + } + + fn copy( + &mut self, + _from: &Self::Path, + _to: &Self::Path, + ) -> Result { + unimplemented!() + } + + fn hard_link( + &mut self, + _src: &Self::Path, + _dst: &Self::Path, + ) -> Result<(), Self::Error> { + unimplemented!() + } + + fn symlink( + &mut self, + _src: &Self::Path, + _dst: &Self::Path, + ) -> Result<(), Self::Error> { + unimplemented!() + } + + fn read_link( + &self, + _path: &Self::Path, + ) -> Result { + unimplemented!() + } + + fn canonicalize( + &self, + _path: &Self::Path, + ) -> Result { + unimplemented!() + } + + fn create_dir( + &mut self, + _path: &Self::Path, + _options: &DirOptions, + ) -> Result<(), Self::Error> { + unimplemented!() + } + + fn remove_dir(&mut self, _path: &Self::Path) -> Result<(), Self::Error> { + unimplemented!() + } + + fn remove_dir_all( + &mut self, + _path: &Self::Path, + ) -> Result<(), Self::Error> { + unimplemented!() + } + + fn read_dir(&self, path: &Self::Path) -> Result { + let inode = self.open(path, OpenOptions::new().read(true))?; + inode.directory().ok_or(Error::NotADirectory { + inode: inode.num, + name: String::from_utf8_lossy(path).into_owned(), + }) + } + + fn set_permissions( + &mut self, + _path: &Self::Path, + _perm: Self::Permissions, + ) -> Result<(), Self::Error> { + unimplemented!() + } +} + impl> Debug for Synced> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Synced>", S::SIZE) @@ -165,7 +261,7 @@ pub struct Inodes> { } impl> Iterator for Inodes { - type Item = (Inode, Address); + type Item = Inode; fn next(&mut self) -> Option { if self.index < self.inodes_count { @@ -186,7 +282,14 @@ impl> Iterator for Inodes { let raw = unsafe { RawInode::find_inode(&fs.volume, offset, self.inode_size).ok() }; - raw.map(|(raw, offset)| (Inode::new(self.fs.clone(), raw), offset)) + raw.map(|(raw, offset)| { + Inode::new( + self.fs.clone(), + raw, + offset, + (self.index - 1) as u32, + ) + }) } else { None } @@ -197,6 +300,8 @@ impl> Iterator for Inodes { pub struct Inode> { fs: Synced>, inner: RawInode, + addr: Address, + num: u32, } impl> Clone for Inode { @@ -204,38 +309,25 @@ impl> Clone for Inode { Inode { fs: self.fs.clone(), inner: self.inner, + addr: self.addr, + num: self.num, } } } impl> Inode { - pub fn new(fs: Synced>, inner: RawInode) -> Inode { - Inode { fs, inner } - } - - pub fn read(&self, buf: &mut [u8]) -> Result { - let total_size = self.size(); - let block_size = { - let fs = self.fs.inner(); - fs.block_size() - }; - let mut offset = 0; - - for block in self.blocks() { - match block { - Ok((data, _)) => { - let data_size = block_size - .min(total_size - offset) - .min(buf.len() - offset); - let end = offset + data_size; - buf[offset..end].copy_from_slice(&data[..data_size]); - offset += data_size; - } - Err(err) => return Err(err.into()), - } + pub fn new( + fs: Synced>, + inner: RawInode, + addr: Address, + num: u32, + ) -> Inode { + Inode { + fs, + inner, + addr, + num, } - - Ok(offset) } pub fn read_to_end(&self, buf: &mut Vec) -> Result { @@ -437,6 +529,47 @@ impl> Inode { } } +impl> File for Inode { + type Error = Error; + + fn read(&self, buf: &mut [u8]) -> Result { + let total_size = self.size(); + let block_size = { + let fs = self.fs.inner(); + fs.block_size() + }; + let mut offset = 0; + + for block in self.blocks() { + match block { + Ok((data, _)) => { + let data_size = block_size + .min(total_size - offset) + .min(buf.len() - offset); + let end = offset + data_size; + buf[offset..end].copy_from_slice(&data[..data_size]); + offset += data_size; + } + Err(err) => return Err(err.into()), + } + } + + Ok(offset) + } + + fn write(&mut self, _buf: &[u8]) -> Result { + unimplemented!() + } + + fn flush(&mut self) -> Result<(), Self::Error> { + unimplemented!() + } + + fn seek(&mut self, _pos: SeekFrom) -> Result { + unimplemented!() + } +} + #[derive(Debug, Clone)] pub struct InodeBlocks> { inode: Inode, @@ -478,6 +611,11 @@ pub struct Directory> { block_size: usize, } +impl> Dir + for Directory +{ +} + impl> Iterator for Directory { type Item = Result; @@ -524,11 +662,37 @@ pub struct DirectoryEntry { pub ty: u8, } +impl DirEntry for DirectoryEntry { + type Path = [u8]; + type PathOwned = Vec; + type Metadata = (); // TODO + type FileType = u8; // TODO: enum FileType + type Error = Error; + + fn path(&self) -> Self::PathOwned { + unimplemented!() + } + + fn metadata(&self) -> Result { + unimplemented!() + } + + fn file_type(&self) -> Result { + Ok(self.ty) + } + + fn file_name(&self) -> &Self::Path { + &self.name + } +} + #[cfg(test)] mod tests { use std::fs::File; use std::cell::RefCell; + use genfs::{File as GenFile, Fs, OpenOptions}; + use sector::{SectorSize, Size512}; use volume::Volume; @@ -566,7 +730,7 @@ mod tests { let fs = fs.unwrap(); - let inodes = fs.inodes().filter(|inode| inode.0.in_use()); + let inodes = fs.inodes().filter(|inode| inode.in_use()); for inode in inodes { println!("{:?}", inode); } @@ -579,12 +743,12 @@ mod tests { let fs = Synced::>::new(file).unwrap(); let inodes = fs.inodes().filter(|inode| { - inode.0.in_use() && inode.0.uid() == 1000 && inode.0.size() < 1024 + inode.in_use() && inode.uid() == 1000 && inode.size() < 1024 }); for inode in inodes { - println!("{:?}", inode.0); - let size = inode.0.size(); - for block in inode.0.blocks() { + println!("{:?}", inode); + let size = inode.size(); + for block in inode.blocks() { let (data, _) = block.unwrap(); assert_eq!(data.len(), { let fs = fs.inner(); @@ -603,9 +767,9 @@ mod tests { let fs = Synced::>::new(file).unwrap(); let inodes = fs.inodes().filter(|inode| { - inode.0.in_use() && inode.0.uid() == 1000 && inode.0.size() < 1024 + inode.in_use() && inode.uid() == 1000 && inode.size() < 1024 }); - for (inode, _) in inodes { + for inode in inodes { let mut buf = Vec::with_capacity(inode.size()); unsafe { buf.set_len(inode.size()); @@ -626,10 +790,9 @@ mod tests { let fs = Synced::>::new(file).unwrap(); let inodes = fs.inodes().filter(|inode| { - inode.0.in_use() && inode.0.uid() == 1000 - && inode.0.size() == 537600 + inode.in_use() && inode.uid() == 1000 && inode.size() == 537600 }); - for (inode, _) in inodes { + for inode in inodes { let mut buf = Vec::with_capacity(inode.size()); unsafe { buf.set_len(inode.size()); @@ -670,7 +833,7 @@ mod tests { if entry_name != "." && entry_name != ".." { walk( fs, - fs.inode_nth(entry.inode).unwrap().0, + fs.inode_nth(entry.inode).unwrap(), format!("{}/{}", name, entry_name), ); } @@ -681,7 +844,7 @@ mod tests { let file = RefCell::new(File::open("ext2.img").unwrap()); let fs = Synced::>::new(file).unwrap(); - let (root, _) = fs.root_inode(); + let root = fs.root_inode(); walk(&fs, root, String::new()); } @@ -691,10 +854,10 @@ mod tests { let file = RefCell::new(File::open("ext2.img").unwrap()); let fs = Synced::>::new(file).unwrap(); - let found = fs.find_inode(b"/home/funky/README.md"); + let found = fs.open(b"/home/funky/README.md", &OpenOptions::new()); assert!(found.is_ok()); - let (inode, _) = found.unwrap(); + let inode = found.unwrap(); let mut vec = Vec::new(); assert!(inode.read_to_end(&mut vec).is_ok()); println!("{}", str::from_utf8(&vec).unwrap()); diff --git a/src/lib.rs b/src/lib.rs index f6e749d..2b6f35c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ extern crate alloc; #[macro_use] extern crate bitflags; +extern crate genfs; extern crate spin; #[cfg(any(test, not(feature = "no_std")))]