|
@@ -5,17 +5,6 @@ use crate::prelude::*;
|
|
use super::Ext4;
|
|
use super::Ext4;
|
|
|
|
|
|
impl Ext4 {
|
|
impl Ext4 {
|
|
- /// Read super block from block device
|
|
|
|
- #[allow(unused)]
|
|
|
|
- pub(super) fn read_super_block(&self) -> SuperBlock {
|
|
|
|
- SuperBlock::load_from_disk(self.block_device.as_ref())
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// Write super block to block device
|
|
|
|
- pub(super) fn write_super_block(&self, sb: &SuperBlock) {
|
|
|
|
- sb.sync_to_disk(self.block_device.as_ref());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/// Read a block from block device
|
|
/// Read a block from block device
|
|
pub(super) fn read_block(&self, block_id: PBlockId) -> Block {
|
|
pub(super) fn read_block(&self, block_id: PBlockId) -> Block {
|
|
self.block_device.read_block(block_id)
|
|
self.block_device.read_block(block_id)
|
|
@@ -26,14 +15,30 @@ impl Ext4 {
|
|
self.block_device.write_block(block)
|
|
self.block_device.write_block(block)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// Read super block from block device
|
|
|
|
+ #[allow(unused)]
|
|
|
|
+ pub(super) fn read_super_block(&self) -> SuperBlock {
|
|
|
|
+ let block = self.read_block(0);
|
|
|
|
+ block.read_offset_as(BASE_OFFSET)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Write super block to block device
|
|
|
|
+ pub(super) fn write_super_block(&self, sb: &SuperBlock) {
|
|
|
|
+ let mut block = Block::new(0, [0; BLOCK_SIZE]);
|
|
|
|
+ block.write_offset_as(BASE_OFFSET, sb);
|
|
|
|
+ self.block_device.write_block(&block)
|
|
|
|
+ }
|
|
|
|
+
|
|
/// Read an inode from block device, return an `InodeRef` that
|
|
/// Read an inode from block device, return an `InodeRef` that
|
|
/// combines the inode and its id.
|
|
/// combines the inode and its id.
|
|
pub(super) fn read_inode(&self, inode_id: InodeId) -> InodeRef {
|
|
pub(super) fn read_inode(&self, inode_id: InodeId) -> InodeRef {
|
|
- InodeRef::load_from_disk(
|
|
|
|
- self.block_device.as_ref(),
|
|
|
|
- &self.read_super_block(),
|
|
|
|
- inode_id,
|
|
|
|
- )
|
|
|
|
|
|
+ let (block_id, offset) = self.inode_disk_pos(inode_id);
|
|
|
|
+ let block = self.read_block(block_id);
|
|
|
|
+ let inode = InodeRef::new(inode_id, block.read_offset_as(offset));
|
|
|
|
+ if inode.inode.uid() != 0 {
|
|
|
|
+ panic!("Inode {:?} has invalid uid", inode);
|
|
|
|
+ }
|
|
|
|
+ inode
|
|
}
|
|
}
|
|
|
|
|
|
/// Read the root inode from block device
|
|
/// Read the root inode from block device
|
|
@@ -44,32 +49,82 @@ impl Ext4 {
|
|
|
|
|
|
/// Write an inode to block device with checksum
|
|
/// Write an inode to block device with checksum
|
|
pub(super) fn write_inode_with_csum(&self, inode_ref: &mut InodeRef) {
|
|
pub(super) fn write_inode_with_csum(&self, inode_ref: &mut InodeRef) {
|
|
- inode_ref.sync_to_disk_with_csum(self.block_device.as_ref(), &self.read_super_block())
|
|
|
|
|
|
+ let super_block = self.read_super_block();
|
|
|
|
+ inode_ref.set_checksum(&super_block.uuid());
|
|
|
|
+ self.write_inode_without_csum(inode_ref);
|
|
}
|
|
}
|
|
|
|
|
|
/// Write an inode to block device without checksum
|
|
/// Write an inode to block device without checksum
|
|
pub(super) fn write_inode_without_csum(&self, inode_ref: &InodeRef) {
|
|
pub(super) fn write_inode_without_csum(&self, inode_ref: &InodeRef) {
|
|
- inode_ref.sync_to_disk_without_csum(self.block_device.as_ref(), &self.read_super_block())
|
|
|
|
|
|
+ if inode_ref.inode.uid() != 0 {
|
|
|
|
+ panic!();
|
|
|
|
+ }
|
|
|
|
+ let (block_id, offset) = self.inode_disk_pos(inode_ref.id);
|
|
|
|
+ let mut block = self.read_block(block_id);
|
|
|
|
+ block.write_offset_as(offset, &inode_ref.inode);
|
|
|
|
+ self.write_block(&block)
|
|
}
|
|
}
|
|
|
|
|
|
/// Read a block group descriptor from block device, return an `BlockGroupRef`
|
|
/// Read a block group descriptor from block device, return an `BlockGroupRef`
|
|
/// that combines the block group descriptor and its id.
|
|
/// that combines the block group descriptor and its id.
|
|
pub(super) fn read_block_group(&self, block_group_id: BlockGroupId) -> BlockGroupRef {
|
|
pub(super) fn read_block_group(&self, block_group_id: BlockGroupId) -> BlockGroupRef {
|
|
- BlockGroupRef::load_from_disk(
|
|
|
|
- self.block_device.as_ref(),
|
|
|
|
- &self.read_super_block(),
|
|
|
|
|
|
+ let (block_id, offset) = self.block_group_disk_pos(block_group_id);
|
|
|
|
+ let block = self.read_block(block_id as PBlockId);
|
|
|
|
+ BlockGroupRef::new(
|
|
block_group_id,
|
|
block_group_id,
|
|
|
|
+ block.read_offset_as::<BlockGroupDesc>(offset),
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
/// Write a block group descriptor to block device with checksum
|
|
/// Write a block group descriptor to block device with checksum
|
|
pub(super) fn write_block_group_with_csum(&self, bg_ref: &mut BlockGroupRef) {
|
|
pub(super) fn write_block_group_with_csum(&self, bg_ref: &mut BlockGroupRef) {
|
|
- bg_ref.sync_to_disk_with_csum(self.block_device.as_ref(), &self.read_super_block())
|
|
|
|
|
|
+ let super_block = self.read_super_block();
|
|
|
|
+ bg_ref.set_checksum(&super_block.uuid());
|
|
|
|
+ self.write_block_group_without_csum(bg_ref);
|
|
}
|
|
}
|
|
|
|
|
|
/// Write a block group descriptor to block device without checksum
|
|
/// Write a block group descriptor to block device without checksum
|
|
#[allow(unused)]
|
|
#[allow(unused)]
|
|
pub(super) fn write_block_group_without_csum(&self, bg_ref: &BlockGroupRef) {
|
|
pub(super) fn write_block_group_without_csum(&self, bg_ref: &BlockGroupRef) {
|
|
- bg_ref.sync_to_disk_without_csum(self.block_device.as_ref(), &self.read_super_block())
|
|
|
|
|
|
+ let (block_id, offset) = self.block_group_disk_pos(bg_ref.id);
|
|
|
|
+ let mut block = self.read_block(block_id as PBlockId);
|
|
|
|
+ block.write_offset_as(offset, &bg_ref.desc);
|
|
|
|
+ self.write_block(&block);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Get disk position of an inode. Return block id and offset within the block.
|
|
|
|
+ ///
|
|
|
|
+ /// Each block group contains `sb.inodes_per_group` inodes.
|
|
|
|
+ /// Because inode 0 is defined not to exist, this formula can
|
|
|
|
+ /// be used to find the block group that an inode lives in:
|
|
|
|
+ /// `bg = (inode_id - 1) / sb.inodes_per_group`.
|
|
|
|
+ ///
|
|
|
|
+ /// The particular inode can be found within the block group's
|
|
|
|
+ /// inode table at `index = (inode_id - 1) % sb.inodes_per_group`.
|
|
|
|
+ /// To get the byte address within the inode table, use
|
|
|
|
+ /// `offset = index * sb.inode_size`.
|
|
|
|
+ fn inode_disk_pos(&self, inode_id: InodeId) -> (PBlockId, usize) {
|
|
|
|
+ let super_block = self.read_super_block();
|
|
|
|
+ let inodes_per_group = super_block.inodes_per_group();
|
|
|
|
+
|
|
|
|
+ let bg_id = ((inode_id - 1) / inodes_per_group) as BlockGroupId;
|
|
|
|
+ let inode_size = super_block.inode_size() as usize;
|
|
|
|
+ let bg = self.read_block_group(bg_id);
|
|
|
|
+ let id_in_bg = ((inode_id - 1) % inodes_per_group) as usize;
|
|
|
|
+
|
|
|
|
+ let block_id =
|
|
|
|
+ bg.desc.inode_table_first_block() + (id_in_bg * inode_size / BLOCK_SIZE) as PBlockId;
|
|
|
|
+ let offset = (id_in_bg * inode_size) % BLOCK_SIZE;
|
|
|
|
+ (block_id, offset)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Get disk position of a block group. Return block id and offset within the block.
|
|
|
|
+ fn block_group_disk_pos(&self, block_group_id: BlockGroupId) -> (PBlockId, usize) {
|
|
|
|
+ let super_block = self.read_super_block();
|
|
|
|
+ let desc_per_block = BLOCK_SIZE as u32 / super_block.desc_size() as u32;
|
|
|
|
+
|
|
|
|
+ let block_id = super_block.first_data_block() + block_group_id / desc_per_block + 1;
|
|
|
|
+ let offset = (block_group_id % desc_per_block) * super_block.desc_size() as u32;
|
|
|
|
+ (block_id as PBlockId, offset as usize)
|
|
}
|
|
}
|
|
}
|
|
}
|