Why does fdopen have a "flags" argument? - c

I'm never really sure what open mode I'm supposed to pass to fdopen, or why it even has an open mode. Since fdopen operates on a file descriptor which may have previously been opened via a lower level call like open - which already sets the mode flags.
I mean, I assumed that any implementation of fopen would just translate the char* mode string into a lower level mode flag type, (an OR'd int on POSIX systems), and then pass that to open.
But if we're calling fdopen where we have an existing file descriptor that came from a previous call to open, why do we need flags? It just seems to create more work for the programmer to translate the int flags into char* flags for fdopen.
Am I missing some use case where we might want different flags for open and fdopen?

Maybe you want to pass O_RDWR to open(2) and then "r" to fdopen(3). That is a perfectly legal thing to do. Perhaps someone else called open(2) and/or fdopen(3) on your behalf.

Kevin shared the proper idea.
FILE * and fd are governed by different instances. since open modes are most likely being hard coded, so it's trivial for programmers to type it twice.
there are indeed some cases you will want to open something in fd first then wrap it to FILE * afterwards. for example, before i tried to provide a serial port interface in my own project, i had to open it using open, so that i could operate ioctl, termios on it, and finally, i wrapped it with a FILE * so that allowed the external world to use fgets or stuff like that.

Quoted from the GNU documentation:
File descriptors provide a primitive, low-level interface to input and output operations. [If] you want to do control operations that are specific to a particular kind of device, you must use a file descriptor; there are no facilities to use streams in this way.
Both file descriptors and streams can represent a connection to a device (such as a terminal), or a pipe or socket for communicating with another process, as well as a normal file.
The fdopen() function associates a stream with the existing file descriptor, fd. The mode of the stream (one of the values "r", "r+", "w", "w+", "a", "a+") must be compatible with the mode of the file descriptor. The fopen() function opens the file whose name is the string pointed to by path and associates a stream with it.
In general, file descriptors are not as portable as streams.
For more information check this link: http://www.gnu.org/software/libc/manual/html_node/Streams-and-File-Descriptors.html

Related

what kinds of types can we specify in `fdopen()`, and which part of the type is valid?

APUE says
With fdopen, the meanings of the type argument differ slightly.
The descriptor has already been opened, so opening for writing does
not truncate the file. (If the descriptor was created by the open
function, for example, and the file already existed, the
O_TRUNC flag would control whether the file was truncated. The
fdopen function cannot simply truncate any file it opens for writing.)
Also, the standard I/O append mode cannot create the file (since the
file has to exist if a descriptor refers to it).
In general, when we call fdopen() on a file descriptor returned from open(),
what kinds of types can we specify in fdopen()?
Must the type specified in fdopen() be exactly the same as the mode specified in open()?
Can the type specified in fdopen() be a subset, superset, or neither subset nor superset of the mode specified in open()?
If there is no restriction on the types specified in fdopen() with respect to the mode specified in the previous open(), which part of the type specified in fdopen() is valid, and which part isn't (i.e. is ignored)?
Thanks.
POSIX specifies:
The application shall ensure that the mode of the stream as expressed by the mode argument is allowed by the file access mode of the open file description to which fildes refers.
The Rationale section goes a little further:
The meanings of the mode arguments of fdopen() and fopen() differ. With fdopen(), open for write (w or w+) does not truncate, and append (a or a+) cannot create for writing. The mode argument formats that include a b are allowed for consistency with the ISO C standard function fopen(). The b has no effect on the resulting stream. Although not explicitly required by this volume of IEEE Std 1003.1-2001, a good implementation of append (a) mode would cause the O_APPEND flag to be set.
Since file descriptors can be opened in a wide variety of ways (open(), socket(), etc.), and there can be custom device drivers that have different restrictions, it's not really possible to provide a general specification of the relationship between the open() mode and the fdopen() mode.
But it should be pretty safe to assume that if the file descriptor is open for writing, you should be able to use mode w, and if it's open for reading you can use mode r.

Equivalent of fgetc with Unix file descriptors

The fgetc(3) function takes a FILE * as its input stream. Must I reimplement character-at-a-time input with read(2), or is there a <unistd.h>-style equivalent taking an integer file descriptor instead?
No, there isn't such a thing, and please never do read(fd, &ch, sizeof(char)) (explanations below).
The function read(2) is usually implemented as a system call to the operating system kernel. Although the internal (and funky) details of such a thing shall not be discused here, the overall idea is that system calls are (usually) not something cheap.
It would be inefficient for both the userspace application and the kernel to do a system call just to get a single character from a file descriptor.
For instance, fgetc(3) usually ends up doing some buffering inside the structure of the FILE object. This means that the internal read(2) from fgetc(3) wouldn't just read a single character, but rather it'll try to get more for the sake of efficiency.
Anyway, it's not usually a good idea to mess up with such low-level stuff. You can get all the benefits of buffering (and of FILEs overall) by using fdopen(3) to create a FILE object from a file descriptor, as your question appears to imply that you have at hand just a raw file descriptor at the moment.
If you want to, you can open a file using open() -
int fh = open("abc.txt", O_RDONLY, S_IREAD); // there are different permissions you can provide (refer to link).
and then you can use fh in read() calls.

How can my code identify the mode passed to fopen() if it's only passed a FILE*?

Suppose my function accepts a FILE* and it would like to know how exactly the underlying file was open - specifically which mode (such as for example r or rb) was passed into fopen().
How can my code find which value mode had if it's only passed a FILE* of an already opened file?
On Unix-like systems, you can use fcntl(fileno(fp), F_GETFL, &flags) to retrieve the flags of the underlying file descriptor. Use the O_ACCMODE mask to obtain the file access mode, which is one of O_RDONLY, O_WRONLY, O_RDWRD and O_APPEND values corresponding to mode strings passed to fopen.
IMO, on linux, you can use fcntl() to achieve this. Man page here.
However, you'll be needing the corresponding fd [maybe with fileno()], because, fcntl() does not work directly with FILE *.
In this case, if you use F_GETFL to read the File status flags, it will return you the status of the flags, which can be used to determine the mode of that file pointer.
There is no portable way to do this.
What you can do, although it's of course fantastically ugly and quite scary, is to use fileno() to get the underlying file descriptor, and then use fdopen() to re-open the file using the mode you want.

When do you use fopen instead of open?

I don't find any difference through test.
What's the key to decide on this?
fopen is a portable interface that any C environment should provide. Also, its result is a buffered stream (FILE*) that can be used with the convenient stdio functions.
open is a Unix/POSIX-specific interface. Its result is a bare (unbuffered) file descriptor, which has to be used with low-level system calls. It does allow some more fine-grained control over I/O (see the list of flags in the POSIX standard), so sometimes you might want to open a file and then perhaps fdopen it to get stdio and buffering.

C fopen vs open

Is there any reason (other than syntactic ones) that you'd want to use
FILE *fdopen(int fd, const char *mode);
or
FILE *fopen(const char *path, const char *mode);
instead of
int open(const char *pathname, int flags, mode_t mode);
when using C in a Linux environment?
First, there is no particularly good reason to use fdopen if fopen is an option and open is the other possible choice. You shouldn't have used open to open the file in the first place if you want a FILE *. So including fdopen in that list is incorrect and confusing because it isn't very much like the others. I will now proceed to ignore it because the important distinction here is between a C standard FILE * and an OS-specific file descriptor.
There are four main reasons to use fopen instead of open.
fopen provides you with buffering IO that may turn out to be a lot faster than what you're doing with open.
fopen does line ending translation if the file is not opened in binary mode, which can be very helpful if your program is ever ported to a non-Unix environment (though the world appears to be converging on LF-only (except IETF text-based networking protocols like SMTP and HTTP and such)).
A FILE * gives you the ability to use fscanf and other stdio functions.
Your code may someday need to be ported to some other platform that only supports ANSI C and does not support the open function.
In my opinion the line ending translation more often gets in your way than helps you, and the parsing of fscanf is so weak that you inevitably end up tossing it out in favor of something more useful.
And most platforms that support C have an open function.
That leaves the buffering question. In places where you are mainly reading or writing a file sequentially, the buffering support is really helpful and a big speed improvement. But it can lead to some interesting problems in which data does not end up in the file when you expect it to be there. You have to remember to fclose or fflush at the appropriate times.
If you're doing seeks (aka fsetpos or fseek the second of which is slightly trickier to use in a standards compliant way), the usefulness of buffering quickly goes down.
Of course, my bias is that I tend to work with sockets a whole lot, and there the fact that you really want to be doing non-blocking IO (which FILE * totally fails to support in any reasonable way) with no buffering at all and often have complex parsing requirements really color my perceptions.
open() is a low-level os call. fdopen() converts an os-level file descriptor to the higher-level FILE-abstraction of the C language. fopen() calls open() in the background and gives you a FILE-pointer directly.
There are several advantages to using FILE-objects rather raw file descriptors, which includes greater ease of usage but also other technical advantages such as built-in buffering. Especially the buffering generally results in a sizeable performance advantage.
fopen vs open in C
1) fopen is a library function while open is a system call.
2) fopen provides buffered IO which is faster compare to open which is non buffered.
3) fopen is portable while open not portable (open is environment specific).
4) fopen returns a pointer to a FILE structure(FILE *); open returns an integer that identifies the file.
5) A FILE * gives you the ability to use fscanf and other stdio functions.
Unless you're part of the 0.1% of applications where using open is an actual performance benefit, there really is no good reason not to use fopen. As far as fdopen is concerned, if you aren't playing with file descriptors, you don't need that call.
Stick with fopen and its family of methods (fwrite, fread, fprintf, et al) and you'll be very satisfied. Just as importantly, other programmers will be satisfied with your code.
If you have a FILE *, you can use functions like fscanf, fprintf and fgets etc. If you have just the file descriptor, you have limited (but likely faster) input and output routines read, write etc.
open() is a system call and specific to Unix-based systems and it returns a file descriptor. You can write to a file descriptor using write() which is another system call.
fopen() is an ANSI C function call which returns a file pointer and it is portable to other OSes. We can write to a file pointer using fprintf.
In Unix:
You can get a file pointer from the file descriptor using:
fP = fdopen(fD, "a");
You can get a file descriptor from the file pointer using:
fD = fileno (fP);
Using open, read, write means you have to worry about signal interaptions.
If the call was interrupted by a signal handler the functions will return -1
and set errno to EINTR.
So the proper way to close a file would be
while (retval = close(fd), retval == -1 && ernno == EINTR) ;
I changed to open() from fopen() for my application, because fopen was causing double reads every time I ran fopen fgetc . Double reads were disruptive of what I was trying to accomplish. open() just seems to do what you ask of it.
open() will be called at the end of each of the fopen() family functions. open() is a system call and fopen() are provided by libraries as a wrapper functions for user easy of use
Depends also on what flags are required to open. With respect to usage for writing and reading (and portability) f* should be used, as argued above.
But if basically want to specify more than standard flags (like rw and append flags), you will have to use a platform specific API (like POSIX open) or a library that abstracts these details. The C-standard does not have any such flags.
For example you might want to open a file, only if it exits. If you don't specify the create flag the file must exist. If you add exclusive to create, it will only create the file if it does not exist. There are many more.
For example on Linux systems there is a LED interface exposed through sysfs. It exposes the brightness of the led through a file. Writing or reading a number as a string ranging from 0-255. Of course you don't want to create that file and only write to it if it exists. The cool thing now: Use fdopen to read/write this file using the standard calls.
opening a file using fopen
before we can read(or write) information from (to) a file on a disk we must open the file. to open the file we have called the function fopen.
1.firstly it searches on the disk the file to be opened.
2.then it loads the file from the disk into a place in memory called buffer.
3.it sets up a character pointer that points to the first character of the buffer.
this the way of behaviour of fopen function
there are some causes while buffering process,it may timedout. so while comparing fopen(high level i/o) to open (low level i/o) system call , and it is a faster more appropriate than fopen.

Resources