Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
788 views
in Technique[技术] by (71.8m points)

c - How to get the mode of a file descriptor?

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:

  1. What are all possible modes (ints) for the fd

  2. 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)

How to catch file mode?

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

  1. The list does not coincide with the table given by Tony Tannous.

  2. 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.

  3. 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.


Code (any function 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
", 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;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...