I receive filesystem events from fanotify. Sometimes I want to get an absolute path to a file that's being accessed.
Usually, it's not a problem - fanotify_event_metadata
contains a file descriptor fd
, so I can call readlink
on /proc/self/fd/<fd>
and get my path.
However, if a path exceeds PATH_MAX
readlink
can no longer be used - it fails with ENAMETOOLONG
. I'm wondering if there's a way to get a file path in this case.
Obviously, I can fstat
the descriptor I get from a fanotify and traverse the entire filesystem looking for files with identical device ID and inode number. But this approach is not feasible for me performance-wise (even if I optimize it to ignore paths shorter than PATH_MAX
).
I've tried getting a parent directory by reopening fd
with O_PATH
and calling openat(fd, "..", ...)
. Obviously, that failed because fd
doesn't refer to a directory. I've also tried examining contents of a buffer after a failed readlink
call (hoping it contains partial path). That didn't work either.
So far I've managed to get long paths for files inside the working directory of a process that opened them (fanotify events contain a pid
of a target process, so I can read /proc/<pid>/cwd
and get the path to the root from there). But that is a partial solution.
Is there a way to get an absolute path from a file descriptor without traversing the whole filesystem? Preferably the one that will work with kernel 2.6.32/glibc 2.11.
Update: For the curious. I've figured out why calling readlink("/proc/self/fd/<fd>", ...
with a buffer large enough to store the entire path doesn't work.
Look at the implementation of do_proc_readlink. Notice that it doesn't use provided buffer
directly. Instead, it allocates a single page and uses it as a temporary buffer when it calls d_path. In other words, no matter how large is buffer
, d_path
will always be limited to a size of a page. Which is 4096 bytes on amd64. Same as PATH_MAX
! The -ENAMETOOLONG
itself is returned by prepend when it runs out of mentioned page.
You can use readlink on /proc/self/fd/NNN where NNN is the file descriptor. This will give you the name of the file as it was when it was opened — however, if the file was moved or deleted since then, it may no longer be accurate (although Linux can track renames in some cases).
> {PATH_MAX} Maximum number of bytes in a pathname, including the terminating null character.
The maximum number of bytes for a file name and file path when combined is 6255. However, the file name itself cannot exceed 255 bytes. Furthermore, directory names (including the directory delimiter) within a path are limited to 255 bytes.
An absolute path always contains the root element and the complete directory list required to locate the file. For example, /home/sally/statusReport is an absolute path. All of the information needed to locate the file is contained in the path string.
readlink
can be used with a link target that's longer than PATH_MAX
. There are two restrictions: the name of the link itself must be shorter than PATH_MAX
(check, "/proc/self/fd/<fd>"
is about 20 characters) and the provided output buffer must be large enough. You might want to call lstat
first to figure out how big the output buffer should be, or just call readlink
repeatedly with growing buffers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With