Linux O_PATH文件描述符的语义是什么?

9
Linux 2.6.39引入了O_PATH打开模式,它实际上并没有打开文件(即不创建打开文件描述符),而是提供一个指向未打开目标的句柄文件描述符。它的主要用途是作为*at函数(如openat等)的参数,并且似乎适用于实现先前Linux缺少的POSIX 2008 O_SEARCH功能。但是,我无法找到有关O_PATH确切语义的任何好的文档。我有几个具体的问题:
  1. 在Linux O_PATH文件描述符上可以进行哪些操作?(仅限*at函数?)
  2. O_PATH是否对非目录有用?
  3. 文件描述符如何绑定到基础文件系统对象,如果移动、删除等会发生什么?O_PATH文件描述符是否计算为引用,防止对象在最后一个链接取消链接时被释放?等等。

我本希望使用O_PATH文件描述符来管理通过cap_get_fdcap_set_fd进行的能力。但是这并没有起作用,我收到了一个坏的文件描述符错误。太糟糕了。 - MvG
1
@MvG:你尝试过在 /proc/self/fd/ 条目上使用 cap_get_filecap_set_file 以使用你打开的 O_PATH 文件描述符吗?这似乎是一个解决方法,可以绕过内核所有无法直接使用 O_PATH 文件描述符的问题。而且,该 proc 条目永久钉在 inode 上(虽然它在目录列表中显示为符号链接,但实际上并不是),因此这种方法与直接使用文件描述符一样没有竞争条件。 - R.. GitHub STOP HELPING ICE
@R:由于在我的实际应用中,我拥有读取权限,所以我只需打开文件进行阅读。但还是谢谢你提供的信息。 - MvG
1个回答

7

使用open(directory, O_PATH | O_DIRECTORY)获取的文件描述符不仅对...at()函数有用,而且对fchdir()也有用(自内核版本3.2.23以来,我相信)。

还有一个最近的补丁,用于新系统调用fbind(),它允许非常长的Unix域套接字名称。首先使用mknod(path, mode | S_IFSOCK, (dev_t)0)创建套接字文件,然后使用open(file, O_PATH)打开。因此获得的文件描述符和Unix域套接字描述符将传递给fbind(),以将套接字绑定到路径名上。无论这是否包含在Linux内核中都有待观察 - 尽管即使包含在内核中,也需要几年时间才能依赖其普遍可用性。(作为过长的Unix域套接字名称的解决方法,它会更早地可行。)

我认为O_PATH目前只对目录有用;文件用途可能在未来被发现。除了未来的fbind()或类似的未来系统调用之外,我不知道使用O_PATH打开的文件描述符的任何用途。甚至在3.5.0内核上,fstatvfs()也无法工作。

在Linux中,当最后一个打开的文件描述符关闭时才释放inode(文件内容和元数据)。当删除(取消链接)文件时,您只会删除与inode关联的文件名。因此,一个文件描述符与两个单独的文件系统对象相关联:用于打开对象的名称和所引用的底层inode。名称仅用于路径解析,即在调用open()(或等效函数)时使用。所有数据和元数据都在inode中。

使用O_PATH获取的文件描述符在移动和重命名用于打开描述符的名称或名称组件方面表现得与普通文件描述符相同(至少在内核3.5.0上是这样)。 (描述符保持有效,因为它引用inode,并且文件名对象仅在路径解析期间使用。保持描述符打开将保持inode资源分配,即使描述符以O_PATH打开。)


1
你错过的一个文件用途是,O_PATH 可以提供 O_EXEC,即使你没有读取文件的权限,fd=open("my_prog", O_PATH); snprintf(buf, sizeof buf, "/proc/self/fd/%d", fd); execl(fd, "my_prog", (char *)0); 也可以执行 my_prog - R.. GitHub STOP HELPING ICE
@R.. 没错,很好的发现。我也不记得检查过是否可以在这些描述符上获得文件租约。如果可以的话,那将是另一个用途。(你的片段中有一个拼写错误:应该是execl(buf, "my_prog", (char *)0);, 我想。) - Nominal Animal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接