Search code examples
cfileposix

access(path, flag) returns 0 even if file exists


I'm trying to write a C program for copying content from a source file to a destination file. I want to check for error by checking if the file exists and if the user can read it before attempting to copy it. I use access() from unistd.h.

Here's the context, I have a folder :

.
├── src.txt
├── test
└── test.c

test.c is my program for testing if the file exists and if I can read it.

int main(){
        char* path = "src.txt";
        fprintf(stderr, "%d\n", access(path, F_OK));
        fprintf(stderr, "%d\n", access(path, R_OK));
        return 0;
}

In this example, as src.file exists and has permissions 664, the result should be :

1
1

But the actual output is

0
0

Even if I use the absolute path instead of relative path leading to src.txt, I get the same result. What disturbs me is if I try to open the file, it works:

test.c

int main(){
        char* path = "src.txt";
        fprintf(stderr, "%d\n", access(path, R_OK));
        fprintf(stderr, "%d\n", access(path, F_OK));

        FILE *f = fopen(path, "r");

        if (!f) {
                fprintf(stderr, "File couldn't be opened.\n");
        } else {
                fprintf(stderr, "File successfully opened.\n");
                fclose(f);
        }

        return 0;
}

It gives as output :

0
0
File successfully opened.

I'm sure I'm missing something, but I can't see what it is.


Solution

  • The access(2) function returns 0 on success. It returns -1 in case you don't have the requested permissions, or the file does not exist, or the path lookup failed. See the man page. It also sets the errno variable to the appropriate error code. So the output of 0, that you are seeing is correct, because you do have read permissions on the said file.

    As an aside, most of the system calls return -1 on error (for example read(2), open(2), write(2) etc) and set the errno variable to reflect the exact error which occurred. In order to take the correct action during an error, you need to check the value of the errno variable.