引文(引用博客: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