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 目录。