I mean to use fdopen
FILE *fdopen(int fd, const char *mode);
In man pages, it is stated that "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."
So I have to first know the mode of fd
(which I guess is an int
) to choose an appropriate const char *mode
for the stream.
I understand I should use fcntl
int fcntl(int fd, int cmd);
to "manipulate file descriptor" (in the following, I quote from this official source). It can operate on:
File descriptor flags
The following commands manipulate the flags associated with a file descriptor.
...File status flags
Each open file description has certain associated status flags, initialized by open(2)...
(I wouldn't know the difference between the two.
Given that fcntl
refers entirely to file descriptors, I guess the second title should be "File descriptor status flags", and thus we would have "flags" and "status flags"... confusing to me. I haven't seen any specification of this). I mention this in passing here, I am putting together a specific question on this.
From the description, I guess I should go for the latter.
In this case, when cmd=F_GETFL
, the return value is "the file access mode and the file status flags". "The file status flags and their semantics are described in open(2)".
Now I couldn't make sense of, after reading the sources cited:
What are all possible modes (int
s) for the fd
Consequently, what are all combinations mode(fd) <-> mode(stream) that are "compatible".
I guess one should be able to put together two list and join with arrows.
Related:
Can I get the access mode of a `FILE*`?
Specification of file descriptors (I asked this)
I Wanna know the Internal Members of struct FILE, the latest ones
How to make sense of O_RDONLY = 0? (I asked this)
https://www.gnu.org/software/libc/manual/html_node/Access-Modes.html
https://www.gnu.org/software/libc/manual/html_node/File-Status-Flags.html#File-Status-Flags
After learning from answers and comments, here and in How to make sense of O_RDONLY = 0?, I put together code below. From there, I obtained the following info about file descriptor status "words" (I wouldn't like to use the term "flags", see Note below, taken from this comment) and file opening modes.
*** Flag O_RDONLY = 0 = 0 = x0000
*** Flag O_WRONLY = 1 = 1 = x0001
*** Flag O_RDWR = 2 = 10 = x0002
*** Flag O_CREAT = 64 = 1000000 = x0040
*** Flag O_TRUNC = 512 = 1000000000 = x0200
*** Flag O_APPEND = 1024 = 10000000000 = x0400
*** Flag O_WRONLY | O_CREAT | O_TRUNC = 577 = 1001000001 = x0241
*** Flag O_WRONLY | O_CREAT | O_APPEND = 1089 = 10001000001 = x0441
*** Flag O_RDWR | O_CREAT | O_TRUNC = 578 = 1001000010 = x0242
*** Flag O_RDWR | O_CREAT | O_APPEND = 1090 = 10001000010 = x0442
*** Mode r F_GETFL -> 32768 = 1000000000000000 = x8000
*** Mode w F_GETFL -> 32769 = 1000000000000001 = x8001
*** Mode a F_GETFL -> 33793 = 1000010000000001 = x8401
*** Mode r+ F_GETFL -> 32770 = 1000000000000010 = x8002
*** Mode w+ F_GETFL -> 32770 = 1000000000000010 = x8002
*** Mode a+ F_GETFL -> 33794 = 1000010000000010 = x8402
Numbers in the three columns are in decimal, binary and hex.
Looking for the "strange" x8000
, I found in fcntl-linux.h
# ifdef __USE_GNU
...
# define AT_RECURSIVE 0x8000 /* Apply to the entire subtree. */
...
# endif
So, except for that flag, present in all modes, the association would be
r <-> O_RDONLY
w <-> O_WRONLY
a <-> O_WRONLY | O_APPEND
r+ <-> O_RDWR
w+ <-> O_RDWR
a+ <-> O_RDWR | O_APPEND
Now this provides a couple of intriguing findings to me:
The list does not coincide with the table given by Tony Tannous.
The word for r+
is the same as for w+
.
This provides a challenge for the coder, as to which mode to use with fdopen
when the word is O_RDWR
(both r+
and w+
would be ok).
As per this, I expected w+
to have also O_CREAT
(as in the table mentioned above).
I also expected w
to have it.
To write completely portable code, it seems that whenever using fdopen
one has to write code as I wrote to automatically find the connection mode <-> word.
(actually, part of the work I did was a manual identification, and further code is needed).
EDIT:
The explanation for points 1 and 2 as per comments is that the table shows the match between fopen
modes and open
flags, i.e., during creation.
But what I obtained with fcntl
is the flags persistent after creation, not those used during creation.
As also explained here, O_CREAT
and O_TRUNC
belong to the category of File creation flags and thus are not persistent.
On the other hand, O_APPEND
belongs to the category File status flags and is persistent.
"The distinction between these two groups of flags is that the file creation flags affect the semantics of the open operation itself, while the file status flags affect the semantics of subsequent I/O operations." [ref]
Note: The man page for open(2) first describes the file access modes, and then adds "In addition, zero or more file creation flags and file status flags can be bitwise-or'd in flags...." But it (correctly) does not mention that file access mode can be bitwise operated on. For me, the word "flag" is an absolute misnomer, and misleading.
to_binary
to get the binary form can be used):
int main() {
const char fname[100] = "test.txt";
const char modes[][4] = { "r", "w", "a", "r+", "w+", "a+" };
const size_t nmodes = sizeof(modes) / sizeof(modes[0]);
const int flags[] = { O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC, O_APPEND,
O_WRONLY | O_CREAT | O_TRUNC,
O_WRONLY | O_CREAT | O_APPEND,
O_RDWR | O_CREAT | O_TRUNC,
O_RDWR | O_CREAT | O_APPEND
};
const char flags_str[][100] = { "O_RDONLY", "O_WRONLY", "O_RDWR", "O_CREAT", "O_TRUNC", "O_APPEND",
"O_WRONLY | O_CREAT | O_TRUNC",
"O_WRONLY | O_CREAT | O_APPEND",
"O_RDWR | O_CREAT | O_TRUNC",
"O_RDWR | O_CREAT | O_APPEND"
};
const size_t nflags = sizeof(flags) / sizeof(flags[0]);
for (size_t iflag = 0 ; iflag < nflags ; iflag++) {
const int flag = flags[iflag];
const char * flag_str = flags_str[iflag];
char nbin[33];
to_binary(flag, nbin);
printf( "*** Flag %30s = %5d = %12s = x%04x\n", flag_str, flag, nbin, flag);
}
for (size_t imode = 0 ; imode < nmodes ; imode++) {
const char * mode = modes[imode];
FILE * fp1 = fopen(fname, mode);
int fd1 = fileno(fp1);
int retval = fcntl(fd1, F_GETFL);
char nbin[33];
to_binary(retval, nbin);
printf( "*** Mode %2s F_GETFL -> %5d = %12s = x%04x", mode, retval, nbin, retval);
fclose(fp1);
}
return 0;
}