inode.rs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. //! # The Defination of Ext4 Inode Table Entry
  2. //!
  3. //! The inode table is a linear array of struct `Ext4Inode`. The table is sized to have
  4. //! enough blocks to store at least `sb.inode_size * sb.inodes_per_group` bytes.
  5. //!
  6. //! The number of the block group containing an inode can be calculated as
  7. //! `(inode_number - 1) / sb.inodes_per_group`, and the offset into the group's table is
  8. //! `(inode_number - 1) % sb.inodes_per_group`. There is no inode 0.
  9. use super::crc::*;
  10. use super::BlockDevice;
  11. use super::Ext4BlockGroupDesc;
  12. use super::Ext4ExtentHeader;
  13. use super::Ext4Superblock;
  14. use super::{ExtentNode, ExtentNodeMut};
  15. use crate::constants::*;
  16. use crate::prelude::*;
  17. #[repr(C)]
  18. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
  19. pub struct Linux2 {
  20. pub l_i_blocks_high: u16, // 原来是l_i_reserved1
  21. pub l_i_file_acl_high: u16,
  22. pub l_i_uid_high: u16, // 这两个字段
  23. pub l_i_gid_high: u16, // 原来是reserved2[0]
  24. pub l_i_checksum_lo: u16, // crc32c(uuid+inum+inode) LE
  25. pub l_i_reserved: u16,
  26. }
  27. #[repr(C)]
  28. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
  29. pub struct Ext4Inode {
  30. pub mode: u16,
  31. pub uid: u16,
  32. pub size: u32,
  33. pub atime: u32,
  34. pub ctime: u32,
  35. pub mtime: u32,
  36. pub dtime: u32,
  37. pub gid: u16,
  38. pub links_count: u16,
  39. pub blocks: u32,
  40. pub flags: u32,
  41. pub osd1: u32,
  42. pub block: [u32; 15], // Block bitmap or extent tree
  43. pub generation: u32,
  44. pub file_acl: u32,
  45. pub size_hi: u32,
  46. pub faddr: u32, /* Obsoleted fragment address */
  47. pub osd2: Linux2, // 操作系统相关的字段2
  48. pub i_extra_isize: u16,
  49. pub i_checksum_hi: u16, // crc32c(uuid+inum+inode) BE
  50. pub i_ctime_extra: u32, // 额外的修改时间(nsec << 2 | epoch)
  51. pub i_mtime_extra: u32, // 额外的文件修改时间(nsec << 2 | epoch)
  52. pub i_atime_extra: u32, // 额外的访问时间(nsec << 2 | epoch)
  53. pub i_crtime: u32, // 文件创建时间
  54. pub i_crtime_extra: u32, // 额外的文件创建时间(nsec << 2 | epoch)
  55. pub i_version_hi: u32, // 64位版本的高32位
  56. }
  57. impl Ext4Inode {
  58. pub fn from_bytes(bytes: &[u8]) -> Self {
  59. unsafe { *(bytes.as_ptr() as *const Ext4Inode) }
  60. }
  61. pub fn flags(&self) -> u32 {
  62. self.flags
  63. }
  64. pub fn set_flags(&mut self, f: u32) {
  65. self.flags |= f;
  66. }
  67. pub fn mode(&self) -> u16 {
  68. self.mode
  69. }
  70. pub fn set_mode(&mut self, mode: u16) {
  71. self.mode |= mode;
  72. }
  73. pub fn inode_type(&self, super_block: &Ext4Superblock) -> u32 {
  74. let mut v = self.mode;
  75. if super_block.creator_os() == EXT4_SUPERBLOCK_OS_HURD {
  76. v |= ((self.osd2.l_i_file_acl_high as u32) << 16) as u16;
  77. }
  78. (v & EXT4_INODE_MODE_TYPE_MASK) as u32
  79. }
  80. pub fn is_dir(&self, super_block: &Ext4Superblock) -> bool {
  81. self.inode_type(super_block) == EXT4_INODE_MODE_DIRECTORY as u32
  82. }
  83. pub fn is_softlink(&self, super_block: &Ext4Superblock) -> bool {
  84. self.inode_type(super_block) == EXT4_INODE_MODE_SOFTLINK as u32
  85. }
  86. pub fn links_cnt(&self) -> u16 {
  87. self.links_count
  88. }
  89. pub fn set_links_cnt(&mut self, cnt: u16) {
  90. self.links_count = cnt;
  91. }
  92. pub fn set_uid(&mut self, uid: u16) {
  93. self.uid = uid;
  94. }
  95. pub fn set_gid(&mut self, gid: u16) {
  96. self.gid = gid;
  97. }
  98. pub fn size(&mut self) -> u64 {
  99. self.size as u64 | ((self.size_hi as u64) << 32)
  100. }
  101. pub fn set_size(&mut self, size: u64) {
  102. self.size = ((size << 32) >> 32) as u32;
  103. self.size_hi = (size >> 32) as u32;
  104. }
  105. pub fn set_access_time(&mut self, access_time: u32) {
  106. self.atime = access_time;
  107. }
  108. pub fn set_change_inode_time(&mut self, change_inode_time: u32) {
  109. self.ctime = change_inode_time;
  110. }
  111. pub fn set_modif_time(&mut self, modif_time: u32) {
  112. self.mtime = modif_time;
  113. }
  114. pub fn set_del_time(&mut self, del_time: u32) {
  115. self.dtime = del_time;
  116. }
  117. pub fn set_blocks_count(&mut self, blocks_count: u32) {
  118. self.blocks = blocks_count;
  119. }
  120. pub fn set_generation(&mut self, generation: u32) {
  121. self.generation = generation;
  122. }
  123. pub fn set_extra_isize(&mut self, extra_isize: u16) {
  124. self.i_extra_isize = extra_isize;
  125. }
  126. pub fn set_inode_checksum_value(&mut self, super_block: &Ext4Superblock, checksum: u32) {
  127. let inode_size = super_block.inode_size();
  128. self.osd2.l_i_checksum_lo = ((checksum << 16) >> 16) as u16;
  129. if inode_size > 128 {
  130. self.i_checksum_hi = (checksum >> 16) as u16;
  131. }
  132. }
  133. pub fn blocks_count(&self) -> u64 {
  134. let mut blocks = self.blocks as u64;
  135. if self.osd2.l_i_blocks_high != 0 {
  136. blocks |= (self.osd2.l_i_blocks_high as u64) << 32;
  137. }
  138. blocks
  139. }
  140. fn copy_to_byte_slice(&self, slice: &mut [u8]) {
  141. unsafe {
  142. let inode_ptr = self as *const Ext4Inode as *const u8;
  143. let array_ptr = slice.as_ptr() as *mut u8;
  144. core::ptr::copy_nonoverlapping(inode_ptr, array_ptr, 0x9c);
  145. }
  146. }
  147. fn calc_checksum(&mut self, inode_id: u32, super_block: &Ext4Superblock) -> u32 {
  148. let inode_size = super_block.inode_size();
  149. let ino_index = inode_id as u32;
  150. let ino_gen = self.generation;
  151. // Preparation: temporarily set bg checksum to 0
  152. self.osd2.l_i_checksum_lo = 0;
  153. self.i_checksum_hi = 0;
  154. let mut checksum = ext4_crc32c(
  155. EXT4_CRC32_INIT,
  156. &super_block.uuid(),
  157. super_block.uuid().len() as u32,
  158. );
  159. checksum = ext4_crc32c(checksum, &ino_index.to_le_bytes(), 4);
  160. checksum = ext4_crc32c(checksum, &ino_gen.to_le_bytes(), 4);
  161. let mut raw_data = [0u8; 0x100];
  162. self.copy_to_byte_slice(&mut raw_data);
  163. // inode checksum
  164. checksum = ext4_crc32c(checksum, &raw_data, inode_size as u32);
  165. self.set_inode_checksum_value(super_block, checksum);
  166. if inode_size == 128 {
  167. checksum &= 0xFFFF;
  168. }
  169. checksum
  170. }
  171. fn set_checksum(&mut self, super_block: &Ext4Superblock, inode_id: u32) {
  172. let inode_size = super_block.inode_size();
  173. let checksum = self.calc_checksum(inode_id, super_block);
  174. self.osd2.l_i_checksum_lo = ((checksum << 16) >> 16) as u16;
  175. if inode_size > 128 {
  176. self.i_checksum_hi = (checksum >> 16) as u16;
  177. }
  178. }
  179. /* Extent methods */
  180. /// Get the immutable extent root node
  181. pub fn extent(&self) -> ExtentNode {
  182. ExtentNode::from_bytes(unsafe {
  183. core::slice::from_raw_parts(self.block.as_ptr() as *const u8, 60)
  184. })
  185. }
  186. /// Get the mutable extent root node
  187. pub fn extent_mut(&mut self) -> ExtentNodeMut {
  188. ExtentNodeMut::from_bytes(unsafe {
  189. core::slice::from_raw_parts_mut(self.block.as_mut_ptr() as *mut u8, 60)
  190. })
  191. }
  192. /// Initialize the `flags` and `block` field of inode. Mark the
  193. /// inode to use extent for block mapping. Initialize the root
  194. /// node of the extent tree
  195. pub fn extent_init(&mut self) {
  196. self.set_flags(EXT4_INODE_FLAG_EXTENTS);
  197. let header = Ext4ExtentHeader::new(0, 4, 0, 0);
  198. let header_ptr = &header as *const Ext4ExtentHeader as *const u32;
  199. let array_ptr = &mut self.block as *mut [u32; 15] as *mut u32;
  200. unsafe {
  201. core::ptr::copy_nonoverlapping(header_ptr, array_ptr, 3);
  202. }
  203. }
  204. }
  205. /// A combination of an `Ext4Inode` and its id
  206. #[derive(Default, Clone)]
  207. pub struct Ext4InodeRef {
  208. pub inode_id: InodeId,
  209. pub inode: Ext4Inode,
  210. }
  211. impl Ext4InodeRef {
  212. pub fn new(inode_id: InodeId, inode: Ext4Inode) -> Self {
  213. Self { inode_id, inode }
  214. }
  215. pub fn read_from_disk(
  216. block_device: Arc<dyn BlockDevice>,
  217. super_block: &Ext4Superblock,
  218. inode_id: InodeId,
  219. ) -> Self {
  220. let pos = Self::inode_disk_pos(super_block, block_device.clone(), inode_id);
  221. let data = block_device.read_offset(pos);
  222. let inode_data = &data[..core::mem::size_of::<Ext4Inode>()];
  223. Self {
  224. inode_id,
  225. inode: Ext4Inode::from_bytes(inode_data),
  226. }
  227. }
  228. /// Find the position of an inode in the block device.
  229. ///
  230. /// Each block group contains `sb.inodes_per_group` inodes.
  231. /// Because inode 0 is defined not to exist, this formula can
  232. /// be used to find the block group that an inode lives in:
  233. /// `bg = (inode_id - 1) / sb.inodes_per_group`.
  234. ///
  235. /// The particular inode can be found within the block group's
  236. /// inode table at `index = (inode_id - 1) % sb.inodes_per_group`.
  237. /// To get the byte address within the inode table, use
  238. /// `offset = index * sb.inode_size`.
  239. fn inode_disk_pos(
  240. super_block: &Ext4Superblock,
  241. block_device: Arc<dyn BlockDevice>,
  242. inode_id: InodeId,
  243. ) -> usize {
  244. let inodes_per_group = super_block.inodes_per_group();
  245. let inode_size = super_block.inode_size();
  246. let group = (inode_id - 1) / inodes_per_group;
  247. let index = (inode_id - 1) % inodes_per_group;
  248. let bg = Ext4BlockGroupDesc::load(block_device, super_block, group as usize).unwrap();
  249. bg.inode_table_first_block() as usize * BLOCK_SIZE + (index * inode_size as u32) as usize
  250. }
  251. pub fn sync_to_disk_without_csum(
  252. &self,
  253. block_device: Arc<dyn BlockDevice>,
  254. super_block: &Ext4Superblock,
  255. ) -> Result<()> {
  256. let disk_pos = Self::inode_disk_pos(super_block, block_device.clone(), self.inode_id);
  257. let data = unsafe {
  258. core::slice::from_raw_parts(self as *const _ as *const u8, size_of::<Ext4Inode>())
  259. };
  260. block_device.write_offset(disk_pos, data);
  261. Ok(())
  262. }
  263. pub fn sync_to_disk_with_csum(
  264. &mut self,
  265. block_device: Arc<dyn BlockDevice>,
  266. super_block: &Ext4Superblock,
  267. ) -> Result<()> {
  268. self.inode.set_checksum(super_block, self.inode_id);
  269. self.sync_to_disk_without_csum(block_device, super_block)
  270. }
  271. }