04.14 文件系统

软链接(符号链接)

软链接本质上存储了目标文件名,但因为是特殊的文件,我们不能直接用 openat 打开软链接文件并用 read 读取其内容。想要跟踪符号链接,可以向 readlink 系统调用传入软链接文件路径。

openat 尝试读取软链接目标有什么错误?

openat 默认会 follow 符号链接,这不是我们期望的;如果把 flags 设置成 O_RDONLY | O_NOFOLLOW,则会(在遇到软链接文件时)直接打开失败。

Important

不像 openatlstat 和带有 AT_SYMLINK_NOFOLLOW 标志的 fstatat 就能够读取符号链接本身的信息。

Note

AT_SYMLINK_NOFOLLOWAT_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。

大多数系统不支持创建目录的硬链接(... 比较特殊),因为这样可能会造成文件系统循环。

linklinkat

#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 会先跟踪符号链接再创建链接。

unlinkunlinkat

这两个函数用来删除文件。从名字可以看出,删除文件的本质是删除目录项,即链接数量减少 1。如果文件处在具有粘着位的目录中,则还受到粘着位规则规定的删除文件需要的权限限制。

当链接计数为 0,同时没有进程正在使用文件时,文件可以被删除。

如果 unlink 的参数是符号链接文件的路径,则会删除符号链接文件本身,而不是其所指的文件。

Important

除了 unlink 之外,remove 函数也能删除文件。对于普通文件,remove 的作用和 unlink 相同;对于目录,remove 的作用和 rmdir 相同。对于目录而言,rmdir 和简单的 unlink 是有差异的,毕竟很多系统都不允许 link 目录。