始于版本2.6.16,Linux内核提供了一系列新的系统调用,在执行与传统系统调用相似任务的同时,还提供了一些附加功能,对某些应用程序非常有用
新 接 口 | 类似的传统接口 | 备 注 |
---|---|---|
faccessat() | access() | 支持 AT_EACCESS 和 AT_SYMLINK_NOFOLLOW 标志 |
fchmodat() | chmod() | |
fchownat() | chown() | 支持 AT_SYMLINK_NOFOLLOW 标志 |
fstatat() | stat() | 支持 AT_SYMLINK_NOFOLLOW 标志 |
linkat() | link() | 支持(始于 Linux 2.6.18)AT_SYMLINK_FOLLOW 标志 |
mkdirat() | mkdir() | |
mkfifoat() | mkfifo() | 基于 mknodat()的库函数 |
mknodat() | mknod() | |
openat() | open() | |
readlinkat() | readlink() | |
renameat() | rename() | |
symlinkat() | symlink() | |
unlinkat() | unlink() | 支持 AT_REMOVEDIR 标志 |
utimensat() | utimes() | 支持 AT_SYMLINK_NOFOLLOW 标志 |
为便于描述这些系统调用,这里就以 openat()为例。
NAME
openat - 打开相对于目录文件描述符的文件
SYNOPSIS
#include <fcntl.h>
int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
openat()系统调用类似于传统的open()系统调用,只是添加了一个dirfd参数,其作用如下:
- 如果pathname中为相对路径名,那么对其解释则以打开文件描述符dirfd所指向目录为参照点,而非进程的当前工作目录
- 如果pathname中为相对路径名,而且dirfd中所含为特殊值AT_FDCWD,那么对 pathname的解释则相对与进程当前工作目录(即与 open(2)行为一致)而言
- 如果 pathname 中为绝对路径,那么将忽略 dirfd 参数、
openat()的 flag 参数目的与 open()相同。还多了一些原本open()不支持的参数:
- AT_SYMLINK_NOFOLLOW :其含义是如果 pathname 为符号链接,那么系统调用将操作于符号
链接本身,而非符号链接所指向的文件。(linkat()系统调用提供了 AT_SYMLINK_FOLLOW 标志,其作用正好相反,即改变 linkat()的默认行为,当 oldpath 属于符号链接时对其进行解引用操作。 - AT_EACCESS :
之所以要支持上表所列的系统调用,其原因有二(此处再以 openat()为例)。
- 当调用open()打开位于当前工作目录之外的文件时,可能会发生某些竞态条件。而使用 openat()就能够避免这一问题。在调用 open()的同时,如果 pathname 目录前缀的某些部分发生了改变,就可能导致竞争。要想避免这类竞态,可以针对目标目录打开一个文件描述符,然后将该描述符传递给 openat()
- 工作目录是进程的属性之一,为进程中所有线程共享。而对于某些应用程序而言,需要针对不同线程拥有不同的“虚拟”工作目录。将 openat()与应用所维护的目录文件描述符相结合,就可以模拟出这一功能
SUSv3 并未对这些系统调用加以规范,但 SUSv4 将其包括在内。为了获得对这些系统调用的声明,必须在包含相应头文件之前(比如定义 open()的<fcntl.h>)将_XOPEN_SOURCE 特性测试宏定义为大于或等于 700 的值。另外,将_POSIX_C_SOURCE 宏的值定义为大于或等于 200809也能收到同样效果。(在 2.10 版本之前的 glibc 中,要获得对这些系统调用的声明还需要定义_ATFILE_SOURCE 宏。)