41

I'm writing a program to check if something is a file or is a directory. Is there a better way to do it than this?

#include <stdio.h>

#include <sys/types.h>
#include <dirent.h>
#include <errno.h>

int isFile(const char* name)
{
    DIR* directory = opendir(name);

    if(directory != NULL)
    {
     closedir(directory);
     return 0;
    }

    if(errno == ENOTDIR)
    {
     return 1;
    }

    return -1;
}

int main(void)
{
    const char* file = "./testFile";
    const char* directory = "./";

    printf("Is %s a file? %s.\n", file,
     ((isFile(file) == 1) ? "Yes" : "No"));

    printf("Is %s a directory? %s.\n", directory,
     ((isFile(directory) == 0) ? "Yes" : "No"));

    return 0;
}
Jookia
  • 6,228
  • 13
  • 46
  • 58

4 Answers4

82

You can call the stat() function and use the S_ISREG() macro on the st_mode field of the stat structure in order to determine if your path points to a regular file:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int is_regular_file(const char *path)
{
    struct stat path_stat;
    stat(path, &path_stat);
    return S_ISREG(path_stat.st_mode);
}

Note that there are other file types besides regular and directory, like devices, pipes, symbolic links, sockets, etc. You might want to take those into account.

Frédéric Hamidi
  • 249,845
  • 40
  • 466
  • 467
  • 7
    When considering symlink cases, use lstat() instead of stat() as it does not follow the symlink. – Sparky Dec 29 '10 at 12:13
  • 4
    There's at least a good discussion at [Checking if a directory exists](http://stackoverflow.com/questions/3828192/checking-if-a-directory-exists-in-unix-system-call/), where `stat()` and `lstat()` are discussed, and the complete set of POSIX file types is outlined. I'm tempted to duplicate this question to that one. The code should check the result of `stat()`, too, and handle errors appropriately. – Jonathan Leffler Mar 13 '15 at 22:49
  • @Jonathan, that answer is indeed more complete than mine, and was posted three months before mine, five years ago. And it's not like my own answer would disappear anyway. I see you wield Mjölnir in the `[c]` tag, so thank you for commenting before acting unilaterally. However, you're ultimately right. No worries, do what you have to do :) – Frédéric Hamidi Mar 13 '15 at 22:56
  • 1
    this does not work on osx for me... – v0d1ch Jan 17 '16 at 18:15
  • 1
    @vodish, maybe `stat()` is failing for you? What about the code in the duplicate, does it work for you? – Frédéric Hamidi Jan 17 '16 at 18:19
31

Use the S_ISDIRmacro:

int isDirectory(const char *path) {
   struct stat statbuf;
   if (stat(path, &statbuf) != 0)
       return 0;
   return S_ISDIR(statbuf.st_mode);
}
ismail
  • 43,610
  • 8
  • 84
  • 94
  • You forgot to fill the `statbuf` struct with information. – RedX Dec 29 '10 at 09:52
  • 1
    This works fine as-is, stat function fills the info itself. – ismail Dec 29 '10 at 09:54
  • 3
    Ideally, the code would check that `stat` worked: `if (stat(path, &statbuf) != 0) return 0;` -- because a non-existent object is not a directory, and if you don't have permission to `stat()` it, it may as well not exist (even if the error reported is related to permissions). – Jonathan Leffler Mar 13 '15 at 22:48
  • 1
    @JonathanLeffler you are absolutely right, updated the code. – ismail Mar 14 '15 at 15:47
4

Yes, there is better. Check the stat or the fstat function

KARASZI István
  • 29,989
  • 8
  • 97
  • 120
2

Normally you want to perform this check atomically with using the result, so stat() is useless. Instead, open() the file read-only first and use fstat(). If it's a directory, you can then use fdopendir() to read it. Or you can try opening it for writing to begin with, and the open will fail if it's a directory. Some systems (POSIX 2008, Linux) also have an O_DIRECTORY extension to open which makes the call fail if the name is not a directory.

Your method with opendir() is also good if you want a directory, but you should not close it afterwards; you should go ahead and use it.

Jonathan Leffler
  • 698,132
  • 130
  • 858
  • 1,229
R.. GitHub STOP HELPING ICE
  • 201,833
  • 32
  • 354
  • 689