【发布时间】:2025-12-05 12:10:01
【问题描述】:
我从 fanotify 接收文件系统事件。有时我想获取正在访问的文件的绝对路径。
通常,这不是问题 - fanotify_event_metadata 包含文件描述符 fd,因此我可以在 /proc/self/fd/<fd> 上调用 readlink 并获取我的路径。
但是,如果路径超过PATH_MAX,则无法再使用readlink - 它会以ENAMETOOLONG 失败。我想知道在这种情况下是否有办法获取文件路径。
显然,我可以fstat 从 fanotify 获得的描述符并遍历整个文件系统以查找具有相同设备 ID 和 inode 号的文件。但是这种方法在性能方面对我来说是不可行的(即使我优化它以忽略比PATH_MAX 短的路径)。
我尝试通过使用O_PATH 重新打开fd 并调用openat(fd, "..", ...) 来获取父目录。显然,这失败了,因为fd 没有引用目录。我还尝试在 readlink 调用失败后检查缓冲区的内容(希望它包含部分路径)。那也没用。
到目前为止,我已经设法在打开它们的进程的工作目录中获取文件的长路径(fanotify 事件包含目标进程的pid,因此我可以读取/proc/<pid>/cwd 并获取路径从那里的根)。但这是部分解决方案。
有没有一种方法可以在不遍历整个文件系统的情况下从文件描述符中获取绝对路径?最好是适用于内核 2.6.32/glibc 2.11 的那个。
更新:对于好奇的人。我已经弄清楚为什么使用足够大的缓冲区来存储整个路径的调用 readlink("/proc/self/fd/<fd>", ... 不起作用。
看do_proc_readlink的实现。请注意,它不直接使用提供的buffer。相反,它会分配一个页面,并在调用d_path 时将其用作临时缓冲区。换句话说,无论buffer 有多大,d_path 总是会被限制在一个页面的大小。在 amd64 上是 4096 字节。同PATH_MAX! -ENAMETOOLONG 本身在用完提到的页面时由prepend 返回。
【问题讨论】:
-
没有链接和/或
./..元素的最终解析路径是否比PATH_MAX长?如果没有,realpath()可能适合您:man7.org/linux/man-pages/man3/realpath.3.html -
路径不应该比
PATH_MAX字符短吗?这听起来很奇怪。 -
@AndrewHenle,
realpath首先需要一条路径。我只有一个文件描述符和一个 PID。 -
@unwind 不。我不能代表所有文件系统,但在 ext4 之类的系统上,您几乎可以继续创建嵌套目录,直到 inode 用完为止。
-
@NikitaKakuev
realpath首先需要一条路径。readlink()也是如此。你是如何让那个工作的?