dir_entry.rs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. //! # The Defination of Ext4 Directory Entry
  2. //!
  3. //! A directory is a series of data blocks and that each block contains a
  4. //! linear array of directory entries.
  5. use super::crc::*;
  6. use super::Ext4Superblock;
  7. use crate::constants::*;
  8. use crate::prelude::*;
  9. use alloc::string::FromUtf8Error;
  10. #[repr(C)]
  11. pub union Ext4DirEnInner {
  12. pub name_length_high: u8, // 高8位的文件名长度
  13. pub inode_type: FileType, // 引用的inode的类型(在rev >= 0.5中)
  14. }
  15. impl Debug for Ext4DirEnInner {
  16. fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
  17. unsafe {
  18. write!(
  19. f,
  20. "Ext4DirEnInternal {{ name_length_high: {:?} }}",
  21. self.name_length_high
  22. )
  23. }
  24. }
  25. }
  26. impl Default for Ext4DirEnInner {
  27. fn default() -> Self {
  28. Self {
  29. name_length_high: 0,
  30. }
  31. }
  32. }
  33. #[repr(C)]
  34. #[derive(Debug)]
  35. pub struct Ext4DirEntry {
  36. inode: u32, // 该目录项指向的inode的编号
  37. rec_len: u16, // 到下一个目录项的距离
  38. name_len: u8, // 低8位的文件名长度
  39. inner: Ext4DirEnInner, // 联合体成员
  40. name: [u8; 255], // 文件名
  41. }
  42. impl Default for Ext4DirEntry {
  43. fn default() -> Self {
  44. Self {
  45. inode: 0,
  46. rec_len: 0,
  47. name_len: 0,
  48. inner: Ext4DirEnInner::default(),
  49. name: [0; 255],
  50. }
  51. }
  52. }
  53. impl Ext4DirEntry {
  54. /// Create a new directory entry
  55. pub fn new(inode: u32, rec_len: u16, name: &str, dirent_type: FileType) -> Self {
  56. let mut name_bytes = [0u8; 255];
  57. let name_len = name.as_bytes().len();
  58. name_bytes[..name_len].copy_from_slice(name.as_bytes());
  59. Self {
  60. inode,
  61. rec_len,
  62. name_len: name_len as u8,
  63. inner: Ext4DirEnInner {
  64. inode_type: dirent_type,
  65. },
  66. name: name_bytes,
  67. }
  68. }
  69. /// Load a directory entry from bytes
  70. pub fn from_bytes(bytes: &[u8]) -> Self {
  71. unsafe { core::ptr::read(bytes.as_ptr() as *const _) }
  72. }
  73. pub fn name(&self) -> core::result::Result<String, FromUtf8Error> {
  74. let name_len = self.name_len as usize;
  75. let name = &self.name[..name_len];
  76. String::from_utf8(name.to_vec())
  77. }
  78. pub fn compare_name(&self, name: &str) -> bool {
  79. &self.name[..name.len()] == name.as_bytes()
  80. }
  81. pub fn set_name(&mut self, name: &str) {
  82. self.name_len = name.len() as u8;
  83. self.name[..name.len()].copy_from_slice(name.as_bytes());
  84. }
  85. /// Distance to the next directory entry
  86. pub fn rec_len(&self) -> u16 {
  87. self.rec_len
  88. }
  89. pub fn set_rec_len(&mut self, len: u16) {
  90. self.rec_len = len;
  91. }
  92. pub fn inode(&self) -> u32 {
  93. self.inode
  94. }
  95. pub fn set_inode(&mut self, inode: u32) {
  96. self.inode = inode;
  97. }
  98. /// Unused directory entries are signified by inode = 0
  99. pub fn unused(&self) -> bool {
  100. self.inode == 0
  101. }
  102. /// Set the dir entry's inode type given the corresponding inode mode
  103. pub fn set_entry_type(&mut self, inode_mode: u16) {
  104. self.inner.inode_type = inode_mode2file_type(inode_mode);
  105. }
  106. /// Get the required size to save this directory entry, 4-byte aligned
  107. pub fn required_size(name_len: usize) -> usize {
  108. // u32 + u16 + u8 + Ext4DirEnInner + name -> align to 4
  109. (core::mem::size_of::<Ext4FakeDirEntry>() + name_len + 3) / 4 * 4
  110. }
  111. /// Get the used size of this directory entry, 4-bytes alighed
  112. pub fn used_size(&self) -> usize {
  113. Self::required_size(self.name_len as usize)
  114. }
  115. pub fn calc_csum(&self, s: &Ext4Superblock, blk_data: &[u8]) -> u32 {
  116. let ino_index = self.inode;
  117. let ino_gen = 0 as u32;
  118. let uuid = s.uuid();
  119. let mut csum = ext4_crc32c(EXT4_CRC32_INIT, &uuid, uuid.len() as u32);
  120. csum = ext4_crc32c(csum, &ino_index.to_le_bytes(), 4);
  121. csum = ext4_crc32c(csum, &ino_gen.to_le_bytes(), 4);
  122. let mut data = [0u8; 0xff4];
  123. unsafe {
  124. core::ptr::copy_nonoverlapping(blk_data.as_ptr(), data.as_mut_ptr(), blk_data.len());
  125. }
  126. csum = ext4_crc32c(csum, &data[..], 0xff4);
  127. csum
  128. }
  129. pub fn copy_to_byte_slice(&self, slice: &mut [u8], offset: usize) {
  130. let de_ptr = self as *const Ext4DirEntry as *const u8;
  131. let slice_ptr = slice as *mut [u8] as *mut u8;
  132. let count = core::mem::size_of::<Ext4DirEntry>();
  133. unsafe {
  134. core::ptr::copy_nonoverlapping(de_ptr, slice_ptr.add(offset), count);
  135. }
  136. }
  137. }
  138. #[repr(C)]
  139. #[derive(Debug, Clone, Copy, Default)]
  140. pub struct Ext4DirEntryTail {
  141. pub reserved_zero1: u32,
  142. pub rec_len: u16,
  143. pub reserved_zero2: u8,
  144. pub reserved_ft: u8,
  145. pub checksum: u32, // crc32c(uuid+inum+dirblock)
  146. }
  147. impl Ext4DirEntryTail {
  148. pub fn from_bytes(data: &mut [u8], blocksize: usize) -> Option<Self> {
  149. unsafe {
  150. let ptr = data as *mut [u8] as *mut u8;
  151. let t = *(ptr.add(blocksize - core::mem::size_of::<Ext4DirEntryTail>())
  152. as *mut Ext4DirEntryTail);
  153. if t.reserved_zero1 != 0 || t.reserved_zero2 != 0 {
  154. log::info!("t.reserved_zero1");
  155. return None;
  156. }
  157. if t.rec_len.to_le() != core::mem::size_of::<Ext4DirEntryTail>() as u16 {
  158. log::info!("t.rec_len");
  159. return None;
  160. }
  161. if t.reserved_ft != 0xDE {
  162. log::info!("t.reserved_ft");
  163. return None;
  164. }
  165. Some(t)
  166. }
  167. }
  168. pub fn set_csum(&mut self, s: &Ext4Superblock, diren: &Ext4DirEntry, blk_data: &[u8]) {
  169. self.checksum = diren.calc_csum(s, blk_data);
  170. }
  171. pub fn copy_to_byte_slice(&self, slice: &mut [u8], offset: usize) {
  172. let de_ptr = self as *const Ext4DirEntryTail as *const u8;
  173. let slice_ptr = slice as *mut [u8] as *mut u8;
  174. let count = core::mem::size_of::<Ext4DirEntryTail>();
  175. unsafe {
  176. core::ptr::copy_nonoverlapping(de_ptr, slice_ptr.add(offset), count);
  177. }
  178. }
  179. }
  180. /// Fake dir entry. A normal entry without `name` field`
  181. #[repr(C)]
  182. pub struct Ext4FakeDirEntry {
  183. inode: u32,
  184. entry_length: u16,
  185. name_length: u8,
  186. inode_type: u8,
  187. }
  188. #[derive(PartialEq, Eq, Clone, Copy, Debug)]
  189. #[repr(u8)]
  190. pub enum FileType {
  191. Unknown,
  192. RegularFile,
  193. Directory,
  194. CharacterDev,
  195. BlockDev,
  196. Fifo,
  197. Socket,
  198. SymLink,
  199. }
  200. pub fn inode_mode2file_type(inode_mode: u16) -> FileType {
  201. match inode_mode & EXT4_INODE_MODE_TYPE_MASK {
  202. EXT4_INODE_MODE_FILE => FileType::RegularFile,
  203. EXT4_INODE_MODE_DIRECTORY => FileType::Directory,
  204. EXT4_INODE_MODE_CHARDEV => FileType::CharacterDev,
  205. EXT4_INODE_MODE_BLOCKDEV => FileType::BlockDev,
  206. EXT4_INODE_MODE_FIFO => FileType::Fifo,
  207. EXT4_INODE_MODE_SOCKET => FileType::Socket,
  208. EXT4_INODE_MODE_SOFTLINK => FileType::SymLink,
  209. _ => FileType::Unknown,
  210. }
  211. }
  212. pub fn file_type2inode_mode(dirent_type: FileType) -> u16 {
  213. match dirent_type {
  214. FileType::RegularFile => EXT4_INODE_MODE_FILE,
  215. FileType::Directory => EXT4_INODE_MODE_DIRECTORY,
  216. FileType::SymLink => EXT4_INODE_MODE_SOFTLINK,
  217. FileType::CharacterDev => EXT4_INODE_MODE_CHARDEV,
  218. FileType::BlockDev => EXT4_INODE_MODE_BLOCKDEV,
  219. FileType::Fifo => EXT4_INODE_MODE_FIFO,
  220. FileType::Socket => EXT4_INODE_MODE_SOCKET,
  221. _ => EXT4_INODE_MODE_FILE,
  222. }
  223. }