views:

358

answers:

2

By using fdopen(), fileno() it's possible to open streams with existing file descriptors. However the proper way to close a file, once you've opened it with a stream is to fclose() the FILE pointer. How can one close the stream, but retain the open file descriptor?

This behaviour is akin to calling fflush() and then fileno(), and then never using the FILE pointer again, except in closing. An additional concern is that if you then fdopen() again, there are now multiple FILE pointers, and you can only close one of them.

+6  A: 

If you're on a POSIXy system (which I assume you are, since you have fileno()), you can use dup() to clone the file descriptor:

int newfd = dup(fileno(stream));
fclose(stream);

Or you can hand fdopen() a duplicate file descriptor:

FILE *stream = fdopen(dup(fd), "r");

Either way, the other copy of the fd won't close with the FILE *. However, keep in mind the location pointer is shared, so be careful if you are using both at the same time.

bdonlan
windows and other platforms support fileno()!i can't believe i didn't think of this dup() solution, very elegant, and obvious
Matt Joiner
Don't you also need to dup2() the new fd back to the original fd and then close() the new fd so everything is back the way it was before, except the file stream is closed? :D Which means you need oldfd = fileno(stream) before you do fclose().
Jonathan Leffler
Jonathan, doing do is racy in multithreaded applications. It's better to `dup` before giving the fd to `fdopen` so you can be sure it never touches your original.
bdonlan
@bdonlan, explain: i don't see how it's racy
Matt Joiner
Thread A: close(42); Thread B: open(...) (returns 42) Thread A: dup2(42, 54); Now thread B's fd has been closed and replaced with whatever thread A was working with.
bdonlan
yeah but that's unavoidable regardless of how you pass the fd around. no threads are introduced between the dup, and fdopen, you just need to make sure that no thread closes it in that time. the code as given above is in no way racy on it's own.
Matt Joiner
+1  A: 

If everything else fails, dup(2) could help.

ndim