Linux ext4文件系统inode信息修改

引文(引用博客:https://blog.csdn.net/stringnewname/article/details/73740155):Linux访问文件过程

1.当我们输入cat testfile时,cat命令接收到testfile参数,进而根据当前工作目录计算出这个文件的绝对路径为/home/niugen/testfile

2.解析这个路径,首先是/即根目录,根目录这个文件对应的inode号固定为2,所以可以直接找到根目录的inode

3.根据根目录的inode中存放的磁盘块号信息,可以知道数据存放在哪些磁盘块中,于是从这些磁盘块里读出数据

4.目录文件的数据,简单的看来就是一个表,有两列,一列是文件名,一列是对应的inode号。对于根目录,文件名就是常见的dev、usr、home等等,于是找到了home对应的inode号

5.于是读出了/home这个文件的inode,发现这也是一个目录文件,继续读出数据,找到niugen对应的inode号

6.于是读出了/home/niugen这个文件的inode,发现这还是一个目录文件,继续读出数据,找到testfile对应的inode号

7.于是读出了/home/niugen/testfile这个文件的inode,发现这是一个普通文件,可以使用cat命令,于是读出数据并打印在屏幕上

 

正文(参考博客:http://www.sohu.com/a/229842067_467784):对ext4文件系统inode信息修改

1、查看分区各group信息,找到iNode table所在块位置

# ./dumpe2fs /dev/mmcblk0p19

由上可知,iNode table 起始位置为145块开始~152块。

2、查看iNode table表信息内容,可通过Linux的常用命令dd + hexdump来查看想要查看的block device任意位置的内容。

# dd if=/dev/mmcblk0p19 bs=4096 skip=145 | hexdump -C -n 4096

已知该文件系统的block size是 4KB, Inode size是256B,一个块可以容纳4KB/256B=16个inode。

一般情况下分区的节点inode 为2,因此根据转换公式:offset = (inode – 1) * 256B 

 offset = (2-1)*256 = 256    ,转换为16进制则offset = 0x100

3、如果需要查看根目录的内容,则根据以下结构找到其数据存放区域

/*
 * Structure of an inode on the disk
 */
struct ext4_inode {
	__le16	i_mode;		/* File mode */
	__le16	i_uid;		/* Low 16 bits of Owner Uid */
	__le32	i_size_lo;	/* Size in bytes */
	__le32	i_atime;	/* Access time */
	__le32	i_ctime;	/* Inode Change time */
	__le32	i_mtime;	/* Modification time */
	__le32	i_dtime;	/* Deletion Time */
	__le16	i_gid;		/* Low 16 bits of Group Id */
	__le16	i_links_count;	/* Links count */
	__le32	i_blocks_lo;	/* Blocks count */
	__le32	i_flags;	/* File flags */
	union {
		struct {
			__le32  l_i_version;
		} linux1;
		struct {
			__u32  h_i_translator;
		} hurd1;
		struct {
			__u32  m_i_reserved1;
		} masix1;
	} osd1;				/* OS dependent 1 */
	__le32	i_block[EXT4_N_BLOCKS];/* Pointers to blocks */
	__le32	i_generation;	/* File version (for NFS) */
	__le32	i_file_acl_lo;	/* File ACL */
	__le32	i_size_high;
	__le32	i_obso_faddr;	/* Obsoleted fragment address */
	union {
		struct {
			__le16	l_i_blocks_high; /* were l_i_reserved1 */
			__le16	l_i_file_acl_high;
			__le16	l_i_uid_high;	/* these 2 fields */
			__le16	l_i_gid_high;	/* were reserved2[0] */
			__le16	l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */
			__le16	l_i_reserved;
		} linux2;
		struct {
			__le16	h_i_reserved1;	/* Obsoleted fragment number/size which are removed in ext4 */
			__u16	h_i_mode_high;
			__u16	h_i_uid_high;
			__u16	h_i_gid_high;
			__u32	h_i_author;
		} hurd2;
		struct {
			__le16	h_i_reserved1;	/* Obsoleted fragment number/size which are removed in ext4 */
			__le16	m_i_file_acl_high;
			__u32	m_i_reserved2[2];
		} masix2;
	} osd2;				/* OS dependent 2 */
	__le16	i_extra_isize;
	__le16	i_checksum_hi;	/* crc32c(uuid+inum+inode) BE */
	__le32  i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */
	__le32  i_mtime_extra;  /* extra Modification time(nsec << 2 | epoch) */
	__le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
	__le32  i_crtime;       /* File Creation time */
	__le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
	__le32  i_version_hi;	/* high 32 bits for 64-bit version */
};

上述结构中,i_block的大小为15个int_32(即EXT4_N_BLOCKS=15 )。

(1)前6个int_32为extent头和extent的基本信息;

(2)后24个int_32可以保存4个extent节点,每个extent节点为6 int_32大小 ;

extent以树的形式组织,叶节点和非页节点的大小均6 int_32;

叶节点即直接保存了文件逻辑块号、起始磁盘块号、块数;

非叶节点同样具有文件逻辑块号,后面内容指向了一个磁盘块号,有两个字节未使用。

/*
 * Each block (leaves and indexes), even inode-stored has header.
 */
struct ext4_extent_header {
    __le16  eh_magic;   /* probably will support different formats */
    __le16  eh_entries; /* number of valid entries */
    __le16  eh_max;     /* capacity of store in entries */
    __le16  eh_depth;   /* has tree real underlying blocks? */
    __le32  eh_generation;  /* generation of the tree */
};
/*
 * This is the extent on-disk structure.
 * It's used at the bottom of the tree.
 */
struct ext4_extent {
    __le32  ee_block;   /* first logical block extent covers */
    __le16  ee_len;     /* number of blocks covered by extent */
    __le16  ee_start_hi;    /* high 16 bits of physical block */ //物理块地址高位
    __le32  ee_start_lo;    /* low 32 bits of physical block */ //物理块地址低位
};
/*
 * This is index on-disk structure.
 * It's used at all the levels except the bottom.
 */
struct ext4_extent_idx {
    __le32  ei_block;   /* index covers logical blocks from 'block' */
    __le32  ei_leaf_lo; /* pointer to the physical block of the next *
                 * level. leaf or next index could be there */
    __le16  ei_leaf_hi; /* high 16 bits of physical block */
    __u16   ei_unused;
};

根据上结构找到,存放内容的块位置,由于ext4用了48位地址,因此其用6个字节存放块地址,再将其转为10进制à0x0000 000000d1 = 209

查看分区根目录存放的内容:

#  dd if=/dev/mmcblk0p19 bs=4096 skip=209 | hexdump -C -n 4096

由上图可见其目录下存放的内容,上述存放是根据以下结构体存放。

#define EXT4_NAME_LEN 255

struct ext4_dir_entry_2 {
	__le32	inode;/*索引节点号*/
	__le16	rec_len;/*目录项长度*/
	__u8	name_len;/*文件名长度*/
	__u8	file_type;/*文件类型*/
	char	name[EXT4_NAME_LEN];/*文件名*/
};

4、进一步查找advert目录,根据以上信息结构进行以下步骤:

(1)获取advert的inode,其inode = 0x0000000c =12(10进制)

(2)根据公式offset = (inode – 1) * 256B换算出,计算出其inode信息在分区inode表中的位置:Offset = (12-*1)*256 = 2816=0xB00(16进制)

(3)打印分区inode tableneir

# dd if=/dev/mmcblk0p19 bs=4096 skip=145 | hexdump -C -n 4096

(4)再根据其内容地址并打印出其内容

Addr = 0xd7 =215

# dd if=/dev/mmcblk0p19 bs=4096 skip=215 | hexdump -C -n 4096

由上图所示,advert目录下的内容为两个文件夹,再通过ls命令查看advert目录,里面有tmp和8e42c7fd4e3974cfa799455f4c0e26cf目录。

5、在uboot修改分区文件节点内容

(1)计算物理地址,根据命令:dd if=/dev/mmcblk0p19 bs=4096 skip=145 | hexdump -C -n 40960 的信息得到偏移offset,使用公式:145*4096 + offset 计算。如: 145*4096 + e00 = 91E00

(2)选中mmc

# mmc dev 2

(3)查看分区表,获取要操作的分区的起始扇区sector

# mmc part

(4)读取flash内容到内存

# mmc read 0x50000000 0x794000 0x80000

(5)打印对应于内容

# md 0x50091E00 0x100

(6)修改inode的校验信息

# mw 0x50091e7c 0x00000000

再次打印检查内容:

# md 0x50091E00 0x100

(7)将修改写回flash

# mmc write 0x50000000 0x794000 0x80000

(8)重启系统

# reset

(9)进入该分区对应文件目录

# cd /usr/VDS-880/data_1/advert/tmp
# ls

由上图可知,出现了错误:

ls: ./hl: Input/output error;

EXT4-fs error (device mmcblk0p19): ext4_iget:4193: inode #15: comm ls: checksum invalid,

原因是我们更改了该文件inode节点信息,导致其inode校验失败内核返回return –EIO。

我们可以使用下面命令获取分区错误信息:

# dmesg | grep err

6、修复ls: ./hl: Input/output error错误

一般出现ls: ./hl: Input/output error错误有1、分区表错误;2、磁盘硬件损坏两种可能。对于第一种可能,我们可以通过工具进行修复,对于第二种可能,则只能更换硬件了,下面将针对第一种可能进行修复。

(1)解挂分区

# umount /usr/VDS-880/data_1/

(2)使用fsck.ext4工具对分区进行修复(对于fsck.ext4 工具源码的获取,请参考:https://blog.csdn.net/Chasing_Chasing/article/details/82215531

# ./fsck.ext4 /dev/mmcblk0p19
[root@VDS-880-C1F data_0]# ./fsck.ext4 /dev/mmcblk0p19
e2fsck 1.44.1 (24-Mar-2018)
ext2fs_check_if_mount: Can't check if filesystem is mounted due to missing mtab file while determining whether /dev/mmcblk0p19 is mounted.
Superblock last mount time is in the future.
        (by less than a day, probably due to the hardware clock being incorrectly set)
/dev/mmcblk0p19 contains a file system with errors, check forced.
Pass 1: Checking inodes, blocks, and sizes
Inode 15 passes checks, but checksum does not match inode.  Fix<y>? yes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mmcblk0p19: ***** FILE SYSTEM WAS MODIFIED *****
/dev/mmcblk0p19: 19/1024 files (0.0% non-contiguous), 8981/262144 blocks

(3)挂载修复后的分区

# mount /dev/mmcblk0p19 /usr/VDS-880/data_1/

参考博客:

http://www.sohu.com/a/229842067_467784

http://www.cnblogs.com/mikeguan/p/7647222.html

https://blog.csdn.net/stringnewname/article/details/73740155

猜你喜欢

转载自blog.csdn.net/Chasing_Chasing/article/details/82260641
今日推荐