Антон
Антон

Reputation: 189

How to catch file mode?

I have to catch modes below:

"rb", "r+b" and "wb".

I tried to execute code (compiled) of this:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    FILE *file = fopen("data.bin", "r");
    if (!file) {
        perror("");
        return -1;
    }

    int fd = fileno(file);
    if (fcntl(fd, F_GETFL) == O_RDONLY) {
        printf("read only\n");
    }

    // printf("%d\n", O_APPEND);

    fclose(file);
    return 0;
}

But gotten nothing printed. fcntl() returns integers like 32768, but I need macros from the library like O_RDONLY.

Upvotes: 2

Views: 288

Answers (2)

 Ill
Ill

Reputation: 1

According to the Linux manual page FOPEN(3)

| fopen mode| open mode                 | 
|:---------:|:-------------------------:| 
|r          |`O_RDONLY`                 | 
|w          |`O_WRONLY|O_CREAT|O_TRUNC` | 
|a          |`O_WRONLY|O_CREAT|O_APPEND`| 
|r+         |`O_RDWR`                   | 
|w+         |`O_RDWR|O_CREAT|O_TRUNC`   |  
|a+         |`O_RDWR|O_CREAT|O_APPEND`  | 

This code has been tested a bit, but I can't distinguish between r+ and w+ mode.

const char *get_fd_mode(FILE *source) {
 int raw_fd = fileno(source);
 int flags = fcntl(raw_fd, F_GETFL);
 if (flags & O_RDWR) {
     if (flags & O_APPEND) {
         return "a+";
     } else if (flags & O_CREAT || flags & O_TRUNC) {
         return "w+";
     }
     return "r+";
 } else if (flags & O_WRONLY) {
     if (flags & O_APPEND) {
         return "a";
     }
     return "w";
 }
// O_RDONLY equals 00, therefore flags & O_RDONLY gives us always 0
 return "r";
}

Upvotes: 0

In general, you cannot catch -given a FILE* handle-, the file mode, in the fopen sense, with a portable C program.

For example, your FILE* might be obtained with popen, fmemopen, open_memstream, fdopen, etc... and could be writable only or readable only. It might not even have a valid file descriptor given by fileno.

You should adopt and define and document conventions about them.

For example, on Linux, a socket might be readable and writable at the OS level, and you could have two different FILE* handles on it (using fdopen) for the read and for the write sides.

And of course, a FILE* handle is not usable after an fclose (or a pclose)

So an hypothetical routine fprint_stuff(FILE*, struct stuff_st*) should document that the first argument is a writable file handle, and would just call fwrite and fprintf but should check that these did not fail.

Upvotes: 5

Related Questions