How to get a file's name from FILE* struct in C - c

Is it possible to retrieve a file's name in C? If a file is created like the following:
FILE *f = fopen ("foo.txt", "r");
And the "foo.txt" comes from a variable out of scope. Is there a way to retrieve it from the FILE struct?

You can't in fact retrieve the file names from your FILE objects.
However, if the name being passed to fopen is important to you, and that variable is out of scope for whatever reason, you could always wrap a FILE* in a struct, ie.
struct file_with_name {
FILE *f;
char *name; /* OR char name[MAX] */
}
At least that's what I'd do but it depends on what you're actually trying to do.

Unfortunately, on many systems a filename is just a pointer to an inode. And if those filesystems support hard links, that means that there are multiple filenames per real file. Also, you can open a file and then remove the file in which case there wouldn't even be a filename, just a descriptor. For these reasons, you can't go from a file descriptor to a file name.

Its not possible to get the filename out of a FILE handle. You should store the filename yourself if you later need to use it.

Since FILE objects may be created from things that have no name associated with them (in particular, from a raw file descriptor with fdopen()), they do not always have a name to get.

In general, it's not possible. The closest you can try, on Linux, is:
char buf[PATH_MAX];
snprintf(buf, sizeof buf, "/proc/self/fd/%d", fileno(f));
readlink(buf, buf, sizeof buf);
Reusing buf like that is horribly ugly, but as far as I can tell, it's legal and not undefined behavior per POSIX.

Related

What are the advantages of using fstat() vs stat()?

If I have an open file with a known file descriptor, what are the advantages of using fstat(), versus stat()? Why isn't there only one function?
int fstat(int fildes, struct stat *buf)
int stat(const char *path, struct stat *buf)
As noted, stat() works on filenames, while fstat() works on file descriptors.
Why have two functions for that?
One factor is likely to be convenience. It's just nice to be able to fstat() a file descriptor that you obtained from other parts of your code, without having to pass the filename too.
The major reason is security, though. If you first stat() the file and then open() it, there is a small window of time in between where the file could have been modified (or had its permissions changed, etc) or replaced with a symlink.
fstat() avoids that problem. You first open() the file, then the file can't be swapped out beneath your feet any more. Then you fstat() and you can be sure that you have the right file.
fstat is to be used with a file descriptor obtained via the open call. Its main feature is to get information on already opened file descriptors instead of reopening.
You can also use fstat with FILE handlers like so (error handling omitted):
FILE *fp = fopen("/path/to/file", "r");
struct stat st;
fstat(fileno(fp), &st);
If you have a file descriptor, you do not necessarily know the path (e.g. when the file was opened by some other part of your application).
If you know the path, you do not need to call open to get a file descriptor just for the purpose of calling fstat.
If you look at man fstat, you will see the following:
fstat() is identical to stat(), except that the file to be stat-ed is
specified by the file descriptor fd.
To expand a little bit, you would use fstat if you happened to have a file descriptor instead of a file path.
With respect to information provided by the function, they are literally identical, as you can see from the above quote.
If you only have a file descriptor to a file (but you may not know its path), then you could use fstat(); if you only have a path to a file, then you could use stat() directly, no need to open it first.

Need way to share file pointer between source files in C

I made a this file pointer in my code that should contain my log.txt file's address:
FILE *log
This address depends on the argv[1] from my main.c function, it could be something like this:
char address[200];
strcpy(address, argv[1]);
FILE *log;
log = fopen(address, "w");
I need the address pointed by *log to be visible in all my .c source files, because they will have some lines like this:
fprintf(log, "Comment to be printed on log.txt");
I know it's a bad way to make a log file, but my program is big enough so that changing all the log printing lines will take a considerable amount of time.
The file's address has to be defined using argv[1]. How do I define it before my functions can use it (And how do I make them identify it)?
Define log as a global variable, and declare it as external symbol by extern FILE *log; in other places that you use it.

Is it possible to recreate a file from an opened file descriptor?

Now, this question may seem weird, and it probably is, but to give some context, I've been reading this to learn about i-nodes in which the author gives an interesting example:
{
FILE *fp;
fp = fopen("some.hidden.file","w");
unlink("some.hidden.file"); /* deletes the filename part */
/* some.hidden.file no longer has a filename and is truly hidden */
fprintf(fp,"This data won't be found\n"); /* access the data part */
/*etc*/
fclose(fp); /* finally release the data part */
}
This allows to create a "hidden" temporary file.
My question here being: is there any way to recreate a filename that points to the inode held opened by fp after the call to unlink()?
Disclaimer: I do not intend to do this in real code; I'm merely (re)learning about i-nodes and wonder if this is possible.
I'm afraid it is not possible because the link system call demands a valid file name (which means, an existing link) rather than an UNIX file descriptor. There is no flink function in the Single UNIX Specification.

Retrieving the name of the file that is associated with a file pointer

Assume I have a file pointer FILE* myfile. Is there a way to retrieve the name of the file where myfile is reading from or writing to?
Not in any CRT implementation that I've ever seen. It is useless info, you already have to supply the file name to get a FILE*. You could probably dig an operating system handle out of the FILE structure although you might need to hop through a file descriptor table. Your next problem is then the operating system support you'd need to map a file handle back to a file name. That should be difficult too.
I found a nice example that uses an overwritten struct MyFile:
How to get filename from a FILE*

How do you get the filename of a tempfile to use in Linux?

Let's say I'm creating a program in C that needs to use a tempfile. Creating an ad hoc tempfile in /tmp is probably not a good idea. Is there a function or OS call to supply me with a tempfile name so that I can begin to write and read from it?
You can use the mkstemp(3) function for this purpose. Another alternative is the tmpfile(3) function.
Which one of them you choose depends on whether you want the file to be opened as a C library file stream (which tmpfile does), or a direct file descriptor (mkstemp). The tmpfile function also deletes the file automatically when you program finishes.
The advantage of using these functions is that they avoid race conditions between determining the unique filename and creating the file -- so that two programs won't try to create the same file at the same time, for example.
See the man pages for both functions for more details.
The question is how to generate a temporary file name. Neither mkstemp nor tmpfile provide the caller with a name, they return a file descriptor or file handle, respectively.
#garethm:
I believe that the function you're looking for is called tmpnam.
You should definitely not use tmpnam. It suffers from the race condition problem I mentioned in my answer: Between determining the name and opening it, another program may create the file or a symlink to it, which is a huge security hole.
The tmpnam man page specifically says not to use it, but to use mkstemp or tmpfile instead.
Absolutely: man mkstemp.
The man page has example usage.
Not sure about anything in a C lib, but you can do this at the shell with mktemp.
You should use the mkstemp() as this is the recommended function, but it returns a file descriptor, so once you have the descriptor get it's name:
int fd;
fd = mkstemp("hdrXXXXXX);
/* 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);
usually there's no need to actually make a named file; instead use the file descriptor path,
FILE *tmp=tmpfile();
char path[PATH_MAX+1]={0};
sprintf(path, "/dev/fd/%d", fileno(tmp));
printf("%s\n", path);

Resources