How to get the mode of a file descriptor?

后端 未结 2 602
不知归路
不知归路 2020-12-21 16:03

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

相关标签:
2条回答
  • 2020-12-21 16:13

    From fopen you can check how they correlate with w+ r etc...

    0 讨论(0)
  • 2020-12-21 16:30

    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\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;
    }
    
    0 讨论(0)
提交回复
热议问题