04.14 文件系统
软链接(符号链接)
软链接本质上存储了目标文件名,但因为是特殊的文件,我们不能直接用 openat
打开软链接文件并用 read
读取其内容。想要跟踪符号链接,可以向 readlink
系统调用传入软链接文件路径。
用 openat
尝试读取软链接目标有什么错误?
openat
默认会 follow 符号链接,这不是我们期望的;如果把 flags
设置成 O_RDONLY | O_NOFOLLOW
,则会(在遇到软链接文件时)直接打开失败。
Important
不像 openat
,lstat
和带有 AT_SYMLINK_NOFOLLOW
标志的 fstatat
就能够读取符号链接本身的信息。
Note
AT_SYMLINK_NOFOLLOW
和 AT_SYMLINK_FOLLOW
两个宏都是有定义的,而且它们处在不同的位!
似乎没有通过软链接本身的 fd 获得软链接目标的系统调用?给 openat
传入 O_PATH | O_NOFOLLOW
的确可以得到一个不会跟踪的、没有打开文件的、只能标识文件位置的 fd,但是获取这样的 fd 就需要文件路径作为参数,所以可能没有必要设计这样的一个系统调用?
Note
在我的 WSL 上,O_PATH
没有被定义,需要使用 __O_PATH
。
硬链接(链接)
文件系统中的链接说的是硬链接,使用 stat
结构的 st_nlink
成员记录。硬链接不能跨文件系统。
任何一个叶目录的链接数都是 2。多出来的这一个链接是由于它的目录项中的 .
,即本目录目录项。
/data/apue $ mkdir d
/data/apue $ cd d
/data/apue/d $ ls -al
total 8
drwxr-xr-x 2 <USER> <USER> 4096 May 14 14:50 .
drwxr-xr-x 6 <USER> <USER> 4096 May 14 14:50 ..
/data/apue/d $ mkdir b
/data/apue/d $ ls -al
total 12
drwxr-xr-x 3 <USER> <USER> 4096 May 14 14:50 .
drwxr-xr-x 6 <USER> <USER> 4096 May 14 14:50 ..
drwxr-xr-x 2 <USER> <USER> 4096 May 14 14:50 b
还可以看到 ..
这个上一级目录的目录项也是真实存在的,因为创建新的子文件夹之后,d 文件夹的链接计数增加了 1。
大多数系统不支持创建目录的硬链接(.
和 ..
比较特殊),因为这样可能会造成文件系统循环。
link
和 linkat
#include <unistd.h>
int link(const char *oldpath, const char *newpath);
#include <fcntl.h> /* Definition of AT_* constants */
#include <unistd.h>
int linkat(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath, int flags);
linkat
默认不会跟踪符号链接,因此如果 oldpath
对应符号链接文件,就会创建符号链接文件本身的链接。使用 AT_SYMLINK_FOLLOW
这个标志时,linkat
会先跟踪符号链接再创建链接。
unlink
和 unlinkat
这两个函数用来删除文件。从名字可以看出,删除文件的本质是删除目录项,即链接数量减少 1。如果文件处在具有粘着位的目录中,则还受到粘着位规则规定的删除文件需要的权限限制。
当链接计数为 0,同时没有进程正在使用文件时,文件可以被删除。
如果 unlink
的参数是符号链接文件的路径,则会删除符号链接文件本身,而不是其所指的文件。
Important
除了 unlink
之外,remove
函数也能删除文件。对于普通文件,remove
的作用和 unlink
相同;对于目录,remove
的作用和 rmdir
相同。对于目录而言,rmdir
和简单的 unlink
是有差异的,毕竟很多系统都不允许 link
目录。