S_ISREG returns 0

Viewed 100

So I want to test if a file given is regular or not.

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h> 
#include <unistd.h>
#include <string.h>
#include <errno.h>

int main(int argc, char **argv)
{
    // Input check.
    if (argc != 2) {
        fprintf(stdout,"Format: %s <filename.txt>\n", argv[0]);
        return -1;
    }
    // Make sure the file is a regular file.
    int fd;
    if ((fd = open(argv[1], O_RDONLY) == -1)) {
        fprintf(stdout, "%s", strerror(errno));
        return -1;
    }
    struct stat st;
    if ((fstat(fd, &st) == -1)) {
        fprintf(stdout, "%s\n", strerror(errno));
        return -1;
    }
    if (!(S_ISREG(st.st_mode))) {
        fprintf(stdout, "Error, invalid file\n");
        return -1;
    }
    close(fd);
    return 0;
}

I run: .\a in.txt

I don't know what exactly is going on, but when I'm trying to test if the file is regular (last if statement), it fails. I tested to see if fstat fails, but it doesn't.

1 Answers

Here's the problem:

if ((fd = open(argv[1], O_RDONLY) == -1)) {

The equality operator == has higher precedence than the assignment operator =. So the above parses as:

if (fd = (open(argv[1], O_RDONLY) == -1)) {

Which assigns to fd the result of the comparison which will be either 0 or 1. These values both happen to be valid open file descriptors for stdin and stdout so the fstat call is successful and gets you the status of one of these streams.

You'll need to adjust the parenthesis to do the assignment first:

if ((fd = open(argv[1], O_RDONLY)) == -1) {

Also, it looks like you have other if statements that have a redundant set of parenthesis that you can remove. You want to avoid this because those extra parenthesis can silence warnings about exactly what you did.

Related