从C中的文件描述符中检索文件名


105

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


我猜,应该给zneak选择答案,因为他的解决方案具有更好的可移植性并且没有明显的访问问题。
谢尔盖(Sergei)

它在Ubuntu 14.04(内核3.16.0-76-通用)上不受支持。我猜它在Linux上根本不受支持。
felipou '16

适用于MacOS,看到这个答案由另一个问题D.Nathanael
乔纳森·莱夫勒19/09/24

Answers:


120

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

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


9
只要原始文件仍然具有对它的引用(打开fd就是这样的引用),则无法重用inode编号。关闭文件后或打开文件之前使用inode编号的任何软件本质上都受竞争条件的影响。
R .. GitHub STOP HELPING ICE

3
危险,威尔·罗宾逊!这并不总是有效---如果您做一些setuid()花招,则可能/proc/self/fd无法被您的过程访问。请参阅:permalink.gmane.org/gmane.linux.kernel/1302546
David给出了

2
@bdonlan:如果没有安装/ proc的话?
user2284570

1
@ user2284570,此答案是特定于Linux的。我不知道NetBSD是否完全支持procfs-如果您的共享主机不提供它,那可能是因为NetBSD根本不支持它,而是使用了另一种机制。您可能想发布另一个以NetBSD为重点的问题,看看是否有人知道NetBSD如何公开此信息(您可能还想在下面尝试zneak的答案,OS X与BSD相比,与Linux更相似)
bdonlan 2015年

1
@bdonlan:NetBSD支持/ proc,但不是必须安装它。每次我提到时,答案就变成“转而使用更高成本的提供商,您会获得/ proc的权利”。因此,我正在寻找一种无能为力的解决方案。
user2284570

90

我在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.

因此,要获取与文件描述符关联的文件,可以使用以下代码段:

#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定义,所以我认为PATH_MAX从syslimits可以。


@uchuugaka,可能不是。使用getsockname
zneak

2
你能指望什么?除非它是UNIX套接字,否则它没有文件关联。
zneak 2015年

2
@uchuugaka是的,所有内容都是文件,但并非所有内容都是具有名称和文件系统树内位置的目录条目。文件由索引节点表示,它可以存在而无需任何目录条目引用。
lgeorget 2015年

9
在<sys / param.h>中:#define MAXPATHLEN PATH_MAX
geowar

1
我刚刚对此进行了测试,如果文件被移动并再次调用它,它仍然正确(意味着:您将获得文件的新路径)。但是,这在Linux上不受支持(在Ubuntu 14.04上测试-未定义F_GETPATH)。
felipou


15

正如泰勒(Tyler)指出的那样,由于给定的FD可能对应0个文件名(在各种情况下)或> 1(多个“硬链接”通常是对后一种情况的描述),因此无法“直接且可靠地”执行所需的操作)。如果您仍然需要具有所有限制的功能(在速度上以及获得0、2,...而不是1的可能性),则可以按照以下方法进行操作:首先,fstat将FD告诉您- ,结果struct stat是文件驻留在什么设备上,它具有多少个硬链接,它是否是特殊文件等。这可能已经回答了您的问题-例如,如果您知道0个硬链接,那么实际上没有相应的文件名在磁盘上。

如果统计数据给了您希望,那么您就必须在相关设备上“遍历目录”,直到找到所有硬链接(或者只有第一个硬链接,如果不需要多个,那么任何一个都可以) )。为此,您使用readdir(当然还有opendir&c)以递归方式打开子目录,直到在struct dirent由此收到的inode号中找到与原始目录相同的inode号为止。struct stat(此时您需要的是整个路径,而不仅仅是名称,您需要向后移动目录链以进行重构)。

如果可以接受这种通用方法,但是您需要更详细的C代码,请告诉我们,这将很容易编写(尽管如果它没有用,我宁愿不编写它,即您无法忍受不可避免的缓慢性能或就您的应用而言,有可能获得!= 1个结果;-)。


9

建议您先查看lsof命令的源代码,然后再将清除为不可能。

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


6

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


2

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

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


4
那么我的答案适用。Linux没有执行此操作的功能。Linux(POSIX)文件描述符不一定引用文件,即使它们引用的是inode,也不是文件名。描述符可以指向已删除的文件(因此没有名称,这是制作临时文件的常用方法),也可以指向具有多个名称的索引节点(硬链接)。
Tyler McHenry,2009年

3
尝试看一下lsof源代码。:)那就是我前一段时间自己遇到相同问题时所做的事情。lsof适用于黑魔法和牺牲山羊-您不能希望复制其行为。更具体地说,lsof与linux内核紧密结合,并且不会通过可用于用户域代码的任何API来完成其工作。
泰勒·麦克亨利

27
Linux为此具有不可移植的proc API。确实存在局限性,但说不可能是纯粹的错误。
bdonlan

1
@Tyler-lsof在用户空间中运行。因此,有一个API可供用户代码使用:)
bdonlan

1
@Duck,那里的可移植性可能就是为什么lsof的来源有这么多的黑魔法。每个UNIX变体的功能都不同。确实,Linux proc接口还算不错,但文档很少。
bdonlan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.