分类: 系统运维
2013-12-10 17:20:03
原文地址:文件显示大小和实际大小以及文件的洞的问题 作者:up哥小号
目录 |
:我们经常用ls命令,du命令,可是看到的结果不同,他们之间有什么关系呢?:如
[root@syslab filetest]# du -h * 0 file_0 4.0K file_1 4.0K file_2 4.0K file_4096 8.0K file_4097 4.0K hole [root@syslab filetest]# ll -h total 24K -rw-r--r--. 1 root root 0 Jan 10 16:15 file_0 -rw-r--r--. 1 root root 1 Jan 10 16:15 file_1 -rw-r--r--. 1 root root 2 Jan 10 16:15 file_2 -rwxr-xr-x. 1 root root 4.0K Jan 10 16:15 file_4096 -rw-r--r--. 1 root root 4.1K Jan 10 16:15 file_4097 -rw-r--r--. 1 root root 25K Jan 10 17:30 hole
:du命令和ll(ll相当于ls -l)命令看到的大小不一样啊!我如何知道文件到底是多大呢?我们接下来讨论这个问题
环境,ext3,块大小格式化为4096byte细节说明 echo 1 >/aa #echo时写入1还会写入一个换行符 echo -n 1 >/bb #echo 时不会写入末尾换行符
for((i=1;i<=4096;i++))do echo -n a>>file_4096;done for((i=1;i<=4097;i++))do echo -n a>>file_4097;done for((i=1;i<=1;i++))do echo -n a>>file_1;done for((i=1;i<=1;i++))do echo a>>file_2;done touch file_0
ls -lh -rw-r--r--. 1 root root 0 Jan 10 16:15 file_0 -rw-r--r--. 1 root root 1 Jan 10 16:15 file_1 -rw-r--r--. 1 root root 2 Jan 10 16:15 file_2 -rw-r--r--. 1 root root 4096 Jan 10 16:15 file_4096 -rw-r--r--. 1 root root 4097 Jan 10 16:15 file_4097现在,file_4096有4096byte,file_2有2个byte大小了,5个文件大小如命名
du -h * [root@syslab filetest]# du -h * 0 file_0 4.0K file_1 4.0K file_2 4.0K file_4096 8.0K file_4097 4.0K hole
struct ext3_inode { __le16 i_mode; /* File mode */ __le16 i_uid; /* Low 16 bits of Owner Uid */ __le32 i_size; /* Size in bytes */ __le32 i_atime; /* Access time */ __le32 i_ctime; /* Creation 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; /* Blocks count */ .. __le32 i_block[EXT3_N_BLOCKS];/* Pointers to blocks */ .. }这是ext3具体文件对应inode在磁盘上的实际存储格式 其中,i_size表示文件的显示大小,即我们以为的文件大小。 i_blocks表示实际此文件占用多少个blocks(这里的block大小固定(与文件系统的块大小不同),固定为512byte,不随格式化时候块大小的变化而变化)。
[root@syslab filetest]# ll -i |sort -k 1 273974 -rw-r--r--. 1 root root 4096 Jan 10 16:15 file_4096 273975 -rw-r--r--. 1 root root 4097 Jan 10 16:15 file_4097 273976 -rw-r--r--. 1 root root 1 Jan 10 16:15 file_1 273977 -rw-r--r--. 1 root root 2 Jan 10 16:15 file_2 273978 -rw-r--r--. 1 root root 0 Jan 10 16:15 file_0 第一列就是inode的编号
debugfs -R 'stats' /dev/sda2 ... Block size: 4096 ... Inodes per group: 8192 ... Inode size: 256 ... Group 32: block bitmap at 1048576, inode bitmap at 1048592, inode table at 1048608 23336 free blocks, 0 free inodes, 968 used directories, 0 unused inodes [Checksum 0x0cdd] Group 33: block bitmap at 1048577, inode bitmap at 1048593, inode table at 1049120 0 free blocks, 4470 free inodes, 217 used directories, 4470 unused inodes [Checksum 0xd341] ...其中,我们看到Inodes per group: 8192,我们得知这5个inode存储的块组为(inode在ls显示中的编号是从1开始的,内核里面是从0开始的) 273974/8192=33;块组中inode下标为余数3638;(数组下标从0开始) 273975/8192=33;块组中inode下标为余数3639;(数组下标从0开始) 273976/8192=33;块组中inode下标为余数3640;(数组下标从0开始) 273977/8192=33;块组中inode下标为余数3641;(数组下标从0开始) 273978/8192=33;块组中inode下标为余数3642;(数组下标从0开始 同时,我们从debugfs的输出中得知,块组33的inodetable在块号为1049120的数据块中 那么上面5个inode结构体在磁盘上面的具体内容是什么呢 直接去看磁盘上面存的是什么 由于磁盘块大小为4096byte(格式化的时候指定的),inodetable的起始位置为1049120*4096(块号*块大小),所以这5个inode的位置为 file_4096对应的inode在磁盘的 1049120*4096+(3638-1)*256到1049120*4096+3638*256存放着(单位:字节) 我们读取这个inode的磁盘数据 1049120*4096+3637*256=4298126592 我们读写磁盘上面的裸数,看到底存的是什么值
[root@syslab filetest]# dd if=/dev/sda2 bs=1 count=256 skip=4298126592 |od -t x4 -Ax 000000 000081a4 00001000 50ee78a8 50ee78a8 000010 50ee78a8 00000000 00010000 00000008 000020 00080000 00000001 0001f30a 00000004 000030 00000000 00000000 00000001 001125c7我们先简单确认一下这段数据是不是file_4096结构体在磁盘上面的数据 我们知道
struct ext3_inode { __le16 i_mode; /* File mode */前面2字节是访问模式,所以
[root@syslab ~]# dd if=/dev/sda2 bs=1 count=256 skip=4298126592|od -t x2 -Ax 000000 81a4 0000 1000 0000 78a8 50ee cdbd 50ef得到前面两字节为0x81a4等于八进制100644,为rw,r,r模式,ll查看一下
-rw-r--r--. 1 root root 4096 Jan 10 16:15 file_4096确实正确,然后我们chmod +x file_4096看结果,ls –l
-rwxr-xr-x. 1 root root 4096 Jan 10 16:15 file_4096模式后几位为755才对
[root@syslab filetest]# dd if=/dev/sda2 bs=1 count=256 skip=4298126592 |od -t x2 -Ax 000000 81ed 0000 1000 0000 78a8 50ee cde7 50ef前面两字节为0x81ed等于八进制100755,为755!就是这个文件
其实我们还可以看时间 创建时间0x50ee78a8=1357805736 [root@syslab filetest]# date -d "@1357805736" Thu Jan 10 16:15:36 CST 2013 或者修改文件来看修改实际等等来确认
__le32 i_size;的位置为相对于struct ext3_inode结构体的偏移量为0x4, __le32 i_blocks的偏移量为0x1c且则两个值都是4字节长度,所以我们下看一下file_4096的i_size和i_blocks到底是多少
[root@syslab filetest]# dd if=/dev/sda2 bs=1 count=256 skip=4298126592 |od -t x4 -Ax 000000 000081ed 00001000 50ee78a8 50efcde7 000010 50ee78a8 00000000 00010000 00000008 000020 00080000 00000001 0001f30a 00000004 000030 00000000 00000000 00000001 001125c7 000040 00000000 00000000 00000000 00000000 ..所以根据偏移量我们可以得到这两个值 i_size=0x00001000=4096,确实为ls显示大小 i_blocks=0x00000008=8,8个块(上面我们已经指出,这里块固定为512字节,与文件系统层次块大小不同),8*512=4096,正好为一个块 所以,file_4096正好为一个块,显示大小为4096 byte,实际大小也为4096byte 同样的方法我们看其余4个file,得到结果如下
file_4097, i_size=0x00001001=4097byte i_blocks=0x00000010=16 (16*512=4096*2,即实际占两个块!)
file_1 i_size=0x00000001=1byte i_blocks=0x00000008=8 (8*512=4096,即1byte也占用1个块)
file_2 i_size=0x00000002=2byte i_blocks=0x00000008=8 (8*512=4096,即2byte也占用1个块)
file_0 i_size=0x00000000=0byte i_blocks=0x00000000=0 (0byte不占用任何数据块)然后我们把i_size和i_blocks的值和ls -l命令和du -h *命令结果对比得知
i_size和ls命令显示大小相同,所以这是我们以为的大小,比如我写了一个字符到一个文件,我们会以为这个文件大小为1个字节 i_blocks和du命令显示大小相同,所以这个是我们磁盘存储的实际大小,比如我写了一个字符到一个文件,但实际磁盘占据了一个块(一般是4096byte)大小
echo -n "a" | dd of=/root/filetest/hole bs=4096 seek=6表示对于文件/root/filetest,前面4096*6byte全部跳过,然后写入一个字符“a”,我们用上面的方法看一下
273979 -rw-r--r--. 1 root root 24577 Jan 10 17:30 hole,这个文件显示占用了24577byte,可是实际占用多少磁盘呢?
4.0K hole
i_size=0x00006001=24577 i_blocks=0x00000008 (8*512=4096byte,占1个块大小!空洞不占用实际的数据块!)
即磁盘上inode结构体中的i_size值,单位byte
即磁盘上inode结构体中的i_blocks*512,单位byte i_blocks固定为512byte,这和文件系统格式化的时候的块大小不同且不随文件系统格式化块大小的变化而变化
即文件如果包含200M的洞,这200M不占用时间的磁盘块
即文件如果包含200M的洞,ls就会加上这200M的空洞 注:我这里是从磁盘的实际存储数据来对比ls,du显示结果,并没有直接查看ls,du命令的源码,如果有错误,欢迎指正~