We need BlockCache.
This commit is contained in:
parent
ed9ca7f62d
commit
00eaa64e7d
7 changed files with 428 additions and 33 deletions
|
@ -4,6 +4,7 @@ extern crate alloc;
|
|||
use easy_fs::{
|
||||
BlockDevice,
|
||||
EasyFileSystem,
|
||||
Inode,
|
||||
};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write, Seek, SeekFrom};
|
||||
|
@ -16,6 +17,7 @@ struct BlockFile(Mutex<File>);
|
|||
|
||||
impl BlockDevice for BlockFile {
|
||||
fn read_block(&self, block_id: usize, buf: &mut [u8]) {
|
||||
println!("reading block {}", block_id);
|
||||
let mut file = self.0.lock().unwrap();
|
||||
file.seek(SeekFrom::Start((block_id * BLOCK_SZ) as u64))
|
||||
.expect("Error when seeking!");
|
||||
|
@ -23,6 +25,7 @@ impl BlockDevice for BlockFile {
|
|||
}
|
||||
|
||||
fn write_block(&self, block_id: usize, buf: &[u8]) {
|
||||
println!("writing block {}", block_id);
|
||||
let mut file = self.0.lock().unwrap();
|
||||
file.seek(SeekFrom::Start((block_id * BLOCK_SZ) as u64))
|
||||
.expect("Error when seeking!");
|
||||
|
@ -35,19 +38,23 @@ fn main() {
|
|||
}
|
||||
|
||||
fn easy_fs_pack() -> std::io::Result<()> {
|
||||
let block_file = BlockFile(Mutex::new(
|
||||
let block_file = Arc::new(BlockFile(Mutex::new(
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open("target/fs.img")?
|
||||
));
|
||||
/*
|
||||
let _efs = EasyFileSystem::create(
|
||||
Arc::new(block_file),
|
||||
)));
|
||||
EasyFileSystem::create(
|
||||
block_file.clone(),
|
||||
4096,
|
||||
1,
|
||||
);
|
||||
*/
|
||||
let _efs = EasyFileSystem::open(Arc::new(block_file));
|
||||
let efs = EasyFileSystem::open(block_file.clone());
|
||||
let mut root_inode = EasyFileSystem::root_inode(&efs);
|
||||
root_inode.create("filea");
|
||||
root_inode.create("fileb");
|
||||
for name in root_inode.ls() {
|
||||
println!("name");
|
||||
}
|
||||
Ok(())
|
||||
}
|
|
@ -7,6 +7,7 @@ pub struct Dirty<T> {
|
|||
block_id: usize,
|
||||
block_cache: [u8; BLOCK_SZ],
|
||||
offset: usize,
|
||||
dirty: bool,
|
||||
block_device: Arc<dyn BlockDevice>,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
@ -21,29 +22,37 @@ impl<T> Dirty<T> where T: Sized {
|
|||
cache
|
||||
},
|
||||
offset,
|
||||
dirty: false,
|
||||
block_device,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
self.dirty = true;
|
||||
let type_size = core::mem::size_of::<T>();
|
||||
// assert that the struct is inside a block
|
||||
assert!(self.offset + type_size <= BLOCK_SZ);
|
||||
let start_addr = &self.block_cache[self.offset] as *const _ as usize;
|
||||
unsafe { &mut *(start_addr as *mut T) }
|
||||
}
|
||||
pub fn read(&self) -> &T {
|
||||
pub fn get_ref(&self) -> &T {
|
||||
let type_size = core::mem::size_of::<T>();
|
||||
// assert that the struct is inside a block
|
||||
assert!(self.offset + type_size <= BLOCK_SZ);
|
||||
let start_addr = &self.block_cache[self.offset] as *const _ as usize;
|
||||
unsafe { &*(start_addr as *const T) }
|
||||
}
|
||||
pub fn modify(&mut self, f: impl Fn(&mut T)) {
|
||||
pub fn read<V>(&self, f: impl FnOnce(&T) -> V) -> V {
|
||||
f(self.get_ref())
|
||||
}
|
||||
pub fn modify(&mut self, f: impl FnOnce(&mut T)) {
|
||||
f(self.get_mut());
|
||||
}
|
||||
pub fn write_back(&mut self) {
|
||||
self.block_device.write_block(self.block_id as usize, &self.block_cache);
|
||||
if self.dirty {
|
||||
self.block_device
|
||||
.write_block(self.block_id as usize, &self.block_cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use alloc::sync::Arc;
|
||||
use spin::Mutex;
|
||||
use super::{
|
||||
BlockDevice,
|
||||
Bitmap,
|
||||
|
@ -6,6 +7,7 @@ use super::{
|
|||
DiskInode,
|
||||
DiskInodeType,
|
||||
Dirty,
|
||||
Inode,
|
||||
};
|
||||
use crate::BLOCK_SZ;
|
||||
|
||||
|
@ -24,7 +26,7 @@ impl EasyFileSystem {
|
|||
block_device: Arc<dyn BlockDevice>,
|
||||
total_blocks: u32,
|
||||
inode_bitmap_blocks: u32,
|
||||
) -> Self {
|
||||
) -> Arc<Mutex<Self>> {
|
||||
// calculate block size of areas & create bitmaps
|
||||
let inode_bitmap = Bitmap::new(1, inode_bitmap_blocks as usize);
|
||||
let inode_num = inode_bitmap.maximum();
|
||||
|
@ -38,7 +40,7 @@ impl EasyFileSystem {
|
|||
(1 + inode_bitmap_blocks + inode_area_blocks) as usize,
|
||||
data_bitmap_blocks as usize,
|
||||
);
|
||||
let efs = Self {
|
||||
let mut efs = Self {
|
||||
block_device,
|
||||
inode_bitmap,
|
||||
data_bitmap,
|
||||
|
@ -65,17 +67,20 @@ impl EasyFileSystem {
|
|||
});
|
||||
// write back immediately
|
||||
// create a inode for root node "/"
|
||||
assert_eq!(efs.inode_bitmap.alloc(&efs.block_device).unwrap(), 0);
|
||||
assert_eq!(efs.alloc_inode(), 0);
|
||||
efs.get_disk_inode(0).modify(|disk_inode| {
|
||||
disk_inode.initialize(DiskInodeType::Directory);
|
||||
disk_inode.initialize(
|
||||
DiskInodeType::Directory,
|
||||
efs.alloc_data(),
|
||||
);
|
||||
});
|
||||
efs
|
||||
Arc::new(Mutex::new(efs))
|
||||
}
|
||||
|
||||
pub fn open(block_device: Arc<dyn BlockDevice>) -> Self {
|
||||
pub fn open(block_device: Arc<dyn BlockDevice>) -> Arc<Mutex<Self>> {
|
||||
// read SuperBlock
|
||||
let super_block_dirty: Dirty<SuperBlock> = Dirty::new(0, 0, block_device.clone());
|
||||
let super_block = super_block_dirty.read();
|
||||
let super_block = super_block_dirty.get_ref();
|
||||
assert!(super_block.is_valid(), "Error loading EFS!");
|
||||
println!("{:?}", super_block);
|
||||
let inode_total_blocks =
|
||||
|
@ -93,14 +98,22 @@ impl EasyFileSystem {
|
|||
inode_area_start_block: 1 + super_block.inode_bitmap_blocks,
|
||||
data_area_start_block: 1 + inode_total_blocks + super_block.data_bitmap_blocks,
|
||||
};
|
||||
efs
|
||||
Arc::new(Mutex::new(efs))
|
||||
}
|
||||
|
||||
pub fn root_inode(efs: &Arc<Mutex<Self>>) -> Inode {
|
||||
Inode::new(
|
||||
0,
|
||||
efs.clone(),
|
||||
efs.lock().block_device.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_super_block(&self) -> Dirty<SuperBlock> {
|
||||
Dirty::new(0, 0, self.block_device.clone())
|
||||
}
|
||||
|
||||
fn get_disk_inode(&self, inode_id: u32) -> Dirty<DiskInode> {
|
||||
pub fn get_disk_inode(&self, inode_id: u32) -> Dirty<DiskInode> {
|
||||
let inode_size = core::mem::size_of::<DiskInode>();
|
||||
let inodes_per_block = (BLOCK_SZ / inode_size) as u32;
|
||||
let block_id = self.inode_area_start_block + inode_id / inodes_per_block;
|
||||
|
@ -111,12 +124,8 @@ impl EasyFileSystem {
|
|||
)
|
||||
}
|
||||
|
||||
fn get_data_block(&self, data_block_id: u32) -> Dirty<DataBlock> {
|
||||
Dirty::new(
|
||||
(self.data_area_start_block + data_block_id) as usize,
|
||||
0,
|
||||
self.block_device.clone(),
|
||||
)
|
||||
pub fn get_data_block(&self, data_block_id: u32) -> Dirty<DataBlock> {
|
||||
self.get_block(self.data_area_start_block + data_block_id)
|
||||
}
|
||||
|
||||
fn get_block(&self, block_id: u32) -> Dirty<DataBlock> {
|
||||
|
@ -127,4 +136,20 @@ impl EasyFileSystem {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn alloc_inode(&mut self) -> u32 {
|
||||
self.inode_bitmap.alloc(&self.block_device).unwrap() as u32
|
||||
}
|
||||
|
||||
/// Return a block ID not ID in the data area.
|
||||
pub fn alloc_data(&mut self) -> u32 {
|
||||
self.data_bitmap.alloc(&self.block_device).unwrap() as u32 + self.data_area_start_block
|
||||
}
|
||||
|
||||
fn dealloc_data(&mut self, block_id: u32) {
|
||||
self.data_bitmap.dealloc(
|
||||
&self.block_device,
|
||||
(block_id - self.data_area_start_block) as usize
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,11 @@
|
|||
use core::fmt::{Debug, Formatter, Result};
|
||||
use super::{
|
||||
BLOCK_SZ,
|
||||
BlockDevice,
|
||||
Dirty,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
const EFS_MAGIC: u32 = 0x3b800001;
|
||||
const INODE_DIRECT_COUNT: usize = 12;
|
||||
|
@ -49,32 +56,224 @@ impl SuperBlock {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum DiskInodeType {
|
||||
File,
|
||||
Directory,
|
||||
}
|
||||
|
||||
type IndirectBlock = [u32; BLOCK_SZ / 4];
|
||||
type DataBlock = [u8; BLOCK_SZ];
|
||||
|
||||
#[repr(C)]
|
||||
/// Only support level-1 indirect now, **indirect2** field is always 0.
|
||||
pub struct DiskInode {
|
||||
size: u32,
|
||||
direct: [u32; INODE_DIRECT_COUNT],
|
||||
indirect1: u32,
|
||||
indirect2: u32,
|
||||
pub size: u32,
|
||||
pub direct: [u32; INODE_DIRECT_COUNT],
|
||||
pub indirect1: u32,
|
||||
pub indirect2: u32,
|
||||
type_: DiskInodeType,
|
||||
}
|
||||
|
||||
impl DiskInode {
|
||||
pub fn initialize(&mut self, type_: DiskInodeType) {
|
||||
/// indirect1 block is allocated when the file is created.
|
||||
pub fn initialize(&mut self, type_: DiskInodeType, indirect1: u32) {
|
||||
self.size = 0;
|
||||
self.direct.iter_mut().for_each(|v| *v = 0);
|
||||
self.indirect1 = 0;
|
||||
self.indirect1 = indirect1;
|
||||
self.indirect2 = 0;
|
||||
self.type_ = type_;
|
||||
}
|
||||
pub fn is_dir(&self) -> bool {
|
||||
self.type_ == DiskInodeType::Directory
|
||||
}
|
||||
pub fn is_file(&self) -> bool {
|
||||
self.type_ == DiskInodeType::File
|
||||
}
|
||||
pub fn blocks(&self) -> u32 {
|
||||
Self::_blocks(self.size)
|
||||
}
|
||||
fn _blocks(size: u32) -> u32 {
|
||||
(size + BLOCK_SZ as u32 - 1) / BLOCK_SZ as u32
|
||||
}
|
||||
pub fn get_block_id(&self, inner_id: u32, block_device: &Arc<dyn BlockDevice>) -> u32 {
|
||||
let inner_id = inner_id as usize;
|
||||
if inner_id < INODE_DIRECT_COUNT {
|
||||
self.direct[inner_id]
|
||||
} else {
|
||||
// only support indirect1 now
|
||||
Dirty::<IndirectBlock>::new(
|
||||
self.indirect1 as usize,
|
||||
0,
|
||||
block_device.clone()
|
||||
).read(|indirect_block| {
|
||||
// it will panic if file is too large
|
||||
indirect_block[inner_id - INODE_DIRECT_COUNT]
|
||||
})
|
||||
}
|
||||
}
|
||||
pub fn blocks_num_needed(&self, new_size: u32) -> u32 {
|
||||
assert!(new_size >= self.size);
|
||||
Self::_blocks(new_size) - self.blocks()
|
||||
}
|
||||
pub fn increase_size(
|
||||
&mut self,
|
||||
new_size: u32,
|
||||
new_blocks: Vec<u32>,
|
||||
block_device: &Arc<dyn BlockDevice>,
|
||||
) {
|
||||
println!("increase_size new_size={}, new_blocks={:?}", new_size, new_blocks);
|
||||
assert_eq!(new_blocks.len() as u32, self.blocks_num_needed(new_size));
|
||||
let last_blocks = self.blocks();
|
||||
self.size = new_size;
|
||||
let current_blocks = self.blocks();
|
||||
Dirty::<IndirectBlock>::new(
|
||||
self.indirect1 as usize,
|
||||
0,
|
||||
block_device.clone()
|
||||
).modify(|indirect_block| {
|
||||
for i in 0..current_blocks - last_blocks {
|
||||
let inner_id = (last_blocks + i) as usize;
|
||||
let new_block = new_blocks[i as usize];
|
||||
if inner_id < INODE_DIRECT_COUNT {
|
||||
self.direct[inner_id] = new_block;
|
||||
} else {
|
||||
indirect_block[inner_id - INODE_DIRECT_COUNT] = new_block;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/// Clear size to zero and return blocks that should be deallocated.
|
||||
pub fn clear_size(&mut self, block_device: &Arc<dyn BlockDevice>) -> Vec<u32> {
|
||||
let mut v: Vec<u32> = Vec::new();
|
||||
let blocks = self.blocks() as usize;
|
||||
self.size = 0;
|
||||
for i in 0..blocks.min(INODE_DIRECT_COUNT) {
|
||||
v.push(self.direct[i]);
|
||||
self.direct[i] = 0;
|
||||
}
|
||||
if blocks > INODE_DIRECT_COUNT {
|
||||
Dirty::<IndirectBlock>::new(
|
||||
self.indirect1 as usize,
|
||||
0,
|
||||
block_device.clone(),
|
||||
).modify(|indirect_block| {
|
||||
for i in 0..blocks - INODE_DIRECT_COUNT {
|
||||
v.push(indirect_block[i]);
|
||||
indirect_block[i] = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
v
|
||||
}
|
||||
pub fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
buf: &mut [u8],
|
||||
block_device: &Arc<dyn BlockDevice>,
|
||||
) -> usize {
|
||||
let mut start = offset;
|
||||
let end = (offset + buf.len()).min(self.size as usize);
|
||||
if start >= end {
|
||||
return 0;
|
||||
}
|
||||
let mut start_block = start / BLOCK_SZ;
|
||||
let mut read_size = 0usize;
|
||||
loop {
|
||||
// calculate end of current block
|
||||
let mut end_current_block = (start / BLOCK_SZ + 1) * BLOCK_SZ;
|
||||
end_current_block = end_current_block.min(end);
|
||||
// read and update read size
|
||||
let block_read_size = end_current_block - start;
|
||||
let dst = &mut buf[read_size..read_size + block_read_size];
|
||||
Dirty::<DataBlock>::new(
|
||||
self.get_block_id(start_block as u32, block_device) as usize,
|
||||
0,
|
||||
block_device.clone()
|
||||
).read(|data_block| {
|
||||
let src = &data_block[start % BLOCK_SZ..start % BLOCK_SZ + block_read_size];
|
||||
dst.copy_from_slice(src);
|
||||
});
|
||||
read_size += block_read_size;
|
||||
// move to next block
|
||||
if end_current_block == end { break; }
|
||||
start_block += 1;
|
||||
start = end_current_block;
|
||||
}
|
||||
read_size
|
||||
}
|
||||
/// File size must be adjusted before.
|
||||
pub fn write_at(
|
||||
&mut self,
|
||||
offset: usize,
|
||||
buf: &[u8],
|
||||
block_device: &Arc<dyn BlockDevice>,
|
||||
) -> usize {
|
||||
let mut start = offset;
|
||||
let end = (offset + buf.len()).min(self.size as usize);
|
||||
assert!(start <= end);
|
||||
let mut start_block = start / BLOCK_SZ;
|
||||
let mut write_size = 0usize;
|
||||
loop {
|
||||
// calculate end of current block
|
||||
let mut end_current_block = (start / BLOCK_SZ + 1) * BLOCK_SZ;
|
||||
end_current_block = end_current_block.min(end);
|
||||
// write and update write size
|
||||
let block_write_size = end_current_block - start;
|
||||
Dirty::<DataBlock>::new(
|
||||
self.get_block_id(start_block as u32, block_device) as usize,
|
||||
0,
|
||||
block_device.clone()
|
||||
).modify(|data_block| {
|
||||
let src = &buf[write_size..write_size + block_write_size];
|
||||
let dst = &mut data_block[start % BLOCK_SZ..start % BLOCK_SZ + block_write_size];
|
||||
dst.copy_from_slice(src);
|
||||
});
|
||||
write_size += block_write_size;
|
||||
// move to next block
|
||||
if end_current_block == end { break; }
|
||||
start_block += 1;
|
||||
start = end_current_block;
|
||||
}
|
||||
write_size
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct DirEntry {
|
||||
name: [u8; NAME_LENGTH_LIMIT + 1],
|
||||
inode_number: u32,
|
||||
}
|
||||
|
||||
pub const DIRENT_SZ: usize = 32;
|
||||
|
||||
pub type DirentBlock = [DirEntry; BLOCK_SZ / DIRENT_SZ];
|
||||
pub type DirentBytes = [u8; DIRENT_SZ];
|
||||
|
||||
impl DirEntry {
|
||||
pub fn new(name: &str, inode_number: u32) -> Self {
|
||||
let mut bytes = [0u8; NAME_LENGTH_LIMIT + 1];
|
||||
&mut bytes[..name.len()].copy_from_slice(name.as_bytes());
|
||||
Self {
|
||||
name: bytes,
|
||||
inode_number,
|
||||
}
|
||||
}
|
||||
pub fn into_bytes(&self) -> &DirentBytes {
|
||||
unsafe {
|
||||
&*(self as *const Self as usize as *const DirentBytes)
|
||||
}
|
||||
}
|
||||
pub fn from_bytes(bytes: &DirentBytes) -> &Self {
|
||||
unsafe { &*(bytes.as_ptr() as usize as *const Self) }
|
||||
}
|
||||
pub fn from_bytes_mut(bytes: &mut DirentBytes) -> &mut Self {
|
||||
unsafe {
|
||||
&mut *(bytes.as_mut_ptr() as usize as *mut Self)
|
||||
}
|
||||
}
|
||||
pub fn name(&self) -> &str {
|
||||
let len = (0usize..).find(|i| self.name[*i] == 0).unwrap();
|
||||
core::str::from_utf8(&self.name[..len]).unwrap()
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ mod vfs;
|
|||
pub const BLOCK_SZ: usize = 512;
|
||||
pub use block_dev::BlockDevice;
|
||||
pub use efs::EasyFileSystem;
|
||||
pub use vfs::Inode;
|
||||
use layout::*;
|
||||
use dirty::Dirty;
|
||||
use bitmap::Bitmap;
|
|
@ -1,3 +1,156 @@
|
|||
pub struct Inode {
|
||||
use super::{
|
||||
BlockDevice,
|
||||
Dirty,
|
||||
DiskInode,
|
||||
DiskInodeType,
|
||||
DirEntry,
|
||||
DirentBytes,
|
||||
EasyFileSystem,
|
||||
BLOCK_SZ,
|
||||
DIRENT_SZ,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use crate::layout::DiskInodeType::Directory;
|
||||
use spin::{Mutex, MutexGuard};
|
||||
|
||||
}
|
||||
pub struct Inode {
|
||||
inode_id: u32,
|
||||
fs: Arc<Mutex<EasyFileSystem>>,
|
||||
block_device: Arc<dyn BlockDevice>,
|
||||
}
|
||||
|
||||
impl Inode {
|
||||
pub fn new(
|
||||
inode_id: u32,
|
||||
fs: Arc<Mutex<EasyFileSystem>>,
|
||||
block_device: Arc<dyn BlockDevice>,
|
||||
) -> Self {
|
||||
Self {
|
||||
inode_id,
|
||||
fs,
|
||||
block_device,
|
||||
}
|
||||
}
|
||||
fn get_disk_inode(&self) -> Dirty<DiskInode> {
|
||||
self.fs.lock().get_disk_inode(self.inode_id)
|
||||
}
|
||||
|
||||
fn find_inode_id(&self, name: &str) -> Option<u32> {
|
||||
let inode = self.get_disk_inode();
|
||||
// assert it is a directory
|
||||
assert!(inode.read(|inode| inode.is_dir()));
|
||||
let file_count = inode.read(|inode| {
|
||||
inode.size as usize
|
||||
}) / DIRENT_SZ;
|
||||
let mut dirent_space: DirentBytes = Default::default();
|
||||
for i in 0..file_count {
|
||||
assert_eq!(
|
||||
inode.read(|inode| {
|
||||
inode.read_at(
|
||||
DIRENT_SZ * i,
|
||||
&mut dirent_space,
|
||||
&self.block_device,
|
||||
)
|
||||
}),
|
||||
DIRENT_SZ,
|
||||
);
|
||||
if DirEntry::from_bytes(&dirent_space).name() == name {
|
||||
return Some(i as u32);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn increase_size(&self, new_size: u32, fs: &mut MutexGuard<EasyFileSystem>) {
|
||||
let mut inode = fs.get_disk_inode(self.inode_id);
|
||||
let blocks_needed = inode.read(|inode| {
|
||||
inode.blocks_num_needed(new_size)
|
||||
});
|
||||
println!("blocks_num_needed = {}", blocks_needed);
|
||||
let mut v: Vec<u32> = Vec::new();
|
||||
for _ in 0..blocks_needed {
|
||||
v.push(fs.alloc_data());
|
||||
}
|
||||
inode.modify(|inode| {
|
||||
inode.increase_size(new_size, v, &self.block_device);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn create(&mut self, name: &str) -> Option<Arc<Inode>> {
|
||||
println!("creating name {}", name);
|
||||
let mut inode = self.get_disk_inode();
|
||||
// assert it is a directory
|
||||
assert!(inode.read(|inode| inode.is_dir()));
|
||||
// has the file been created?
|
||||
if let Some(_) = self.find_inode_id(name) {
|
||||
return None;
|
||||
}
|
||||
println!("stop1");
|
||||
|
||||
// create a new file
|
||||
// alloc a inode with an indirect block
|
||||
let mut fs = self.fs.lock();
|
||||
let new_inode_id = fs.alloc_inode();
|
||||
let indirect1 = fs.alloc_data();
|
||||
println!("creating new file, new_inode_id={}, indirect={}", new_inode_id, indirect1);
|
||||
// initialize inode
|
||||
fs.get_disk_inode(new_inode_id).modify(|inode| {
|
||||
inode.initialize(
|
||||
DiskInodeType::File,
|
||||
indirect1,
|
||||
)
|
||||
});
|
||||
|
||||
// append file in the dirent
|
||||
let file_count =
|
||||
inode.read(|inode| inode.size as usize) / DIRENT_SZ;
|
||||
let new_size = (file_count + 1) * DIRENT_SZ;
|
||||
println!("expected new_size={}", new_size);
|
||||
// increase size
|
||||
self.increase_size(new_size as u32, &mut fs);
|
||||
// write dirent
|
||||
let dirent = DirEntry::new(name, new_inode_id);
|
||||
inode.modify(|inode| {
|
||||
inode.write_at(
|
||||
file_count * DIRENT_SZ,
|
||||
dirent.into_bytes(),
|
||||
&self.block_device,
|
||||
);
|
||||
});
|
||||
|
||||
// return inode
|
||||
Some(Arc::new(Self::new(
|
||||
new_inode_id,
|
||||
self.fs.clone(),
|
||||
self.block_device.clone(),
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn ls(&self) -> Vec<String> {
|
||||
println!("into ls!");
|
||||
let fs = self.fs.lock();
|
||||
let inode = fs.get_disk_inode(self.inode_id);
|
||||
let file_count = inode.read(|inode| {
|
||||
(inode.size as usize) / DIRENT_SZ
|
||||
});
|
||||
println!("file_count = {}", file_count);
|
||||
let mut v: Vec<String> = Vec::new();
|
||||
for i in 0..file_count {
|
||||
let mut dirent_bytes: DirentBytes = Default::default();
|
||||
assert_eq!(
|
||||
inode.read(|inode| {
|
||||
inode.read_at(
|
||||
i * DIRENT_SZ,
|
||||
&mut dirent_bytes,
|
||||
&self.block_device,
|
||||
)
|
||||
}),
|
||||
DIRENT_SZ,
|
||||
);
|
||||
v.push(String::from(DirEntry::from_bytes(&dirent_bytes).name()));
|
||||
}
|
||||
v
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue