6
FILE * fd = fopen ("/tmp/12345","wb");

If I have the variable fd , how can I print the file path ? (/tmp/12345) in Linux env.

joif doi
  • 181
  • 1
  • 2
  • 10
  • Possible duplicate of [Retrieve filename from file descriptor in C?](https://stackoverflow.com/q/1188757/608639), [How do I find a filename, given a FILE pointer?](https://stackoverflow.com/q/11221186/608639), [Is there a way to get the filename from a `FILE*`?](https://stackoverflow.com/q/4862327/608639), etc. – jww Sep 24 '19 at 15:08
  • Note that the [answer](https://stackoverflow.com/a/58082106/15168) by [D.Nathanael](https://stackoverflow.com/users/8474738/d-nathanael) for macOS is not represented in the other answers (though I've now left a comment pointing to it in each of the three questions). – Jonathan Leffler Sep 24 '19 at 16:05

3 Answers3

7

You can't. Not with just standard C.

On Linux you can do:

#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>


int print_filename(FILE *f)
{
    char buf[PATH_MAX];
    char fnmbuf[sizeof "/prof/self/fd/0123456789"];
    sprintf(fnmbuf,"/proc/self/fd/%d", fileno(f));
    ssize_t nr;
    if(0>(nr=readlink(fnmbuf, buf, sizeof(buf)))) return -1;
    else buf[nr]='\0';
    return puts(buf);
}

int main(void)
{
    FILE * f = fopen ("/tmp/12345","wb");
    if (0==f) return EXIT_FAILURE;
    print_filename(f);

}
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • 3
    Beware: [`readlink()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html) does not null terminate the string. You need to capture the value it returns (the length of the byte array containing the name) and put the null terminator in place before passing what is now a string to `puts()`. – Jonathan Leffler Sep 24 '19 at 14:06
6

Since MacOS don't have /proc, fcntl is a good alternative for fetching a file descriptor's path!

Here's a working example:

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

char filePath[PATH_MAX];
if (fcntl(fd, F_GETPATH, filePath) != -1)
{
    printf("%s", filePath);
}

But it works only on MacOS, for Linux PSkocik's solution using readlink seems to be the best answer.

Nathanael Demacon
  • 1,169
  • 7
  • 19
  • 2
    Interesting! Not standardized by POSIX, though ([`fcntl()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html)). – Jonathan Leffler Sep 24 '19 at 14:07
  • Nice solve for MacOS. But it doesn't work on Linux. At least none of my linux glibcs' fcntl.h defines F_GETPATH. – Petr Skocik Sep 24 '19 at 14:13
  • Oh yeah, I'm surprised! Seems like it has been given a patch but wasn't implemented: https://lwn.net/Articles/277736/ -- I'll edit my answer to give a linux answer with the macos one – Nathanael Demacon Sep 24 '19 at 14:18
  • This also applies to FreeBSD (all *BSD actually) where `procfs` is not enabled by default. – rustyx Sep 15 '20 at 14:22
5

There's no standard way to retrieve a pathname from a FILE * object, mainly because you can have streams that aren't associated with a named file (stdin, stdout, stderr, pipes, etc.). Individual platforms may supply utilities to retrieve a path from a stream, but you'd have to check the documentation for that platform.

Otherwise, you're expected to keep track of that information manually.

John Bode
  • 119,563
  • 19
  • 122
  • 198