Search code examples
cfile-descriptorstdiofcntlfile-pointer

How to tell if FILE* is referring to a directory?


I just discovered that a FILE* can not only refer to a regular file, but also to a directory. If the latter is the case, fread will fail with errno set to 21 (Is a directory).

Minimal repro can be tested here

#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>

int main() {
    char const* sz = ".";

    int fd = open(sz, O_RDONLY | O_NOFOLLOW); // all cleanup omitted for brevity
    FILE* file = fdopen(fd, "rb");
    // I would like to test in this line if it is a directory

    char buffer[21];
    int const n = fread(buffer, 1, 20, file);
    if (0 < n) {
        buffer[n] = 0;
        printf(buffer);
    } else {
        printf("Error %d", errno); // 21 = Is a directory
    }
}

What is the proper way to detect early that my FILE* is referring to directory without trying to read from it?

EDIT to repel the duplicate flags: I want to test on the FILE*, not the filename. Testing on filename only and then opening it later is a race condition.


Solution

  • Assuming a POSIX-like environment, if you have just the file stream (FILE *fp), then you are probably reduced to using fileno() and fstat():

    #include <sys/stat.h>
    
    
    struct stat sb;
    if (fstat(fileno(fp), &sb) != 0)
        …oops…
    if (S_ISDIR(sb.st_mode))
        …it is a directory…
    else
        …it is not a directory…