16

Possible Duplicate:
Getting Filename from file descriptor in C

Is there a simple and (reasonably) portable way of getting the filename from a FILE*?

I open a file using f = fopen(filename, ...) and then pass down f to various other functions, some of which may report an error. I'd like to report the filename in the error message but avoid having to pass around the extra parameter.

I could create a custom wrapper struct { FILE *f, const char *name }, but is there perhaps a simpler way? (If the FILE* wasn't opened using fopen I don't care about the result.)

Community
  • 1
  • 1
nominolo
  • 5,085
  • 2
  • 25
  • 31
  • duplicate http://stackoverflow.com/questions/1188757/getting-filename-from-file-descriptor-in-c – Manuel Salvadores Feb 01 '11 at 12:12
  • 1
    No standard way that I know of; `freopen` will let you change the read/write, and binary/normal mode, but if you want the name for its own sake (say for printing an error message) you're out of luck. – dmckee --- ex-moderator kitten Feb 01 '11 at 12:13
  • Since you are using a system that has a file structure, I doubt that "passing around an extra parameter" even is an issue? What's your reason for not passing it around? Performance? – Lundin Feb 01 '11 at 12:15
  • 1
    I don't think you can - what about files that have multiple names pointing to the same inode? (there is no "canonical" filename in such case, both are equally valid) What about things that are not really files (sockets etc.)? – Piskvor left the building Feb 01 '11 at 12:15
  • 1
    Answered for Linux in http://stackoverflow.com/questions/1188757/getting-filename-from-file-descriptor-in-c (you just use `fileno` to get fd from `FILE*`). That's not very portable, though... – gnud Feb 01 '11 at 12:16
  • Just bite the bullet and pass the filename around... – tdammers Feb 01 '11 at 12:22
  • 1
    NOT a dup 1188757, because this question is about stdio file handles NOT file descriptors. – Nordic Mainframe Feb 01 '11 at 12:23
  • 1
    If it has to be posix-portable, there apparently is [no nice solution][1]. You must also take into account that on many filesystems the same file-system-object (equivalent of "inode" in whatever filesystem) may have multiple names (such as hard links). So rather than getting complicated about this, i'd just save the name. [1]: http://bytes.com/topic/c/answers/836504-possible-get-file-name-file-descriptor-returnedby-low-level-i-o-api-open – sinelaw Feb 01 '11 at 12:29
  • For macOS, see this [answer](https://stackoverflow.com/a/58082106/15168) to another question by [D.Nathanael](https://stackoverflow.com/users/8474738/d-nathanael). – Jonathan Leffler Sep 24 '19 at 16:06

2 Answers2

14

On some platforms (such as Linux), you may be able to fetch it by reading the link of /proc/self/fd/<number>, as so:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
    char path[1024];
    char result[1024];

    /* Open a file, get the file descriptor. */
    FILE *f = fopen("/etc/passwd", "r");
    int fd = fileno(f); 

    /* Read out the link to our file descriptor. */
    sprintf(path, "/proc/self/fd/%d", fd);
    memset(result, 0, sizeof(result));
    readlink(path, result, sizeof(result)-1);

    /* Print the result. */
    printf("%s\n", result);
}

This will, on my system, print out /etc/passwd, as desired.

foz
  • 3,121
  • 1
  • 27
  • 21
davidg
  • 5,868
  • 2
  • 33
  • 51
4

It's a bit difficult, because a FILE* can read/write from a file handle which isn't associated with a named file at all (for example an unnamed pipe or a socket). You can obtain the file handle with fileno() and then there are system specific ways to learn about the file name. Here's a discussion on how to do this under Linux:

Getting Filename from file descriptor in C

and under Windows this isn't much easier either:

http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx (as an extra step here, you use _get_osfhandle() to get the Windows file handle from the c-library file descriptor)

Community
  • 1
  • 1
Nordic Mainframe
  • 28,058
  • 10
  • 66
  • 83