rw.rs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. use super::Ext4;
  2. use crate::constants::*;
  3. use crate::ext4_defs::*;
  4. use crate::prelude::*;
  5. impl Ext4 {
  6. /// Read a block from block device
  7. pub(super) fn read_block(&self, block_id: PBlockId) -> Block {
  8. #[cfg(feature = "block_cache")]
  9. {
  10. self.block_cache.read_block(block_id)
  11. }
  12. #[cfg(not(feature = "block_cache"))]
  13. {
  14. self.block_device.read_block(block_id)
  15. }
  16. }
  17. /// Write a block to block device
  18. pub(super) fn write_block(&self, block: &Block) {
  19. #[cfg(feature = "block_cache")]
  20. {
  21. self.block_cache.write_block(block)
  22. }
  23. #[cfg(not(feature = "block_cache"))]
  24. {
  25. self.block_device.write_block(block)
  26. }
  27. }
  28. /// Read super block from block device
  29. #[allow(unused)]
  30. pub(super) fn read_super_block(&self) -> SuperBlock {
  31. let block = self.read_block(0);
  32. block.read_offset_as(BASE_OFFSET)
  33. }
  34. /// Write super block to block device
  35. pub(super) fn write_super_block(&self, sb: &SuperBlock) {
  36. let mut block = Block::new(0, [0; BLOCK_SIZE]);
  37. block.write_offset_as(BASE_OFFSET, sb);
  38. self.write_block(&block)
  39. }
  40. /// Read an inode from block device, return an `InodeRef` that
  41. /// combines the inode and its id.
  42. pub(super) fn read_inode(&self, inode_id: InodeId) -> InodeRef {
  43. let (block_id, offset) = self.inode_disk_pos(inode_id);
  44. let block = self.read_block(block_id);
  45. InodeRef::new(inode_id, block.read_offset_as(offset))
  46. }
  47. /// Read the root inode from block device
  48. #[allow(unused)]
  49. pub(super) fn read_root_inode(&self) -> InodeRef {
  50. self.read_inode(EXT4_ROOT_INO)
  51. }
  52. /// Write an inode to block device with checksum
  53. pub(super) fn write_inode_with_csum(&self, inode_ref: &mut InodeRef) {
  54. let super_block = self.read_super_block();
  55. inode_ref.set_checksum(&super_block.uuid());
  56. self.write_inode_without_csum(inode_ref);
  57. }
  58. /// Write an inode to block device without checksum
  59. pub(super) fn write_inode_without_csum(&self, inode_ref: &InodeRef) {
  60. let (block_id, offset) = self.inode_disk_pos(inode_ref.id);
  61. let mut block = self.read_block(block_id);
  62. block.write_offset_as(offset, &inode_ref.inode);
  63. self.write_block(&block)
  64. }
  65. /// Read a block group descriptor from block device, return an `BlockGroupRef`
  66. /// that combines the block group descriptor and its id.
  67. pub(super) fn read_block_group(&self, block_group_id: BlockGroupId) -> BlockGroupRef {
  68. let (block_id, offset) = self.block_group_disk_pos(block_group_id);
  69. let block = self.read_block(block_id as PBlockId);
  70. BlockGroupRef::new(
  71. block_group_id,
  72. block.read_offset_as::<BlockGroupDesc>(offset),
  73. )
  74. }
  75. /// Write a block group descriptor to block device with checksum
  76. pub(super) fn write_block_group_with_csum(&self, bg_ref: &mut BlockGroupRef) {
  77. let super_block = self.read_super_block();
  78. bg_ref.set_checksum(&super_block.uuid());
  79. self.write_block_group_without_csum(bg_ref);
  80. }
  81. /// Write a block group descriptor to block device without checksum
  82. #[allow(unused)]
  83. pub(super) fn write_block_group_without_csum(&self, bg_ref: &BlockGroupRef) {
  84. let (block_id, offset) = self.block_group_disk_pos(bg_ref.id);
  85. let mut block = self.read_block(block_id as PBlockId);
  86. block.write_offset_as(offset, &bg_ref.desc);
  87. self.write_block(&block);
  88. }
  89. /// Get disk position of an inode. Return block id and offset within the block.
  90. ///
  91. /// Each block group contains `sb.inodes_per_group` inodes.
  92. /// Because inode 0 is defined not to exist, this formula can
  93. /// be used to find the block group that an inode lives in:
  94. /// `bg = (inode_id - 1) / sb.inodes_per_group`.
  95. ///
  96. /// The particular inode can be found within the block group's
  97. /// inode table at `index = (inode_id - 1) % sb.inodes_per_group`.
  98. /// To get the byte address within the inode table, use
  99. /// `offset = index * sb.inode_size`.
  100. fn inode_disk_pos(&self, inode_id: InodeId) -> (PBlockId, usize) {
  101. let super_block = self.read_super_block();
  102. let inodes_per_group = super_block.inodes_per_group();
  103. let bg_id = ((inode_id - 1) / inodes_per_group) as BlockGroupId;
  104. let inode_size = super_block.inode_size();
  105. let bg = self.read_block_group(bg_id);
  106. let id_in_bg = ((inode_id - 1) % inodes_per_group) as usize;
  107. let block_id =
  108. bg.desc.inode_table_first_block() + (id_in_bg * inode_size / BLOCK_SIZE) as PBlockId;
  109. let offset = (id_in_bg * inode_size) % BLOCK_SIZE;
  110. (block_id, offset)
  111. }
  112. /// Get disk position of a block group. Return block id and offset within the block.
  113. fn block_group_disk_pos(&self, block_group_id: BlockGroupId) -> (PBlockId, usize) {
  114. let super_block = self.read_super_block();
  115. let desc_per_block = BLOCK_SIZE as u32 / super_block.desc_size() as u32;
  116. let block_id = super_block.first_data_block() + block_group_id / desc_per_block + 1;
  117. let offset = (block_group_id % desc_per_block) * super_block.desc_size() as u32;
  118. (block_id as PBlockId, offset as usize)
  119. }
  120. }