前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >openat与open的区别及用法示例(dfd)

openat与open的区别及用法示例(dfd)

作者头像
Laikee
发布2022-04-25 14:53:58
6680
发布2022-04-25 14:53:58
举报
文章被收录于专栏:Laikee Tech SpaceLaikee Tech Space

从2.6.16版本开始,GNU/Linux引入opeant系统调用:

代码语言:javascript
复制
#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在“当前目录”操作文件了,如:

代码语言:javascript
复制
int dirfd = open("/tmp"); // 相当于chdir到“/tmp”
int filefd = openat(dirfd, "myfile"); // 在/tmp目录下打开“myfile”文件 

用法示例:

代码语言:javascript
复制
#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类型的文件描述符

代码语言:javascript
复制
#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;  

}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-07-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档