从2.6.16
版本开始,GNU/Linux
引入openat
系统调用:
#define _XOPEN_SOURCE 700 /* Or define _POSIX_C_SOURCE >= 200809 */
#include <fcntl.h>
int openat(int dirfd , const char * pathname , int flags , ... /* mode_t mode */);
Returns file descriptor on success, or –1 on error
同open
相比,多了一个dirfd
参数。关于它的用法,参考以下解释:
If pathname specifies a relative pathname, then it is interpreted relative to the directory referred to by the open file descriptor dirfd, rather than relative to the process’s current working directory.
If pathname specifies a relative pathname, and dirfd contains the special value AT_FDCWD , then pathname is interpreted relative to the process’s current working directory (i.e., the same behavior as open(2)).
If pathname specifies an absolute pathname, then dirfd is ignored.
总结起来,如果pathname
是绝对路径,则dirfd
参数没用。如果pathname
是相对路径,并且dirfd
的值不是AT_FDCWD
,则pathname
的参照物是相对于dirfd
指向的目录,而不是进程的当前工作目录;反之,如果dirfd
的值是AT_FDCWD
,pathname
则是相对于进程当前工作目录的相对路径,此时等同于open
。参考kernel
代码则一目了然:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
umode_t, mode)
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(dfd, filename, flags, mode);
}
引入openat
(及其它at
结尾的函数)有以下两个原因:
First, openat() allows an application to avoid race conditions that could occur when using open(2) to open files in directories other than the current working directory. These race conditions result from the fact that some component of the directory prefix given to open(2) could be changed in parallel with the call to open(2). Such races can be avoided by opening a file descriptor for the target directory, and then specifying that file descriptor as the dirfd argument of openat().
Second, openat() allows the implementation of a per-thread “current working directory”, via file descriptor(s) maintained by the application. (This functionality can also be obtained by tricks based on the use of /proc/self/fd/dirfd, but less efficiently.)
参考资料:
openat(2) – Linux man page;
The Linux programming interface。