【问题标题】:Retrieve filename from file descriptor in C从C中的文件描述符中检索文件名
【发布时间】:2010-11-14 09:31:09
【问题描述】:

是否可以在 C 中获取文件描述符 (Linux) 的文件名?

【问题讨论】:

  • 我想,选择的答案应该交给zneak,因为他的解决方案具有更好的可移植性并且没有明显的访问问题。
  • Ubuntu 14.04(内核 3.16.0-76-generic)不支持。我猜它在 Linux 上根本不支持。
  • 对于 macOS,请参阅answerD.Nathanael 的另一个问题。

标签: c linux file file-descriptor


【解决方案1】:

您可以在/proc/self/fd/NNN 上使用readlink,其中NNN 是文件描述符。这将为您提供文件打开时的名称——但是,如果文件从那时起被移动或删除,它可能不再准确(尽管 Linux 在某些情况下可以跟踪重命名)。要验证,stat 给定的文件名和 fstat 你拥有的 fd,并确保 st_devst_ino 相同。

当然,并不是所有的文件描述符都指向文件,对于那些你会看到一些奇怪的文本字符串,例如pipe:[1538488]。由于所有真实文件名都是绝对路径,因此您可以很容易地确定哪些是绝对路径。此外,正如其他人所指出的,文件可以有多个指向它们的硬链接——这只会报告打开它的那个。如果您想查找给定文件的所有名称,您只需遍历整个文件系统。

【讨论】:

  • 只要原始文件仍然有对它的引用(打开的fd 就是这样的引用),inode 号不能被重用。任何在关闭文件后或打开文件之前使用 inode 编号的软件本质上都会受到竞争条件的影响。
  • 危险,威尔罗宾逊!这并不总是有效 --- 如果您使用 setuid() 技巧,您的进程可能无法访问 /proc/self/fd。见:permalink.gmane.org/gmane.linux.kernel/1302546
  • @bdonlan : 如果 /proc 没有挂载?
  • @user2284570,这个答案是 Linux 特定的。我不知道 NetBSD 是否完全支持 procfs - 如果您的共享主机不提供它,可能是因为 NetBSD 根本不支持它,而是使用了另一种机制。您可能想发布另一个关注 NetBSD 的问题,看看是否有人知道 NetBSD 如何公开此信息(您可能还想尝试下面 zneak 的回答,OS X 与 BSD 相比更类似于 Linux)
  • @bdonlan : NetBSD 支持 /proc 但不是强制安装它。每次我提到的时候,答案都变成了“切换到成本更高的提供商,你会得到 /proc”。所以我正在寻找一个无过程的解决方案。
【解决方案2】:

我在 Mac OS X 上遇到了这个问题。我们没有/proc 虚拟文件系统,因此接受的解决方案无法工作。

相反,我们有一个F_GETPATH 命令用于fcntl

 F_GETPATH          Get the path of the file descriptor Fildes.  The argu-
                    ment must be a buffer of size MAXPATHLEN or greater.

所以要获取关联到文件描述符的文件,可以使用这个sn-p:

#include <sys/syslimits.h>
#include <fcntl.h>

char filePath[PATH_MAX];
if (fcntl(fd, F_GETPATH, filePath) != -1)
{
    // do something with the file path
}

由于我不记得 MAXPATHLEN 是在哪里定义的,我认为来自 syslimits 的 PATH_MAX 会很好。

【讨论】:

  • @uchuugaka,可能不是。使用getsockname
  • 你期待什么?除非它是 UNIX 套接字,否则它没有关联的文件。
  • @uchuugaka 是的,一切都是文件,但并非一切都是文件系统树中具有名称和位置的目录条目。一个文件由一个 inode 表示,它可以在没有任何目录条目引用它的情况下存在。
  • 中:#define MAXPATHLEN PATH_MAX
  • 我刚刚对此进行了测试,如果文件被移动并且您再次调用它(意思是:您获得文件的新路径),它仍然是正确的。但是,这在 linux 上不受支持(在 Ubuntu 14.04 上测试 - 未定义 F_GETPATH)。
【解决方案3】:

在 Windows 中,使用GetFileInformationByHandleEx,传递FileNameInfo,可以检索文件名。

【讨论】:

    【解决方案4】:

    正如 Tyler 指出的那样,没有办法“直接可靠地”执行您需要的操作,因为给定的 FD 可能对应于 0 个文件名(在各种情况下)或 > 1(多个“硬链接”是后一种情况一般描述)。如果您仍然需要具有所有限制的功能(速度和获得 0、2、... 结果而不是 1 的可能性),您可以这样做:首先,fstat FD -- 这个在生成的struct stat 中告诉您文件所在的设备、它有多少硬链接、是否是特殊文件等。这可能已经回答了您的问题——例如如果 0 硬链接你会知道实际上磁盘上没有对应的文件名。

    如果统计数据给了您希望,那么您必须在相关设备上“遍历目录树”,直到找到所有硬链接(或者只找到第一个,如果您不需要多个硬链接)一个会做)。为此,您使用readdir(当然还有opendir &c)递归地打开子目录,直到您在struct dirent 中找到因此收到与原始struct stat 中相同的inode 编号(此时如果您想要整个路径,而不仅仅是名称,您需要向后遍历目录链以重建它)。

    如果这种通用方法可以接受,但您需要更详细的 C 代码,请告诉我们,写起来不难(虽然我宁愿不写,如果它没用,即您无法承受不可避免的慢性能或为您的应用程序获得 != 1 个结果的可能性;-)。

    【讨论】:

      【解决方案5】:

      在将其写成不可能之前,我建议您查看lsof 命令的源代码。

      可能有一些限制,但 lsof 似乎能够确定文件描述符和文件名。此信息存在于 /proc 文件系统中,因此应该可以从您的程序中获取。

      【讨论】:

        【解决方案6】:

        您可以使用 fstat() 通过 struct stat 获取文件的 inode。然后,使用 readdir() 您可以将找到的 inode 与目录中存在的 inode (struct dirent) 进行比较(假设您知道该目录,否则您将不得不搜索整个文件系统)并找到相应的文件名。 讨厌吗?

        【讨论】:

          【解决方案7】:

          不可能。一个文件描述符在文件系统中可能有多个名称,也可能根本没有名称。

          编辑:假设您正在谈论一个普通的旧 POSIX 系统,没有任何特定于操作系统的 API,因为您没有指定操作系统。

          【讨论】:

          • 那么我的回答适用。 Linux 没有工具可以做到这一点。 Linux(POSIX)文件描述符不一定引用文件,即使它们引用索引节点,而不是文件名。描述符可以指向已删除的文件(因此没有名称,这是制作临时文件的常用方法),也可以指向具有多个名称的 inode(硬链接)。
          • 尝试查看 lsof 源代码。 :) 前段时间我自己也有同样的问题时,我就是这么做的。 lsof 适用于黑魔法和祭祀山羊——你不能希望复制它的行为。更具体地说,lsof 与 linux 内核紧密耦合,并且不会通过任何可用于用户级代码的 API 来完成它所做的事情。
          • Linux 为此提供了一个不可移植的 proc API。确实有限制,但说不可能是完全错误的。
          • @Tyler - lsof 在用户空间中运行。因此,对于用户态代码可用的任何功能都有一个 API :)
          • @Duck,那里的可移植性可能是 lsof 的源代码有这么多黑魔法的原因;每个 UNIX 变体都有不同的做法。 linux proc 接口还不错,真的,alebit 文档很少。
          猜你喜欢
          • 2012-07-18
          • 1970-01-01
          • 2012-12-01
          • 2010-09-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-14
          相关资源
          最近更新 更多