123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- //! # The Defination of Ext4 Directory Entry
- //!
- //! A directory is a series of data blocks and that each block contains a
- //! linear array of directory entries.
- use super::crc::*;
- use super::Ext4Block;
- use super::Ext4Superblock;
- use crate::constants::*;
- use crate::prelude::*;
- use alloc::string::FromUtf8Error;
- #[repr(C)]
- pub union Ext4DirEnInner {
- pub name_length_high: u8, // 高8位的文件名长度
- pub inode_type: FileType, // 引用的inode的类型(在rev >= 0.5中)
- }
- impl Debug for Ext4DirEnInner {
- fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
- unsafe {
- write!(
- f,
- "Ext4DirEnInternal {{ name_length_high: {:?} }}",
- self.name_length_high
- )
- }
- }
- }
- impl Default for Ext4DirEnInner {
- fn default() -> Self {
- Self {
- name_length_high: 0,
- }
- }
- }
- #[repr(C)]
- #[derive(Debug)]
- pub struct Ext4DirEntry {
- inode: u32, // 该目录项指向的inode的编号
- rec_len: u16, // 到下一个目录项的距离
- name_len: u8, // 低8位的文件名长度
- inner: Ext4DirEnInner, // 联合体成员
- name: [u8; 255], // 文件名
- }
- impl Default for Ext4DirEntry {
- fn default() -> Self {
- Self {
- inode: 0,
- rec_len: 0,
- name_len: 0,
- inner: Ext4DirEnInner::default(),
- name: [0; 255],
- }
- }
- }
- impl<T> TryFrom<&[T]> for Ext4DirEntry {
- type Error = u64;
- fn try_from(data: &[T]) -> core::result::Result<Self, u64> {
- let data = data;
- Ok(unsafe { core::ptr::read(data.as_ptr() as *const _) })
- }
- }
- impl Ext4DirEntry {
- pub fn name(&self) -> core::result::Result<String, FromUtf8Error> {
- let name_len = self.name_len as usize;
- let name = &self.name[..name_len];
- String::from_utf8(name.to_vec())
- }
- pub fn compare_name(&self, name: &str) -> bool {
- &self.name[..name.len()] == name.as_bytes()
- }
- pub fn set_name(&mut self, name: &str) {
- self.name_len = name.len() as u8;
- self.name[..name.len()].copy_from_slice(name.as_bytes());
- }
- pub fn rec_len(&self) -> u16 {
- self.rec_len
- }
- pub fn set_rec_len(&mut self, len: u16) {
- self.rec_len = len;
- }
- pub fn inode(&self) -> u32 {
- self.inode
- }
- pub fn set_inode(&mut self, inode: u32) {
- self.inode = inode;
- }
- /// Unused directory entries are signified by inode = 0
- pub fn unused(&self) -> bool {
- self.inode == 0
- }
- /// Set the dir entry's inode type given the corresponding inode mode
- pub fn set_entry_type(&mut self, inode_mode: u16) {
- self.inner.inode_type = inode_mode2file_type(inode_mode);
- }
- /// Get the required size to save this directory entry, 4-byte aligned
- pub fn required_size(name_len: usize) -> usize {
- // u32 + u16 + u8 + Ext4DirEnInner + name -> align to 4
- (core::mem::size_of::<Ext4FakeDirEntry>() + name_len + 3) / 4 * 4
- }
- /// Get the used size of this directory entry, 4-bytes alighed
- pub fn used_size(&self) -> usize {
- Self::required_size(self.name_len as usize)
- }
- pub fn calc_csum(&self, s: &Ext4Superblock, blk_data: &[u8]) -> u32 {
- let ino_index = self.inode;
- let ino_gen = 0 as u32;
- let uuid = s.uuid();
- let mut csum = ext4_crc32c(EXT4_CRC32_INIT, &uuid, uuid.len() as u32);
- csum = ext4_crc32c(csum, &ino_index.to_le_bytes(), 4);
- csum = ext4_crc32c(csum, &ino_gen.to_le_bytes(), 4);
- let mut data = [0u8; 0xff4];
- unsafe {
- core::ptr::copy_nonoverlapping(blk_data.as_ptr(), data.as_mut_ptr(), blk_data.len());
- }
- csum = ext4_crc32c(csum, &data[..], 0xff4);
- csum
- }
- pub fn write_to_blk(&self, dst_blk: &mut Ext4Block, offset: usize) {
- let count = core::mem::size_of::<Ext4DirEntry>() / core::mem::size_of::<u8>();
- let data = unsafe { core::slice::from_raw_parts(self as *const _ as *const u8, count) };
- dst_blk.block_data.splice(
- offset..offset + core::mem::size_of::<Ext4DirEntry>(),
- data.iter().cloned(),
- );
- // assert_eq!(dst_blk.block_data[offset..offset + core::mem::size_of::<Ext4DirEntry>()], data[..]);
- }
- pub fn copy_to_byte_slice(&self, slice: &mut [u8], offset: usize) {
- let de_ptr = self as *const Ext4DirEntry as *const u8;
- let slice_ptr = slice as *mut [u8] as *mut u8;
- let count = core::mem::size_of::<Ext4DirEntry>();
- unsafe {
- core::ptr::copy_nonoverlapping(de_ptr, slice_ptr.add(offset), count);
- }
- }
- }
- #[repr(C)]
- #[derive(Debug, Clone, Copy, Default)]
- pub struct Ext4DirEntryTail {
- pub reserved_zero1: u32,
- pub rec_len: u16,
- pub reserved_zero2: u8,
- pub reserved_ft: u8,
- pub checksum: u32, // crc32c(uuid+inum+dirblock)
- }
- impl Ext4DirEntryTail {
- pub fn from(data: &mut [u8], blocksize: usize) -> Option<Self> {
- unsafe {
- let ptr = data as *mut [u8] as *mut u8;
- let t = *(ptr.add(blocksize - core::mem::size_of::<Ext4DirEntryTail>())
- as *mut Ext4DirEntryTail);
- if t.reserved_zero1 != 0 || t.reserved_zero2 != 0 {
- log::info!("t.reserved_zero1");
- return None;
- }
- if t.rec_len.to_le() != core::mem::size_of::<Ext4DirEntryTail>() as u16 {
- log::info!("t.rec_len");
- return None;
- }
- if t.reserved_ft != 0xDE {
- log::info!("t.reserved_ft");
- return None;
- }
- Some(t)
- }
- }
- pub fn set_csum(&mut self, s: &Ext4Superblock, diren: &Ext4DirEntry, blk_data: &[u8]) {
- self.checksum = diren.calc_csum(s, blk_data);
- }
- pub fn copy_to_byte_slice(&self, slice: &mut [u8], offset: usize) {
- let de_ptr = self as *const Ext4DirEntryTail as *const u8;
- let slice_ptr = slice as *mut [u8] as *mut u8;
- let count = core::mem::size_of::<Ext4DirEntryTail>();
- unsafe {
- core::ptr::copy_nonoverlapping(de_ptr, slice_ptr.add(offset), count);
- }
- }
- }
- pub struct Ext4DirSearchResult<'a> {
- pub block: Ext4Block<'a>,
- pub dentry: Ext4DirEntry,
- }
- impl<'a> Ext4DirSearchResult<'a> {
- pub fn new(block: Ext4Block<'a>, dentry: Ext4DirEntry) -> Self {
- Self { block, dentry }
- }
- }
- /// Fake dir entry. A normal entry without `name` field`
- #[repr(C)]
- pub struct Ext4FakeDirEntry {
- inode: u32,
- entry_length: u16,
- name_length: u8,
- inode_type: u8,
- }
- #[derive(PartialEq, Eq, Clone, Copy, Debug)]
- #[repr(u8)]
- pub enum FileType {
- Unknown,
- RegularFile,
- Directory,
- CharacterDev,
- BlockDev,
- Fifo,
- Socket,
- SymLink,
- }
- pub fn inode_mode2file_type(inode_mode: u16) -> FileType {
- let file_type = (inode_mode & EXT4_INODE_MODE_TYPE_MASK) as usize;
- match file_type {
- EXT4_INODE_MODE_FILE => FileType::RegularFile,
- EXT4_INODE_MODE_DIRECTORY => FileType::Directory,
- EXT4_INODE_MODE_CHARDEV => FileType::CharacterDev,
- EXT4_INODE_MODE_BLOCKDEV => FileType::BlockDev,
- EXT4_INODE_MODE_FIFO => FileType::Fifo,
- EXT4_INODE_MODE_SOCKET => FileType::Socket,
- EXT4_INODE_MODE_SOFTLINK => FileType::SymLink,
- _ => FileType::Unknown,
- }
- }
- pub fn file_type2inode_mode(dirent_type: FileType) -> u16 {
- let inode_mode = match dirent_type {
- FileType::RegularFile => EXT4_INODE_MODE_FILE,
- FileType::Directory => EXT4_INODE_MODE_DIRECTORY,
- FileType::SymLink => EXT4_INODE_MODE_SOFTLINK,
- FileType::CharacterDev => EXT4_INODE_MODE_CHARDEV,
- FileType::BlockDev => EXT4_INODE_MODE_BLOCKDEV,
- FileType::Fifo => EXT4_INODE_MODE_FIFO,
- FileType::Socket => EXT4_INODE_MODE_SOCKET,
- _ => EXT4_INODE_MODE_FILE,
- };
- inode_mode as u16
- }
|