说到软硬链接,首先要了解inode
是什么,了解了inode
的结构,会有助于区分软硬链接
inode
inode 内容
在Linux
系统中,每个文件都有对应的inode
,而inode
作为数据索引的标识符,其中包含了一个文件的基本信息,如inode
编号,修改时间,文件的位置等。所以linux
中不使用文件名,而是使用inode
号来识别文件。
通常打开一个文件的步骤也就被系统大致的拆分为三个步骤:
- 找到目标文件对应的
inode
号 - 通过
inode
号,获取出inode
信息 - 根据获取出的信息,找到文件数据所在的
block
,读取内容
为了更直观得看到inode
的信息,先新建一个文件,使用stat
命令查看inode
相关信息
[root@suhw ~]# touch file.txt
[root@suhw ~]# stat file.txt
File: ‘file.txt’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd00h/64768d Inode: 33575038 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2020-09-27 09:53:29.477000000 +0800
Modify: 2020-09-27 09:53:29.477000000 +0800
Change: 2020-09-27 09:53:29.477000000 +0800
Birth: -
其中较为关键的几个字段说明如下
字段 | 解释 |
---|---|
File | 文件名 |
size | 文件大小 |
Blocks | 文件所占用的块数 |
Device | 文件所在设备号,分别以十六进制和十进制显示 |
Inode | 文件节点号 |
Links | 对应的链接数,有多少个文件名指向该inode (硬链接会增加该值) |
inode 使用情况
inode
也会消耗硬盘空间,所以格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是inode
区,存放inode
所包含的信息。每个inode
的大小,一般是128
字节或256
字节。通常情况下不需要关注单个inode
的大小,而是需要重点关注inode
总数。inode
总数在格式化的时候就确定了。
可以通过df -i
查看inode
使用情况
[root@suhw ~]# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/mapper/centos-root 8910848 26547 8884301 1% /
devtmpfs 998093 369 997724 1% /dev
tmpfs 1001108 1 1001107 1% /dev/shm
tmpfs 1001108 455 1000653 1% /run
tmpfs 1001108 16 1001092 1% /sys/fs/cgroup
/dev/sda1 524288 327 523961 1% /boot
tmpfs 1001108 1 1001107 1% /run/user/0
inode 结构
我们可以简单的将linux
中的文件看做是 **inode
+数据块 **组成。
首先需要了硬盘的最小存储单位叫扇区(Sector)
,每个扇区能存储大小为512字节(0.5KB)
,操作系统在读取硬盘时,不会一个一个扇区读,而是一次读取一个块(block)
, 所以块是文件存取的最小单位。一般常见块的大小为4KB,也就是八个扇区组成的。(以下都默认块大小为4KB)
块大小可以通过如下方式查看,其中IO Block
就说明了当前块大小为4KB。
[root@suhw ~]# stat /boot/|grep "IO Block"
Size: 4096 Blocks: 8 IO Block: 4096 directory
但是inode
是如何访问到数据块的呢,通过下面计算 最大文件大小 的例子来帮助理解
最大文件大小
接下来讨论ext3
文件系统下单个文件所能占用最大空间,有些前提条件需要明确:
ext3
文件系统采用32bit
的块地址索引空间;- 在
inode
条目中,引用一个块空间符号需要4byte
的大小; - 对于一个
inode
来说,设计了12个直接指针索引,一个间接指针索引,一个双间接指针索引,以及一个三间接指针索引。
下图就是inode
的大体结构示意图。可以从图中看出,inode
中除了描述了一些文件相关信息外,最主要的就是维护了与数据库之间的索引关系。
我们目前所用的文件系统可归类为“索引式文件系统”,最简单粗暴的设计就是为一个文件所需要的所有block
建立一个索引表,其中第n个元素就存着第n个块所对应的地址,这样访问任意一个块时,直接索引找到地址进行访问即可。但是当文件很大时,所维护的索引表就会很大,所以有了间接索引表的出现。
间接索引表中有15个索引项,前12个地址存放了12个可直接获取地址访问的直接块,这12个块可保存12*4KB=48KB
的文件;
若文件存储所需大于12个块,就需要建立一个新的一级间接索引表,此时第13个索引就会指向一个新的块,其中存放了4kb / 4bytes = 1024
个块的地址(块大小为4KB
,一个指针大小为4bytes
),通过一级间接索引表,可索引的文件大小已经变为 (1024+12) * 4kb ≈ 4M
若文件大小又超过了1024+12=1036
个块,就又需要第14个索引来指向一个新的块,该块就是所谓的二级间接索引表,存放了1024个一级间接索引表的地址,每个一级简介索引表可以表示4M
的文件,所以如果使用二级间接索引表最多可表示 1024*4M = 4G
大小的文件
同理,当三级间接索引表也使用的时候,最多就可表示 1024*4G = 4T
大小的文件。
结论:ext3
文件系统下,当块大小为4k
得时候,支持的单个文件大小小最大为 4TB
当然通过这个例子也能够简单的了解下inode
是如何访问到对应文件的数据。接下来进入正题。
硬链接
一般情况下,文件名和inode
号码是"一一对应"关系,每个inode
号码对应一个文件名。但是Unix/Linux
系统允许多个文件名指向同一个inode
号码。这意味着,可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所有文件名;但是,删除一个文件名,不影响另一个文件名的访问。这种情况就被称为"硬链接"(hard link)
。
命令
ln
默认创建硬链接:
ln 源文件 目标文件
示例
- 先创建
file.txt
文件观察inode
信息
[root@suhw ~]# stat file.txt
File: ‘file.txt’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd00h/64768d Inode: 33575038 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2020-09-27 09:53:29.477000000 +0800
Modify: 2020-09-27 09:53:29.477000000 +0800
Change: 2020-09-27 09:53:29.477000000 +0800
Birth: -
- 给
file.txt
创建硬链接hardlink
[root@suhw ~]# ln file.txt hardlink
- 分别打印源文件和目标文件的
inode
信息
[root@suhw ~]# stat file.txt
File: ‘file.txt’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd00h/64768d Inode: 33575038 Links: 2
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2020-09-27 09:53:29.477000000 +0800
Modify: 2020-09-27 09:53:29.477000000 +0800
Change: 2020-09-27 15:38:07.529000000 +0800
Birth: -
[root@suhw ~]# stat hardlink
File: ‘hardlink’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd00h/64768d Inode: 33575038 Links: 2
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2020-09-27 09:53:29.477000000 +0800
Modify: 2020-09-27 09:53:29.477000000 +0800
Change: 2020-09-27 15:38:07.529000000 +0800
Birth: -
会发现,添加完硬链接后,只有链接数加了1,剩下的所有内容都保持不变
- 删除源文件,观察硬链接文件
[root@suhw ~]# rm -rf file.txt
[root@suhw ~]# stat hardlink
File: ‘hardlink’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd00h/64768d Inode: 33575038 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2020-09-27 09:53:29.477000000 +0800
Modify: 2020-09-27 09:53:29.477000000 +0800
Change: 2020-09-27 15:42:29.895000000 +0800
Birth: -
此时会发现删除文件,只会将链接数减1,当链接数为0时,系统就会回收对应的block
软链接
软连接就如同windows
中的快捷方式,虽然文件A和文件B的inode
号虽然不一样,但是文件A的内容是文件B的路径。读取文件A时,系统会自动将访问者导向文件B。因此,无论打开哪一个文件,最终读取的都是文件B。这时,文件A就称为文件B的"软链接"(soft link)
或者"符号链接(symbolic link)
。
这意味着,文件A依赖于文件B而存在,如果删除了文件B,打开文件A就会报错:“No such file or directory”。这是软链接与硬链接最大的不同:文件A指向文件B的文件名,而不是文件B的inode
号码,文件B的inode
"链接数"不会因此发生变化。
命令
通过ln -s
命令可以创建软链接。
ln -s 源文文件或目录 目标文件或目录
示例
- 新建
file.txt
并查看inode
信息
[root@suhw ~]# stat file.txt
File: ‘file.txt’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd00h/64768d Inode: 33575038 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2020-09-27 15:49:09.338000000 +0800
Modify: 2020-09-27 15:49:09.338000000 +0800
Change: 2020-09-27 15:49:09.338000000 +0800
Birth: -
- 创建软链接
[root@suhw ~]# ln -s file.txt softlink
- 对比软链接文件和源文件的
inode
信息
[root@suhw ~]# stat file.txt
File: ‘file.txt’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd00h/64768d Inode: 33575038 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2020-09-27 15:49:09.338000000 +0800
Modify: 2020-09-27 15:49:09.338000000 +0800
Change: 2020-09-27 15:49:09.338000000 +0800
Birth: -
[root@suhw ~]# stat softlink
File: ‘softlink’ -> ‘file.txt’
Size: 8 Blocks: 0 IO Block: 4096 symbolic link
Device: fd00h/64768d Inode: 33575039 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2020-09-27 15:49:49.162000000 +0800
Modify: 2020-09-27 15:49:36.821000000 +0800
Change: 2020-09-27 15:49:36.821000000 +0800
Birth: -
会发现创建软链接并不会增加源文件的链接数,并且inode
号也不相同
- 删除源文件,查看软链接文件
[root@suhw ~]# rm -rf file.txt
[root@suhw ~]# cat softlink
cat: softlink: No such file or directory
验证了之前所说的,由于已经删除了源文件,当我们通过软链接再访问源文件时,就会报已经没有对应文件了。
- 在当前目录重新新建
file.txt
,再次打开软链接文件
[root@suhw ~]# touch file.txt
[root@suhw ~]# cat softlink
[root@suhw ~]#
又证实了软链接存储的是目标文件的路径。
补充
通过inode
号删除文件
有时,文件名包含特殊字符,无法正常删除。这时,直接删除inode
节点,就能起到删除文件的作用。
[root@suhw ~]# ll -i
33575038 -rw-r--r--. 1 root root 5 Sep 28 10:53 file.txt
[root@suhw ~]# find ./* -inum 33575038 -delete
此时就会发现通过匹配inode
号我们删除了file.txt
文件