BREAK: sfs direntry no longer take up a block

master
WangRunji 6 years ago
parent d39d3baea3
commit d071071342

@ -70,7 +70,8 @@ fn main() {
let device = Mutex::new(file); let device = Mutex::new(file);
const MAX_SPACE: usize = 0x1000 * 0x1000 * 1024; // 1G const MAX_SPACE: usize = 0x1000 * 0x1000 * 1024; // 1G
match create { match create {
true => sfs::SimpleFileSystem::create(Arc::new(device), MAX_SPACE), true => sfs::SimpleFileSystem::create(Arc::new(device), MAX_SPACE)
.expect("failed to create sfs"),
false => sfs::SimpleFileSystem::open(Arc::new(device)).expect("failed to open sfs"), false => sfs::SimpleFileSystem::open(Arc::new(device)).expect("failed to open sfs"),
} }
} }

@ -10,8 +10,8 @@ use alloc::{
collections::BTreeMap, collections::BTreeMap,
string::String, string::String,
sync::{Arc, Weak}, sync::{Arc, Weak},
vec::Vec,
vec, vec,
vec::Vec,
}; };
use core::any::Any; use core::any::Any;
use core::fmt::{Debug, Error, Formatter}; use core::fmt::{Debug, Error, Formatter};
@ -49,19 +49,20 @@ trait DeviceExt: Device {
/// Load struct `T` from given block in device /// Load struct `T` from given block in device
fn load_struct<T: AsBuf>(&self, id: BlockId) -> vfs::Result<T> { fn load_struct<T: AsBuf>(&self, id: BlockId) -> vfs::Result<T> {
let mut s: T = unsafe { uninitialized() }; let mut s: T = unsafe { uninitialized() };
self.read_block(id, 0, s.as_buf_mut()).map(|_| s) self.read_block(id, 0, s.as_buf_mut())?;
Ok(s)
} }
} }
impl DeviceExt for Device {} impl DeviceExt for Device {}
/// inode for sfs /// INode for SFS
pub struct INodeImpl { pub struct INodeImpl {
/// inode number /// INode number
id: INodeId, id: INodeId,
/// on-disk inode /// On-disk INode
disk_inode: RwLock<Dirty<DiskINode>>, disk_inode: RwLock<Dirty<DiskINode>>,
/// Weak reference to SFS, used by almost all operations /// Reference to SFS, used by almost all operations
fs: Arc<SimpleFileSystem>, fs: Arc<SimpleFileSystem>,
} }
@ -152,13 +153,8 @@ impl INodeImpl {
} }
/// Only for Dir /// Only for Dir
fn get_file_inode_and_entry_id(&self, name: &str) -> Option<(INodeId, usize)> { fn get_file_inode_and_entry_id(&self, name: &str) -> Option<(INodeId, usize)> {
(0..self.disk_inode.read().blocks) (0..self.disk_inode.read().size as usize / DIRENT_SIZE)
.map(|i| { .map(|i| (self.read_direntry(i as usize).unwrap(), i))
let mut entry: DiskEntry = unsafe { uninitialized() };
self._read_at(i as usize * BLKSIZE, entry.as_buf_mut())
.unwrap();
(entry, i)
})
.find(|(entry, _)| entry.name.as_ref() == name) .find(|(entry, _)| entry.name.as_ref() == name)
.map(|(entry, id)| (entry.id as INodeId, id as usize)) .map(|(entry, id)| (entry.id as INodeId, id as usize))
} }
@ -168,40 +164,50 @@ impl INodeImpl {
} }
/// Init dir content. Insert 2 init entries. /// Init dir content. Insert 2 init entries.
/// This do not init nlinks, please modify the nlinks in the invoker. /// This do not init nlinks, please modify the nlinks in the invoker.
fn init_dir_entry(&self, parent: INodeId) -> vfs::Result<()> { fn init_direntry(&self, parent: INodeId) -> vfs::Result<()> {
// Insert entries: '.' '..' // Insert entries: '.' '..'
self._resize(BLKSIZE * 2)?; self._resize(DIRENT_SIZE * 2)?;
self._write_at( self.write_direntry(
BLKSIZE * 1, 0,
DiskEntry { &DiskEntry {
id: self.id as u32,
name: Str256::from("."),
},
)?;
self.write_direntry(
1,
&DiskEntry {
id: parent as u32, id: parent as u32,
name: Str256::from(".."), name: Str256::from(".."),
},
)?;
Ok(())
} }
.as_buf(), fn read_direntry(&self, id: usize) -> vfs::Result<DiskEntry> {
) let mut direntry: DiskEntry = unsafe { uninitialized() };
.unwrap(); self._read_at(DIRENT_SIZE * id, direntry.as_buf_mut())?;
self._write_at( Ok(direntry)
BLKSIZE * 0,
DiskEntry {
id: self.id as u32,
name: Str256::from("."),
} }
.as_buf(), fn write_direntry(&self, id: usize, direntry: &DiskEntry) -> vfs::Result<()> {
) self._write_at(DIRENT_SIZE * id, direntry.as_buf())?;
.unwrap();
Ok(()) Ok(())
} }
/// remove a page in middle of file and insert the last page here, useful for dirent remove fn append_direntry(&self, direntry: &DiskEntry) -> vfs::Result<()> {
let size = self.disk_inode.read().size as usize;
let dirent_count = size / DIRENT_SIZE;
self._resize(size + DIRENT_SIZE)?;
self.write_direntry(dirent_count, direntry)?;
Ok(())
}
/// remove a direntry in middle of file and insert the last one here, useful for direntry remove
/// should be only used in unlink /// should be only used in unlink
fn remove_dirent_page(&self, id: usize) -> vfs::Result<()> { fn remove_direntry(&self, id: usize) -> vfs::Result<()> {
debug_assert!(id < self.disk_inode.read().blocks as usize); let size = self.disk_inode.read().size as usize;
let to_remove = self.get_disk_block_id(id)?; let dirent_count = size / DIRENT_SIZE;
let current_last = self.get_disk_block_id(self.disk_inode.read().blocks as usize - 1)?; debug_assert!(id < dirent_count);
self.set_disk_block_id(id, current_last)?; let last_dirent = self.read_direntry(dirent_count - 1)?;
self.disk_inode.write().blocks -= 1; self.write_direntry(id, &last_dirent)?;
let new_size = self.disk_inode.read().blocks as usize * BLKSIZE; self._resize(size - DIRENT_SIZE)?;
self._set_size(new_size);
self.fs.free_block(to_remove);
Ok(()) Ok(())
} }
/// Resize content size, no matter what type it is. /// Resize content size, no matter what type it is.
@ -216,9 +222,10 @@ impl INodeImpl {
use core::cmp::Ordering; use core::cmp::Ordering;
let old_blocks = self.disk_inode.read().blocks; let old_blocks = self.disk_inode.read().blocks;
match blocks.cmp(&old_blocks) { match blocks.cmp(&old_blocks) {
Ordering::Equal => {} // Do nothing Ordering::Equal => {
self.disk_inode.write().size = len as u32;
}
Ordering::Greater => { Ordering::Greater => {
{
let mut disk_inode = self.disk_inode.write(); let mut disk_inode = self.disk_inode.write();
disk_inode.blocks = blocks; disk_inode.blocks = blocks;
// allocate indirect block if needed // allocate indirect block if needed
@ -247,16 +254,18 @@ impl INodeImpl {
)?; )?;
} }
} }
} drop(disk_inode);
// allocate extra blocks // allocate extra blocks
for i in old_blocks..blocks { for i in old_blocks..blocks {
let disk_block_id = self.fs.alloc_block().expect("no space"); let disk_block_id = self.fs.alloc_block().expect("no space");
self.set_disk_block_id(i as usize, disk_block_id)?; self.set_disk_block_id(i as usize, disk_block_id)?;
} }
// clean up // clean up
let old_size = self._size(); let mut disk_inode = self.disk_inode.write();
self._set_size(len); let old_size = disk_inode.size as usize;
self._clean_at(old_size, len).unwrap(); disk_inode.size = len as u32;
drop(disk_inode);
self._clean_at(old_size, len)?;
} }
Ordering::Less => { Ordering::Less => {
// free extra blocks // free extra blocks
@ -266,7 +275,9 @@ impl INodeImpl {
} }
let mut disk_inode = self.disk_inode.write(); let mut disk_inode = self.disk_inode.write();
// free indirect block if needed // free indirect block if needed
if blocks < MAX_NBLOCK_DIRECT as u32 && disk_inode.blocks >= MAX_NBLOCK_DIRECT as u32 { if blocks < MAX_NBLOCK_DIRECT as u32
&& disk_inode.blocks >= MAX_NBLOCK_DIRECT as u32
{
self.fs.free_block(disk_inode.indirect as usize); self.fs.free_block(disk_inode.indirect as usize);
disk_inode.indirect = 0; disk_inode.indirect = 0;
} }
@ -279,7 +290,8 @@ impl INodeImpl {
(blocks as usize - MAX_NBLOCK_INDIRECT) / BLK_NENTRY + 1 (blocks as usize - MAX_NBLOCK_INDIRECT) / BLK_NENTRY + 1
} }
}; };
let indirect_end = (disk_inode.blocks as usize - MAX_NBLOCK_INDIRECT) / BLK_NENTRY + 1; let indirect_end =
(disk_inode.blocks as usize - MAX_NBLOCK_INDIRECT) / BLK_NENTRY + 1;
for i in indirect_begin..indirect_end { for i in indirect_begin..indirect_end {
let mut indirect: u32 = 0; let mut indirect: u32 = 0;
self.fs.device.read_block( self.fs.device.read_block(
@ -297,38 +309,18 @@ impl INodeImpl {
} }
} }
disk_inode.blocks = blocks; disk_inode.blocks = blocks;
disk_inode.size = len as u32;
} }
} }
self._set_size(len);
Ok(()) Ok(())
} }
/// Get the actual size of this inode,
/// since size in inode for dir is not real size
fn _size(&self) -> usize {
let disk_inode = self.disk_inode.read();
match disk_inode.type_ {
FileType::Dir => disk_inode.blocks as usize * BLKSIZE,
FileType::File | FileType::SymLink => disk_inode.size as usize,
_ => panic!("Unknown file type"),
}
}
/// Set the ucore compat size of this inode,
/// Size in inode for dir is size of entries
fn _set_size(&self, len: usize) {
let mut disk_inode = self.disk_inode.write();
disk_inode.size = match disk_inode.type_ {
FileType::Dir => disk_inode.blocks as usize * DIRENT_SIZE,
FileType::File | FileType::SymLink => len,
_ => panic!("Unknown file type"),
} as u32
}
// Note: the _\w*_at method always return begin>size?0:begin<end?0:(min(size,end)-begin) when success // Note: the _\w*_at method always return begin>size?0:begin<end?0:(min(size,end)-begin) when success
/// Read/Write content, no matter what type it is /// Read/Write content, no matter what type it is
fn _io_at<F>(&self, begin: usize, end: usize, mut f: F) -> vfs::Result<usize> fn _io_at<F>(&self, begin: usize, end: usize, mut f: F) -> vfs::Result<usize>
where where
F: FnMut(&Arc<Device>, &BlockRange, usize) -> vfs::Result<()>, F: FnMut(&Arc<Device>, &BlockRange, usize) -> vfs::Result<()>,
{ {
let size = self._size(); let size = self.disk_inode.read().size as usize;
let iter = BlockIter { let iter = BlockIter {
begin: size.min(begin), begin: size.min(begin),
end: size.min(end), end: size.min(end),
@ -402,7 +394,7 @@ impl vfs::INode for INodeImpl {
Ok(vfs::PollStatus { Ok(vfs::PollStatus {
read: true, read: true,
write: true, write: true,
error: false error: false,
}) })
} }
/// the size returned here is logical size(entry num for directory), not the disk space used. /// the size returned here is logical size(entry num for directory), not the disk space used.
@ -411,11 +403,7 @@ impl vfs::INode for INodeImpl {
Ok(vfs::Metadata { Ok(vfs::Metadata {
dev: 0, dev: 0,
inode: self.id, inode: self.id,
size: match disk_inode.type_ { size: disk_inode.size as usize,
FileType::File | FileType::SymLink => disk_inode.size as usize,
FileType::Dir => disk_inode.blocks as usize,
_ => panic!("Unknown file type"),
},
mode: 0o777, mode: 0o777,
type_: vfs::FileType::from(disk_inode.type_.clone()), type_: vfs::FileType::from(disk_inode.type_.clone()),
blocks: disk_inode.blocks as usize, blocks: disk_inode.blocks as usize,
@ -476,13 +464,10 @@ impl vfs::INode for INodeImpl {
}; };
// Write new entry // Write new entry
let entry = DiskEntry { self.append_direntry(&DiskEntry {
id: inode.id as u32, id: inode.id as u32,
name: Str256::from(name), name: Str256::from(name),
}; })?;
let old_size = self._size();
self._resize(old_size + BLKSIZE)?;
self._write_at(old_size, entry.as_buf()).unwrap();
inode.nlinks_inc(); inode.nlinks_inc();
if type_ == vfs::FileType::Dir { if type_ == vfs::FileType::Dir {
inode.nlinks_inc(); //for . inode.nlinks_inc(); //for .
@ -511,13 +496,10 @@ impl vfs::INode for INodeImpl {
if child.metadata()?.type_ == vfs::FileType::Dir { if child.metadata()?.type_ == vfs::FileType::Dir {
return Err(FsError::IsDir); return Err(FsError::IsDir);
} }
let entry = DiskEntry { self.append_direntry(&DiskEntry {
id: child.id as u32, id: child.id as u32,
name: Str256::from(name), name: Str256::from(name),
}; })?;
let old_size = self._size();
self._resize(old_size + BLKSIZE)?;
self._write_at(old_size, entry.as_buf()).unwrap();
child.nlinks_inc(); child.nlinks_inc();
Ok(()) Ok(())
} }
@ -544,8 +526,7 @@ impl vfs::INode for INodeImpl {
let type_ = inode.disk_inode.read().type_; let type_ = inode.disk_inode.read().type_;
if type_ == FileType::Dir { if type_ == FileType::Dir {
// only . and .. // only . and ..
assert!(inode.disk_inode.read().blocks >= 2); if inode.disk_inode.read().size as usize / DIRENT_SIZE > 2 {
if inode.disk_inode.read().blocks > 2 {
return Err(FsError::DirNotEmpty); return Err(FsError::DirNotEmpty);
} }
} }
@ -554,7 +535,7 @@ impl vfs::INode for INodeImpl {
inode.nlinks_dec(); //for . inode.nlinks_dec(); //for .
self.nlinks_dec(); //for .. self.nlinks_dec(); //for ..
} }
self.remove_dirent_page(entry_id)?; self.remove_direntry(entry_id)?;
Ok(()) Ok(())
} }
@ -595,31 +576,27 @@ impl vfs::INode for INodeImpl {
.ok_or(FsError::EntryNotFound)?; .ok_or(FsError::EntryNotFound)?;
if info.inode == dest_info.inode { if info.inode == dest_info.inode {
// rename: in place modify name // rename: in place modify name
let mut entry: DiskEntry = unsafe { uninitialized() }; self.write_direntry(
let entry_pos = entry_id as usize * BLKSIZE; entry_id,
self._read_at(entry_pos, entry.as_buf_mut()).unwrap(); &DiskEntry {
entry.name = Str256::from(new_name); id: inode_id as u32,
self._write_at(entry_pos, entry.as_buf()).unwrap(); name: Str256::from(new_name),
},
)?;
} else { } else {
// move // move
let inode = self.fs.get_inode(inode_id); dest.append_direntry(&DiskEntry {
let entry = DiskEntry {
id: inode_id as u32, id: inode_id as u32,
name: Str256::from(new_name), name: Str256::from(new_name),
}; })?;
let old_size = dest._size(); self.remove_direntry(entry_id)?;
dest._resize(old_size + BLKSIZE)?;
dest._write_at(old_size, entry.as_buf()).unwrap();
self.remove_dirent_page(entry_id)?;
let inode = self.fs.get_inode(inode_id);
if inode.metadata()?.type_ == vfs::FileType::Dir { if inode.metadata()?.type_ == vfs::FileType::Dir {
self.nlinks_dec(); self.nlinks_dec();
dest.nlinks_inc(); dest.nlinks_inc();
} }
} }
Ok(()) Ok(())
} }
fn find(&self, name: &str) -> vfs::Result<Arc<vfs::INode>> { fn find(&self, name: &str) -> vfs::Result<Arc<vfs::INode>> {
@ -634,12 +611,10 @@ impl vfs::INode for INodeImpl {
if self.disk_inode.read().type_ != FileType::Dir { if self.disk_inode.read().type_ != FileType::Dir {
return Err(FsError::NotDir); return Err(FsError::NotDir);
} }
if id >= self.disk_inode.read().blocks as usize { if id >= self.disk_inode.read().size as usize / DIRENT_SIZE {
return Err(FsError::EntryNotFound); return Err(FsError::EntryNotFound);
}; };
let mut entry: DiskEntry = unsafe { uninitialized() }; let entry = self.read_direntry(id)?;
self._read_at(id as usize * BLKSIZE, entry.as_buf_mut())
.unwrap();
Ok(String::from(entry.name.as_ref())) Ok(String::from(entry.name.as_ref()))
} }
fn io_control(&self, _cmd: u32, _data: usize) -> vfs::Result<()> { fn io_control(&self, _cmd: u32, _data: usize) -> vfs::Result<()> {
@ -688,13 +663,17 @@ pub struct SimpleFileSystem {
impl SimpleFileSystem { impl SimpleFileSystem {
/// Load SFS from device /// Load SFS from device
pub fn open(device: Arc<Device>) -> vfs::Result<Arc<Self>> { pub fn open(device: Arc<Device>) -> vfs::Result<Arc<Self>> {
let super_block = device.load_struct::<SuperBlock>(BLKN_SUPER).unwrap(); let super_block = device.load_struct::<SuperBlock>(BLKN_SUPER)?;
if !super_block.check() { if !super_block.check() {
return Err(FsError::WrongFs); return Err(FsError::WrongFs);
} }
let mut freemap_disk = vec![0u8; BLKSIZE * super_block.freemap_blocks as usize]; let mut freemap_disk = vec![0u8; BLKSIZE * super_block.freemap_blocks as usize];
for i in 0..super_block.freemap_blocks as usize { for i in 0..super_block.freemap_blocks as usize {
device.read_block(BLKN_FREEMAP + i, 0, &mut freemap_disk[i * BLKSIZE..(i+1) *BLKSIZE])?; device.read_block(
BLKN_FREEMAP + i,
0,
&mut freemap_disk[i * BLKSIZE..(i + 1) * BLKSIZE],
)?;
} }
Ok(SimpleFileSystem { Ok(SimpleFileSystem {
@ -707,7 +686,7 @@ impl SimpleFileSystem {
.wrap()) .wrap())
} }
/// Create a new SFS on blank disk /// Create a new SFS on blank disk
pub fn create(device: Arc<Device>, space: usize) -> Arc<Self> { pub fn create(device: Arc<Device>, space: usize) -> vfs::Result<Arc<Self>> {
let blocks = (space + BLKSIZE - 1) / BLKSIZE; let blocks = (space + BLKSIZE - 1) / BLKSIZE;
let freemap_blocks = (space + BLKBITS * BLKSIZE - 1) / BLKBITS / BLKSIZE; let freemap_blocks = (space + BLKBITS * BLKSIZE - 1) / BLKBITS / BLKSIZE;
assert!(blocks >= 16, "space too small"); assert!(blocks >= 16, "space too small");
@ -739,12 +718,12 @@ impl SimpleFileSystem {
// Init root INode // Init root INode
let root = sfs._new_inode(BLKN_ROOT, Dirty::new_dirty(DiskINode::new_dir())); let root = sfs._new_inode(BLKN_ROOT, Dirty::new_dirty(DiskINode::new_dir()));
root.init_dir_entry(BLKN_ROOT).unwrap(); root.init_direntry(BLKN_ROOT)?;
root.nlinks_inc(); //for . root.nlinks_inc(); //for .
root.nlinks_inc(); //for ..(root's parent is itself) root.nlinks_inc(); //for ..(root's parent is itself)
root.sync_all().unwrap(); root.sync_all()?;
sfs Ok(sfs)
} }
/// Wrap pure SimpleFileSystem with Arc /// Wrap pure SimpleFileSystem with Arc
/// Used in constructors /// Used in constructors
@ -830,7 +809,7 @@ impl SimpleFileSystem {
let id = self.alloc_block().ok_or(FsError::NoDeviceSpace)?; let id = self.alloc_block().ok_or(FsError::NoDeviceSpace)?;
let disk_inode = Dirty::new_dirty(DiskINode::new_dir()); let disk_inode = Dirty::new_dirty(DiskINode::new_dir());
let inode = self._new_inode(id, disk_inode); let inode = self._new_inode(id, disk_inode);
inode.init_dir_entry(parent)?; inode.init_direntry(parent)?;
Ok(inode) Ok(inode)
} }
fn flush_weak_inodes(&self) { fn flush_weak_inodes(&self) {
@ -852,17 +831,17 @@ impl vfs::FileSystem for SimpleFileSystem {
let mut super_block = self.super_block.write(); let mut super_block = self.super_block.write();
if super_block.dirty() { if super_block.dirty() {
self.device self.device
.write_at(BLKSIZE * BLKN_SUPER, super_block.as_buf()) .write_at(BLKSIZE * BLKN_SUPER, super_block.as_buf())?;
.unwrap();
super_block.sync(); super_block.sync();
} }
let mut free_map = self.free_map.write(); let mut free_map = self.free_map.write();
if free_map.dirty() { if free_map.dirty() {
let data = free_map.as_buf(); let data = free_map.as_buf();
for i in 0..super_block.freemap_blocks as usize { for i in 0..super_block.freemap_blocks as usize {
self.device self.device.write_at(
.write_at(BLKSIZE * (BLKN_FREEMAP + i), &data[i * BLKSIZE..(i+1) * BLKSIZE]) BLKSIZE * (BLKN_FREEMAP + i),
.unwrap(); &data[i * BLKSIZE..(i + 1) * BLKSIZE],
)?;
} }
free_map.sync(); free_map.sync();
} }
@ -872,6 +851,7 @@ impl vfs::FileSystem for SimpleFileSystem {
inode.sync_all()?; inode.sync_all()?;
} }
} }
self.device.sync()?;
Ok(()) Ok(())
} }

@ -175,7 +175,7 @@ pub type BlockId = usize;
pub type INodeId = BlockId; pub type INodeId = BlockId;
/// magic number for sfs /// magic number for sfs
pub const MAGIC: u32 = 0x2f8dbe2a; pub const MAGIC: u32 = 0x2f8dbe2b;
/// size of block /// size of block
pub const BLKSIZE: usize = 1usize << BLKSIZE_LOG2; pub const BLKSIZE: usize = 1usize << BLKSIZE_LOG2;
/// log2( size of block ) /// log2( size of block )
@ -204,7 +204,7 @@ pub const ENTRY_SIZE: usize = 4;
/// number of entries in a block /// number of entries in a block
pub const BLK_NENTRY: usize = BLKSIZE / ENTRY_SIZE; pub const BLK_NENTRY: usize = BLKSIZE / ENTRY_SIZE;
/// size of a dirent used in the size field /// size of a dirent used in the size field
pub const DIRENT_SIZE: usize = MAX_FNAME_LEN + 1; pub const DIRENT_SIZE: usize = MAX_FNAME_LEN + 1 + ENTRY_SIZE;
/// max number of blocks with direct blocks /// max number of blocks with direct blocks
pub const MAX_NBLOCK_DIRECT: usize = NDIRECT; pub const MAX_NBLOCK_DIRECT: usize = NDIRECT;
/// max number of blocks with indirect blocks /// max number of blocks with indirect blocks

@ -20,6 +20,7 @@ fn _open_sample_file() -> Arc<SimpleFileSystem> {
fn _create_new_sfs() -> Arc<SimpleFileSystem> { fn _create_new_sfs() -> Arc<SimpleFileSystem> {
let file = tempfile::tempfile().expect("failed to create file"); let file = tempfile::tempfile().expect("failed to create file");
SimpleFileSystem::create(Arc::new(Mutex::new(file)), 32 * 4096 * 4096) SimpleFileSystem::create(Arc::new(Mutex::new(file)), 32 * 4096 * 4096)
.expect("failed to create SFS")
} }
#[test] #[test]
@ -43,7 +44,7 @@ fn create_file() -> Result<()> {
assert_eq!( assert_eq!(
file1.metadata()?, file1.metadata()?,
Metadata { Metadata {
inode: 8, inode: 7,
size: 0, size: 0,
type_: FileType::File, type_: FileType::File,
mode: 0o777, mode: 0o777,
@ -165,11 +166,26 @@ fn create_then_lookup() -> Result<()> {
"failed to find dir1/file2 by weird relative" "failed to find dir1/file2 by weird relative"
); );
assert!(root.lookup("./dir1/../file2").is_err(), "found non-existent file"); assert!(
assert!(root.lookup("./dir1/../file3").is_err(), "found non-existent file"); root.lookup("./dir1/../file2").is_err(),
assert!(root.lookup("/dir1/../dir1/../file3").is_err(), "found non-existent file"); "found non-existent file"
assert!(root.lookup("/dir1/../../../dir1/../file3").is_err(), "found non-existent file"); );
assert!(root.lookup("/").unwrap().lookup("dir1/../file2").is_err(), "found non-existent file"); assert!(
root.lookup("./dir1/../file3").is_err(),
"found non-existent file"
);
assert!(
root.lookup("/dir1/../dir1/../file3").is_err(),
"found non-existent file"
);
assert!(
root.lookup("/dir1/../../../dir1/../file3").is_err(),
"found non-existent file"
);
assert!(
root.lookup("/").unwrap().lookup("dir1/../file2").is_err(),
"found non-existent file"
);
sfs.sync()?; sfs.sync()?;
Ok(()) Ok(())

@ -44,7 +44,7 @@ impl TimeProvider for StdTimeProvider {
} }
impl From<Error> for DevError { impl From<Error> for DevError {
fn from(e: Error) -> Self { fn from(_: Error) -> Self {
DevError DevError
} }
} }

@ -3,6 +3,7 @@ use core::any::Any;
use core::fmt; use core::fmt;
use core::result; use core::result;
use core::str; use core::str;
use crate::dev::DevError;
/// Abstract file system object such as file or directory. /// Abstract file system object such as file or directory.
pub trait INode: Any + Sync + Send { pub trait INode: Any + Sync + Send {
@ -248,6 +249,12 @@ impl fmt::Display for FsError {
} }
} }
impl From<DevError> for FsError {
fn from(_: DevError) -> Self {
FsError::DeviceError
}
}
#[cfg(any(test, feature = "std"))] #[cfg(any(test, feature = "std"))]
impl std::error::Error for FsError {} impl std::error::Error for FsError {}

Loading…
Cancel
Save