What I want:
void printFname(FILE * f)
{
char buf[255];
MagicFunction(f,buf);
printf("File name: %s",buf);
}
So, all I need is “MagicFunction”, but unfortunatelly I haven’t found such …
Is there any way to implement using an OS library? (windows.h , cocoa.h, posix.h etc.)
There is no such function. There may be no filename, or more than one filename that correspond with the
FILE *. On Unix, a program can continue to have a reference to a file after it has been renamed or deleted, which could mean that you have aFILE *with no name. Or more hard links may be made to the file, which means a file can have multiple names; which one would you choose? To further confuse things, a file can be temporarily hidden, by mounting a filesystem over a directory containing that file. The file will still be on disk, at its original pathname, but the file will be inaccessible at that path because the mount is obscuring it.It’s also possible that the
FILE *never corresponded to a file on the filesystem at all; while they usually do, you can create one from any file descriptor usingfdopen(), and that file descriptor may be a pipe, socket, or other file-like object that has never had a path on the disk. In some versions of the C library, you can open a string stream (for instance,fmemopen()in glibc), so theFILE *actually just corresponds to a memory buffer.If you care about the name, it’s best to just keep track of what it was named when you opened the file.
There are some hacky ways to approximate getting the filename; if you’re just using this for debugging or informational purposes, then they may be sufficient. Most of these will require operating on the file descriptor rather than the
FILE *, as the file descriptor is the lower level way of referring to a file. To get the file descriptor, runfileno()on theFILE *, and remember to check for errors in case there is no file descriptor associated with thatFILE *.On Linux, you can do
readlink()on"/proc/self/fd/fileno"wherefilenois the file descriptor. That will show you what filename the file had when the file was opened, or a string indicating what other kind of file descriptor it is, like a socket or inotify handle. FreeBSD and NetBSD have Linux emulation layers, which include emulation of Linux-style procfs; you may be able to do this on those if you mount a Linux-compatible procfs, though I don’t have them available for testing.On Mac OS X, you don’t have
/proc/self/fd. If you don’t care about finding the original filename, but some other filename that refers to the file would work (such that you could pass it to another program), you can construct one:/.vol/deviceid/inode. For example,/.vol/234881030/281363. To get those values, runfstat()on the file descriptor, and usest_devandst_inoon the resultingstruct stat.On Windows, files and the filesystem work quite differently than Unix. Apparently it’s possible to map a file back to its name on Windows. As of Windows Vista, you can simply call
GetFinalPathNameByHandle(). This takes aHANDLE; to get theHANDLEfrom the file descriptor, call_get_osfhandle(). Prior to Windows Vista, you need to do a little more work, as described in this article. Note that on Windowsfileno()is named_fileno(), though the former may work with a warning.Going even further into hacky territory, there are a few more techniques that you could use. You could shell out to
lsof, or you could extract the code it uses to resolve pathnames.lsofactually looks directly in kernel memory, extracting information from the kernel’s name cache. This has several limitations, outlined in thelsofFAQ. And of course, you need root or equivalent privileges to do this, either directly or with an suid/sgid binary.And finally, for a portable but slow solution for finding one or more filenames matching an open file, you could find the device and inode number using
fstat()on the file descriptor, and then recursively traverse the filesystemstat()ing every file, until you find a file with matching device and inode number. Remember the caveats I mention above; you may find no matching files, more than one matching file, and even if you don’t find any matching files, the file might still be there, but hidden by a mount point. And of course, there may be race conditions; something may rename the file in such a way that you never see it while traversing the hierarchy.