summaryrefslogtreecommitdiff
path: root/src/disk
diff options
context:
space:
mode:
authorChuyan Zhang <me@zcy.moe>2023-10-17 23:07:21 -0700
committerChuyan Zhang <me@zcy.moe>2023-10-17 23:07:21 -0700
commit7a748cadbb2e2ce8c0e045cb8fbd77ccbd47459f (patch)
tree07ed09bb6c55110dd2f2ea59283623f023b11666 /src/disk
downloadmyfs-7a748cadbb2e2ce8c0e045cb8fbd77ccbd47459f.tar.gz
myfs-7a748cadbb2e2ce8c0e045cb8fbd77ccbd47459f.zip
initial commit
Diffstat (limited to 'src/disk')
-rw-r--r--src/disk/bitmap.rs49
-rw-r--r--src/disk/inode.rs152
-rw-r--r--src/disk/mod.rs2
3 files changed, 203 insertions, 0 deletions
diff --git a/src/disk/bitmap.rs b/src/disk/bitmap.rs
new file mode 100644
index 0000000..a5a9cc4
--- /dev/null
+++ b/src/disk/bitmap.rs
@@ -0,0 +1,49 @@
+use crate::block_device::{BlockDevice, BLOCK_SIZE};
+use std::sync::Arc;
+
+pub struct Bitmap {
+ pub starting_block: usize,
+ pub length: usize,
+ pub device: Arc<dyn BlockDevice>,
+ pub data: Vec<u8>,
+ pub dirty_blocks: Vec<usize>,
+}
+
+impl Bitmap {
+ pub fn new(starting_block: usize, length: usize, device: Arc<dyn BlockDevice>) -> Self {
+ Self {
+ starting_block,
+ length,
+ device,
+ data: vec![0u8; length * BLOCK_SIZE],
+ dirty_blocks: Vec::new(),
+ }
+ }
+ pub fn allocate(&mut self) -> usize {
+ for (i, byte) in self.data.iter_mut().enumerate() {
+ let leading_ones = byte.leading_ones();
+ if leading_ones != 8 {
+ *byte |= (1 << (7 - leading_ones)) as u8;
+ self.dirty_blocks.push(i / BLOCK_SIZE);
+ return i * 8 + leading_ones as usize;
+ }
+ }
+ panic!("No more space for allocation!")
+ }
+
+ pub fn query(&self, index: usize) -> bool {
+ self.data[index / 8] & ((1 << (7 - index % 8)) as u8) != 0
+ }
+
+ fn write_back(&mut self) {
+ for block_index_offset in self.dirty_blocks.iter() {
+ let buffer_front_index = BLOCK_SIZE * block_index_offset;
+ let buffer_back_index = BLOCK_SIZE * (block_index_offset + 1);
+ self.device.write(
+ self.starting_block + block_index_offset,
+ &self.data[buffer_front_index..buffer_back_index],
+ );
+ }
+ self.dirty_blocks = Vec::new();
+ }
+}
diff --git a/src/disk/inode.rs b/src/disk/inode.rs
new file mode 100644
index 0000000..f38508a
--- /dev/null
+++ b/src/disk/inode.rs
@@ -0,0 +1,152 @@
+use bitflags::bitflags;
+
+const DIRECT_NUMBER: usize = 15;
+
+#[derive(Debug)]
+pub struct InodeMode(u16);
+
+bitflags! {
+ impl InodeMode: u16 {
+ const IXOTH = 0x0001;
+ const IWOTH = 0x0002;
+ const IROTH = 0x0004;
+ const IXGRP = 0x0008;
+ const IWGRP = 0x0010;
+ const IRGRP = 0x0020;
+ const IXUSR = 0x0040;
+ const IWUSR = 0x0080;
+ const IRUSR = 0x0100;
+ const ISVTX = 0x0200;
+ const ISGID = 0x0400;
+ const ISUID = 0x0800;
+ // These are mutually-exclusive:
+ const IFIFO = 0x1000;
+ const IFCHR = 0x2000;
+ const IFDIR = 0x4000;
+ const IFBLK = 0x6000;
+ const IFREG = 0x8000;
+ const IFLNK = 0xA000;
+ const IFSOCK = 0xC000;
+ }
+}
+
+/// Pretty much the same with ext2, with minor changes:
+/// - removed OS dependent attributes (osd1 & osd2)
+/// - removed i_faddr since fragmentation is not supported
+/// - changed uid and gid from u16 to u32
+/// - added more direct blocks for a total size of 128 bytes
+/// TODO: do we need to extend time precision?
+#[repr(C)]
+#[derive(Debug)]
+pub struct Inode {
+ mode: InodeMode,
+ uid: u32,
+ size: u32,
+ atime: u32, // time in seconds
+ ctime: u32,
+ mtime: u32,
+ dtime: u32,
+ gid: u32,
+ n_links: u16,
+ n_blocks: u32,
+ flags: u32, // TODO: do we actually need this? maybe just return 0
+ direct: [u32; DIRECT_NUMBER],
+ single_indirect: u32,
+ double_indirect: u32,
+ triple_indirect: u32,
+ generation: u32,
+ file_acl: u32,
+ dir_acl: u32, // TODO do we have to implement ACL......?
+}
+
+impl Inode {
+ pub fn directory() -> Self {
+ Self {
+ mode: InodeMode::IFDIR
+ | InodeMode::IRUSR
+ | InodeMode::IWUSR
+ | InodeMode::IXUSR
+ | InodeMode::IRGRP
+ | InodeMode::IXGRP
+ | InodeMode::IROTH
+ | InodeMode::IXOTH,
+ // Directory, 755 permissions
+ uid: 0,
+ size: 0,
+ atime: 0,
+ ctime: 0,
+ mtime: 0,
+ dtime: 0,
+ gid: 0,
+ n_links: 0,
+ n_blocks: 0,
+ flags: 0,
+ direct: [0; DIRECT_NUMBER],
+ single_indirect: 0,
+ double_indirect: 0,
+ triple_indirect: 0,
+ generation: 0,
+ file_acl: 0,
+ dir_acl: 0,
+ }
+ }
+
+ pub fn file() -> Self {
+ Self {
+ mode: InodeMode::IFREG
+ | InodeMode::IRUSR
+ | InodeMode::IWUSR
+ | InodeMode::IXUSR
+ | InodeMode::IRGRP
+ | InodeMode::IXGRP
+ | InodeMode::IROTH
+ | InodeMode::IXOTH,
+ // RegularFile, 755 permissions
+ uid: 0,
+ size: 0,
+ atime: 0,
+ ctime: 0,
+ mtime: 0,
+ dtime: 0,
+ gid: 0,
+ n_links: 0,
+ n_blocks: 0,
+ flags: 0,
+ direct: [0; DIRECT_NUMBER],
+ single_indirect: 0,
+ double_indirect: 0,
+ triple_indirect: 0,
+ generation: 0,
+ file_acl: 0,
+ dir_acl: 0,
+ }
+ }
+}
+
+//
+// #[repr(C)]
+// #[derive(Debug, Default)]
+// pub struct FileInode {
+// file_size: u32,
+// direct_blocks: [u32; DIRECT_NUMBER],
+// indirect_block: u32,
+// doubly_indirect_block: u32,
+// } // sizeof(FileInode) == 124 bytes
+//
+// #[repr(C)]
+// #[derive(Debug, Default)]
+// pub struct DirectoryInode {
+// child_number: u32,
+// direct_blocks: [u32; DIRECT_NUMBER],
+// indirect_block: u32,
+// doubly_indirect_block: u32,
+// } // sizeof(FileInode) == 124 bytes
+//
+// #[repr(C)]
+// #[derive(Debug)]
+// pub enum Inode {
+// File(FileInode),
+// Directory(DirectoryInode),
+// } // sizeof(Inode) == 128 bytes
+
+pub const INODE_SIZE: usize = std::mem::size_of::<Inode>();
diff --git a/src/disk/mod.rs b/src/disk/mod.rs
new file mode 100644
index 0000000..e4e4216
--- /dev/null
+++ b/src/disk/mod.rs
@@ -0,0 +1,2 @@
+pub mod inode;
+pub mod bitmap;