Close file in C - c

Under Linux I use this code to redirect stdout and stderr on a file, as shown in the code the file is opened using fopen(f) and is it closed using close(fd).
int fd;
FILE *f;
f = fopen("test.txt", "rb+");
fd = fileno(f);
dup2(fd,STDOUT_FILENO);
dup2(fd,STDERR_FILENO);
close(fd);
My question is whether the close(fd) statement closes all file descriptors, or is it necessary to use fclose(f) as well ?

The rule is to close the outermost level. Here the FILE object pointed to by f contains the fd file handle but also internal data like a possible buffer and various pointers to it.
When you use close(fd), you free the kernel structures related to the file, but all the data structures provided by the standard library are not released. On the other hand, fclose(f) will internally close the fd file handle, but it will also release all the resources that were allocated by fopen.
TL/DR: if you use fd= open(...); to open a file, you should use close(fd); to close it, but if you use f = fopen(...);, then you should use fclose(f);.

As already pointed out in the other answers, you should use fclose(f); instead of close(fd);.
My question is whether the close(fd) statement closes all file descriptors [...]
No, it won't close all file descriptors. The file descriptors STDOUT_FILENO and STDERR_FILENO will still remain open and will now refer to the opened file test.txt. However, these file descriptors should probably not be closed, as it is good programming practice for STDOUT_FILENO and STDERR_FILENO to remain valid until the end of the program. They will be automatically closed by the kernel on process termination.

C FILE* streams use buffered I/O internally. fclose() flushes this buffer and then closes the file descriptor at OS level. close()'ing a FILE* stream may not flush this internal buffer and you may lose data. So for C streams always use C fxxx() functions.

Related

Does fprintf() work for writing in a pipe, or I must always use write()?

Keep in mind that when using fprintf() I'm aware that I need to pass the file descriptor for writing to the pipe. I just have the doubt and wish to know right now; I don't really have any kind of sample code.
In addition, I want to know if functions such as fputc(), fputs() will also work.
Using fprintf() requires a file stream (FILE *). When you create a pipe, you get two file descriptors. File descriptors are not the same as streams.
You can use the POSIX fdopen() function to create a file stream from a file descriptor; you can then use fprintf() on that file stream — or any of the other standard I/O functions that take an explicit file stream argument and write to the stream. You can't use fseek(); you'll get an error (ESPIPE — illegal seek).
You can (in theory) use the POSIX dprintf() function to write directly to a file descriptor — if your system supports it.
You can use fdopen() to convert a file descriptor to a FILE *, and then use all the stdio functions.
int pipefd[2];
pipe(pipefd);
FILE *pipeout = fdopen(pipefd[1], "w");
fprintf(pipeout, "Message written to the pipe\n");

POSIX fdopen() function in C

When should we use fdopen and how do we use it? My understanding of that is when we can't use fopen to read (read from pipe). I don't really understand the description of fdopen on the man page: The fdopen() function associates a stream with the existing file descriptor, fd.
You use fdopen() when you have a file descriptor (int fd;) of some sort but you need to call functions that require a file stream (FILE *fp;) instead. This could be a pipe file descriptor, or a socket file descriptor, or any other file descriptor type.
Once you've used fdopen(), you should not use the file descriptor again — you should use only the file stream. If you must use a file descriptor as well, it would be best to use fileno(fp) rather than the saved fd. Most importantly, if you mix access, you need to ensure that you've flushed the file stream before you do anything with the file descriptor. (There's no buffering with the file descriptor, so there's less of a problem reverting to the file stream from the file descriptor.). Operations that change the current file position on the file descriptor could mess up the file stream and vice versa (when there is a current position associated with the file descriptor or file stream). Note that both read and write operations change the current file position — there's not a lot you can do without risking a mess.
You must use fclose(fp); to close the file stream (and implicitly the file descriptor). Do NOT use just close(fd) or close(fileno(fp)).
Note that POSIX defines dprintf() to do formatted output to a file descriptor. Also, you could use snprintf() or its relatives to format data into a string and then write the string to the file descriptor. This might make it less important to use fdopen().

Difference between fclose and close

If I fopen a file, what's the difference between calling fclose or close and which one should I use?
If forked children have access to the file as well, what should they do when they are finished with the file?
fclose() is function related with file streams. When you open file with the help of fopen() and assign stream to FILE *ptr. Then you will use fclose() to close the opened file.
close() is a function related with file descriptors. When you open file with the help of open() and assign descriptor to int fd. Then you will use close() to close the opened file.
The functions like fopen(), fclose() etc are C standard functions, while the other category of open(), close() etc are POSIX-specific. This means that code written with open(), close() etc is not a standard C code and hence non-portable. Whereas the code written with fopen(), fclose etc is a standard code and can be ported on any type of system.
which one should I use?
It depends on how you opened the file. If you open a file with fopen(), you should use fclose() and if you open file with open(), you should use close().
If forked children have access to the file as well, what should they do when they are finished with the file?
This is also dependent on where you made the fork() call: before opening the file or after opening it.
See: Are file descriptors shared when fork()ing?
See: man fclose and man close
open() and close() are UNIX syscalls which return and take file descriptors, for use with other UNIX syscalls such as write(). fopen() and fclose() are standard C library functions which operate on FILE*s, for use with things like fwrite and fprintf. The latter are almost always what you should be using: They're simpler and more cross-platform.
As for your second question, forked children have the same numeric file descriptor as the parent, but it's a copy; they can close it, and it will still be open for the parent and other children. (Though personally, I don't like to have files open when I fork()... I like to make that sort of shared resource usage explicit. Pipes, of course, are an exception.)
which one should I use?
If you open a file with fopen, close it with fclose. Using close in this case may cause a memory leak on a handle allocated by fopen

Interaction of POSIX file descriptors and C FILEs

I'm reading the POSIX specification and I can't fully understand how file descriptors, file descriptions and streams interact.
FILE* f1 = fopen("a.txt", "r");
int fno = fileno(f1);
FILE* f2 = fdopen(fno, "r");
// is it true?
assert(fileno(f2) == fno);
// does it close only f1 or f2 too?
fclose(f1);
fgetc(f2); // valid?
(Question is in the comments.)
The C standard library gives you the opaque pointer FILE*, a file handle, which you can manipulate with fopen()/fclose(), and access with fread()/fwrite().
POSIX offers a notion of file descriptors which are integers. You can manipulate those with open()/close(), and access with read()/write().
For every open file handle FILE * fp on a POSIX system, you can get the underlying file descriptor with fileno(fp). Conversely, for an existing file descriptor n, you can open a standard file handle with fdopen(n).
In other words, the POSIX file descriptors are an operating system primitive which is used to implement the C standard io library. Note that POSIX file descriptors also serve as handles for sockets.
Your final call to fgets() is undefined because the fclose() invalidates the file handle, and consequently its underlying file descriptor. fdopen() does not duplicate the file descriptor.
Yes, it's true and it closes both files as they use the same file descriptor.

Close a FILE pointer without closing the underlying file descriptor

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.
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. Also, any fcntl() locks held on the original fd will be released when you close the copy.
If everything else fails, dup(2) could help.

Resources