|
|
@ -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(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|