Linux 環境編程:dirfd參數 有關解析


背景

在Unix環境編程中,系統提供了很多以at結尾的函數,如openatfstatat等,而這類函數通常有一個特點,就是形參列表中多了int dirfd

例如:

int open(const char *pathname, int flags, mode_t mode);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);

int mkfifo(const char *pathname, mode_t mode);
int mkfifoat(int dirfd, const char *pathname, mode_t mode);

...

意義

dirfd參數的意義:
1)path參數指定為絕對路徑名時,fd會被忽略,openat函數就相當於open函數
2)path參數指定為相對路徑名時,fd參數指出了相對路徑名在文件系統的開始地址。fd參數是通過打開相對路徑名所在的目錄來獲取。所以此時的path是相對於文件描述符dirfd所引用的目錄。
3)path參數指定了相對路徑名,並且fd參數是特殊值AT_FDCWD。在這種情況下,路徑名在當前工作目錄中獲取,openat函數在操作上與open函數類似。

實際上,dirfd參數 實現了 以 文件描述符+相對路徑 作為定位的 一種功能(而不是 當前工作路徑+相對路徑 作為定位)。我們可以參考下文的文檔描述來體會這個功能:

If the pathname given in pathname is relative, then it is interpreted relative to the directory referred to by the file descriptor dirfd (rather than relative to the current working directory of the calling process, as is done by mkfifo() for a relative pathname).
如果pathname中給定的路徑名是相對的,那么它將被解釋為相對於文件描述符dirfd所引用的目錄(而不是相對於調用進程的當前工作目錄)。

用法

用法有兩種,分別說明如下:

1、直接用open打開目錄,用返回值作為openat的第一個參數的值,代碼如下:

#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);
	if (dir_fd < 0) 
	{
		perror("open");
		exit(EXIT_FAILURE);
	}
 
	flags = O_CREAT | O_TRUNC | O_RDWR | O_DIRECTORY;
	mode = 0640;
	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("./open", "log.txt");
	return 0;
}

**2、借用dirfd,將DIR*轉換成int類型的文件描述符 **

#include <sys/types.h>
#include <dirent.h>

int dirfd(DIR *dirp);

完整代碼如下:

#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("./open/chl");
	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);
	if(-1 == fd)
	{
		perror("opeat error");
		return -1;
	}
	n = write(fd,"Hello world!\n",15);
	
	close(fd);
	closedir(dir);
 
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM