從2.6.16
版本開始,GNU/Linux
引入opeant
系統調用:
#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
代碼則一目了然:
引入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是方便一個進程內的各線程可擁有不同的當前目錄,傳統的chdir會影響整個進程,而使用openat只需要每個線程在初始化時打開一個目錄(調用open),然后就可以以openat在“當前目錄”操作文件了,如:
int dirfd = open("/tmp"); // 相當於chdir到“/tmp”
int filefd = openat(dirfd, "myfile"); // 在/tmp目錄下打開“myfile”文件
用法示例:
#include <stdio.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> void creat_at(char *dir_path, char *relative_path) { int dir_fd; int fd; int flags; mode_t mode; dir_fd = open(dir_path, O_RDONLY); //fd參數是通過打開相對路徑名所在的目錄來獲取。 if (dir_fd < 0) { perror("open"); exit(EXIT_FAILURE); } flags = O_CREAT | O_TRUNC | O_RDWR; mode = 0640; //-rw-r----- fd = openat(dir_fd, relative_path, flags, mode); if (fd < 0) { perror("openat"); exit(EXIT_FAILURE); } write(fd, "HELLO", 5); close(fd); close(dir_fd); } int main() { creat_at("../03.文件IO", "log.txt"); return 0; }
借用dirfd,將DIR*轉換成int類型的文件描述符
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> #include <stdio.h> #include <unistd.h> int main() { DIR *dir; int dirfd2; int fd; int n; dir = opendir("../03.文件IO"); if(NULL == dir) { perror("open dir error"); return -1; } dirfd2 = dirfd(dir); if(-1 == dirfd2) { perror("dirfd error"); return -1; } fd = openat(dirfd2,"output.log",O_CREAT|O_RDWR|O_TRUNC, \
S_IRWXU|S_IRWXG|S_IRWXO); if(-1 == fd) { perror("opeat error"); return -1; } n = write(fd,"Hello world!\n",15); close(fd); closedir(dir); return 0; }
參考資料:
openat(2) – Linux man page
The Linux programming interface
http://blog.csdn.net/wang1902568721/article/details/47796173