从Linux2.6.16开始,引用了openat函数。主要解决两个问题:
- 让线程可以使用相对路径名打开目录中的文件,不再是只能打开当前目录中的文件。同一进程中的所有线程共享当前目录,很难让同一进程中的线程工作在不同目录。
- 避免time-of-check-to-time-of-use(TOCTTOU)错误。如果有两个基于文件的函数调用,并其中一个依赖另一个的结果,这个程序是脆弱的。这两个调用都不是原子操作,在两个函数调用期间,可能文件发生了变化,进而导致影响最终结果。文件系统命名空间中的TOCTTOU错误通常处理那些特权程序降低特权文件的权限控制或通过特权文件打开一个安全漏洞等方式进行。
#include <fcntl.h>
int open(int const char* pathname, int flags);
int open(int const char* pathname,int flags, mode_t mode);
int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
相比之下,openat函数多了一个dirfd参数:
- 如果pathname指定的是绝对路径名。这种情况下,dirfd参数将被忽略,openat函数等同于open函数。
- 如果pathname指定的是相对路径,并且dirfd的值不是AT_FDCWD,pathname则参照dirfd指定的目录下寻找,dirfd可以是当前目录(打开的是当前目录),也可以其他目录。dirfd是通过open函数打开相对路径名所在的目录来获取的。
- 如果pathname指定相对路径名,并且dirfd的值为AT_FDEWD时,相对路径名在当前目录获取(相当于当前目录的相对路径)。
#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); //返回参数dirp所指向的目录文件的文件描述符
if(-1 == dirfd2) //转换失败返回-1.并且设置error变量
{
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); //write 返回实际写入的字符数,失败则返回-1
close(fd);
closedir(dir);
return 0;
}
以上是在学习Unix编程中遇到的open和openat函数的一点笔记,希望大佬们能补充纠正,谢谢。