linux 文件存储原理
在linux系统中,文件存储被分为两部分,用户数据和元数据。
用户数据,即文件数据块,是记录文件真实内容的地方。
元数据则是文件的附加属性,如文件大小、创建时间、所有者等信息。
inode号(即索引节点号)是元数据的一部分,是文件的唯一标致。
这里要区分文件名和inode号的区别。文件名是为了方便用户记忆和使用,而系统是通过inode号寻找正确的文件数据块。
我们可以改通过 stat 查看文件的inode号
[user_00@localhost ~/d1]$ ls
f1 f2 f3
[user_00@localhost ~/d1]$ stat f1
File: ‘f1’
Size: 18 Blocks: 8 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 805903006 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ user_00) Gid: ( 100/ users)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2020-06-11 16:42:05.119863677 +0800
Modify: 2020-06-11 16:41:58.862863004 +0800
Change: 2020-06-12 16:48:12.425140189 +0800
Birth: -
[user_00@localhost ~/d1]$
可以看到 f1 的 Inode 号是 805903006。
那按照上面的原理,我们重命名文件,或者移动文件的话,inode号和用户数据是不会变的。
[user_00@localhost ~/d1]$ mv f1 ../f1.new
[user_00@localhost ~/d1]$ stat ../f1.new
File: ‘../f1.new’
Size: 18 Blocks: 8 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 805903006 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ user_00) Gid: ( 100/ users)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2020-06-11 16:42:05.119863677 +0800
Modify: 2020-06-11 16:41:58.862863004 +0800
Change: 2020-06-12 16:53:45.688176047 +0800
Birth: -
我们可以看到 Inode 没有变,也就是说用户数据的地址是没变的。只有文件目录地址和文件名发生了变化。
硬连接和软连接
为了解决文件共享的问题,linux引入了两种连接方式,硬链接(hard link)和软连接(symbolic link 又称符号连接)。一个inode号对应多个文件的时候,这些文件就称为硬连接。或者说硬链接就是一个文件同时有多个文件名。
硬连接
[user_00@localhost ~/d1]$ ln f1 f1.hlink
[user_00@localhost ~/d1]$ ls
f1 f1.hlink f2 f3 f4
[user_00@localhost ~/d1]$
[user_00@localhost ~/d1]$ stat f1.hlink
File: ‘f1.hlink’
Size: 18 Blocks: 8 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 805903006 Links: 2
Access: (0644/-rw-r--r--) Uid: ( 1000/ user_00) Gid: ( 100/ users)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2020-06-11 16:42:05.119863677 +0800
Modify: 2020-06-11 16:41:58.862863004 +0800
Change: 2020-06-12 17:35:38.830013074 +0800
Birth: -
可以看到 f1.hlink 的 inode 和 f1的 inode 是一样的,仅仅是文件名不一样而已。
由于硬链接是两个文件名对应同一个文件,所以会有一些特性:
- 文件有相同的inode和 data block
- 只能对已有的文件创建
- 删除一个硬链接并不影响其他相同inode号的文件
- 硬链接只能针对文件创建,不能针对目录
- 不能交叉文件系统创建
[user_00@localhost ~/d1]$ ls -li
total 8
805903006 -rw-r--r--. 2 user_00 users 18 Jun 11 16:41 f1
805903006 -rw-r--r--. 2 user_00 users 18 Jun 11 16:41 f1.hlink
805903007 -rw-r--r--. 1 user_00 users 0 Jun 11 16:30 f2
805878680 -rw-r--r--. 1 user_00 users 0 Jun 11 16:30 f3
805939943 -rw-r--r--. 1 user_00 users 0 Jun 12 17:22 f4
具有相同的inode号
[user_00@localhost ~/d1]$ ln f5 f5.hlink
ln: failed to access ‘f5’: No such file or directory
不能对不存在的文件创建
[user_00@localhost ~]$ ln d1 d1.hlonk
ln: ‘d1’: hard link not allowed for directory
可以看到是不予许为目录创建硬链接的。基于linux的文件存储机制,如果我们给目录创建硬链接,系统是检测不出来的,如果形成目录环那程序会陷入死循环。
比如 有目录 d1/a , d2/b b指向d1,a指向d2,那当我们用 find 查找文件的时候,遍历过程会是 d1/a/b/a/b…陷入无限循环
但是系统里缺有两个目录的硬链接,便是 . 和 …
[user_00@localhost ~/d1]$ ls -ail
total 8
805903005 drwxr-xr-x. 2 user_00 users 62 Jun 12 17:35 .
134217792 drwxr-x---. 8 user_00 users 184 Jun 12 17:13 ..
. 和 … 的 inode 号,就是当前目录和上层目录的 inode 号
至于为什么不能交叉文件系统创建就很容易理解了。inode 在同一个文件系统里是唯一的,如果夸文件系统,则会出现相同的inode号对应不同 data block 的情况。这肯定是不对的。
软连接
软连接和硬连接是完全不同的。
软连接是一个新的文件,文件的用户数据块存放的是原文件的路径名。
like this
因此软连接没有硬连接那么多限制:
- 软连接有自己的文件权限和属性
- 可对不存在的文件或目录创建软链接
- 软链接可交叉文件系统
- 软链接可对文件或目录创建
- 创建软链接时,链接计数 i_nlink 不会增加
- 删除软链接并不影响被指向的文件,但若被指向的原文件被删除,则相关软连接被称为死链接(即 dangling link,若被指向路径文件被重新创建,死链接可恢复为正常的软链接)
[user_00@localhost ~/d1]$ ln -s f1 f1.slink
[user_00@localhost ~/d1]$ ls -l
total 8
-rwxrwxrwx. 2 user_00 users 18 Jun 11 16:41 f1
-rwxrwxrwx. 2 user_00 users 18 Jun 11 16:41 f1.hlink
lrwxrwxrwx. 1 user_00 users 2 Jun 15 11:17 f1.slink -> f1
-rw-r--r--. 1 user_00 users 0 Jun 11 16:30 f2
-rw-r--r--. 1 user_00 users 0 Jun 11 16:30 f3
-rw-r--r--. 1 user_00 users 0 Jun 12 17:22 f4
可以看到 ls 命令下,软连接是会明确标识出来的。
我们试着修改下软连接的文件权限
[user_00@localhost ~/d1]$ chmod 600 f1.slink
[user_00@localhost ~/d1]$ ls -l
total 8
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1.hlink
lrwxrwxrwx. 1 user_00 users 2 Jun 15 11:17 f1.slink -> f1
-rw-r--r--. 1 user_00 users 0 Jun 11 16:30 f2
-rw-r--r--. 1 user_00 users 0 Jun 11 16:30 f3
-rw-r--r--. 1 user_00 users 0 Jun 12 17:22 f4
f1 以及自身的硬链接 f1.hlink 文件权限都发生了更改,但是身为软连接的 f1.slink 依然坚挺,并未改变。
那如果我给一个不存在的文件创建软连接呢?
[user_00@localhost ~/d1]$ ln -s f5 f5.slink
[user_00@localhost ~/d1]$ ls -l
total 8
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1.hlink
lrwxrwxrwx. 1 user_00 users 2 Jun 15 11:17 f1.slink -> f1
-rw-r--r--. 1 user_00 users 0 Jun 11 16:30 f2
-rw-r--r--. 1 user_00 users 0 Jun 11 16:30 f3
-rw-r--r--. 1 user_00 users 0 Jun 12 17:22 f4
lrwxrwxrwx. 1 user_00 users 2 Jun 15 11:27 f5.slink -> f5
[user_00@localhost ~/d1]$
[user_00@localhost ~/d1]$ cd f5.slink
-bash: cd: f5.slink: No such file or directory
[user_00@localhost ~/d1]$
[user_00@localhost ~/d1]$ cat f5.slink
cat: f5.slink: No such file or directory
[user_00@localhost ~/d1]$
事实上,可以给一个不存在的目录或者文件创建软连,但是创建的软连是死链接。但是如果软连接的指向被重新创建,那它就复活了,恢复为正常的软连接。神奇吧。
[user_00@localhost ~/d1]$ ls -l
total 12
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1
-rw-------. 2 user_00 users 18 Jun 11 16:41 f1.hlink
lrwxrwxrwx. 1 user_00 users 2 Jun 15 11:17 f1.slink -> f1
-rw-r--r--. 1 user_00 users 0 Jun 11 16:30 f2
-rw-r--r--. 1 user_00 users 0 Jun 11 16:30 f3
-rw-r--r--. 1 user_00 users 0 Jun 12 17:22 f4
-rw-r--r--. 1 user_00 users 11 Jun 15 11:30 f5
lrwxrwxrwx. 1 user_00 users 2 Jun 15 11:27 f5.slink -> f5
[user_00@localhost ~/d1]$
[user_00@localhost ~/d1]$ cat f5.slink
I am live;
我们重新创建了 f5 ,通过软连接也可以顺利找到 f5。
还有一个问题是,软连接是否会导致 links 数增加呢。
有兴趣的朋友自己思考下吧。