126

I want to write a program that checks for the existence of a directory; if that directory does not exist then it creates the directory and a log file inside of it, but if the directory already exists, then it just creates a new log file in that folder.

How would I do this in C with Linux?

Forest Katsch
  • 1,485
  • 2
  • 15
  • 26
Jeegar Patel
  • 26,264
  • 51
  • 149
  • 222
  • 1
    mkdir function creates a new directory, http://blog.tremend.ro/2008/10/06/create-directories-in-c-using-mkdir-with-proper-permissions/ – fsonmezay Sep 15 '11 at 11:50
  • 1
    maybe that's because you can find the solution in google or even in here by making a simple search http://stackoverflow.com/search?q=C+make+directory. By the way I'm not the guy who has down voted. – fsonmezay Sep 15 '11 at 11:57
  • Please [edit] your question to show [the code you have so far](http://whathaveyoutried.com). You should include at least an outline (but preferably a [mcve]) of the code that you are having problems with, then we can try to help with the specific problem. You should also read [ask]. – Toby Speight Feb 28 '18 at 11:45
  • @TobySpeight That is not good advice for this question at all. This question is far too broad, and there is no "specific problem" that is not covered by the question as it is. The problem is to find a way to create a directory in C. Polluting the question with the OP's specific code would likely greatly reduce the applicability to the countless other users that would reach this page. – Kröw Feb 18 '23 at 04:05

4 Answers4

190

Look at stat for checking if the directory exists,

And mkdir, to create a directory.

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

struct stat st = {0};

if (stat("/some/directory", &st) == -1) {
    mkdir("/some/directory", 0700);
}

You can see the manual of these functions with the man 2 stat and man 2 mkdir commands.

Arnaud Le Blanc
  • 98,321
  • 23
  • 206
  • 194
  • 9
    I believe `mkdir` under Linux needs a second parameter, `mode`, in addition to `path`. – Paul R Sep 15 '11 at 11:51
  • Paul R: it's not mandatory, it just gets effective id as the owner – Uku Loskit Sep 15 '11 at 11:54
  • @Uku Loskit: won't you get a compile error if you pass only one parameter ? – Paul R Sep 15 '11 at 11:56
  • @Uku: did you compile with gcc -Wall ? – Paul R Sep 15 '11 at 12:54
  • @Uku: maybe you're compiling C++ (and in that language maybe there is a version of `mkdir()` with only 1 parameter ...) ... – pmg Sep 15 '11 at 13:09
  • i'm compiling with gcc. It gives me warnings with -Wall, but still compiles. – Uku Loskit Sep 15 '11 at 13:12
  • 3
    @Uku: passing an incorrect number of parameters to a function is Undefined Behaviour, so while it may appear to work for you in one instance you should not rely on it. – Paul R Sep 15 '11 at 21:34
  • I found it odd that execute bit was set. Apparently permissions are interpreted differently for folders. http://unix.stackexchange.com/questions/21251/why-do-directories-need-the-executable-x-permission-to-be-opened – stephen Mar 28 '14 at 18:39
  • 5
    What is the purpose of checking that the directory doesn't exist before creating it? Even if stat says it doesn't exist yet, another process could have created it in the meantime. – Brandin Aug 20 '15 at 06:21
  • 3
    @Brandin I guess I blindly answered to OP's question :) You are right about the race condition. – Arnaud Le Blanc Aug 21 '15 at 12:39
  • 4
    This will be flagged by most good static analyzers as a TOCTOU risk – kdopen Jun 22 '16 at 14:52
  • How can I add another option like `$mkdir -p ./parent_dir/my_dir/`? – Naveen Kumar Jan 22 '19 at 13:50
  • error C1083: Cannot open include file: 'unistd.h': No such file or directory – john k Jul 11 '22 at 15:10
34

You can use mkdir:

$ man 2 mkdir

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

int result = mkdir("/home/me/test.txt", 0777);
Paul R
  • 208,748
  • 37
  • 389
  • 560
  • 1
    Will this remove and replace existing directories? – jjxtra Jan 18 '17 at 21:50
  • 1
    @jjxtra:: no, it should fail if the directory already exists, in much the same way as if you had attempted the same operation from the command line. – Paul R Jan 18 '17 at 21:54
  • That's what I would have guessed. Any performance problem by skipping the stat check and just mkdir every time? – jjxtra Jan 19 '17 at 15:40
  • @jjxtra: unless you're creating thousands of directories I can't imagine there would be any measurable performance difference. – Paul R Jan 19 '17 at 18:30
  • 5
    Trying `mkdir()` directly instead of doing a `stat()` first is faster, as it saves one system call, if the directory is created. If the directory does already exit, then the successful `stat()` will still be slower than the unsuccessful `mkdir()`, as `stat()` has to do more work to complete. – Kai Petzke Apr 26 '21 at 18:22
11

I want to write a program that (...) creates the directory and a (...) file inside of it

because this is a very common question, here is the code to create multiple levels of directories and than call fopen. I'm using a gnu extension to print the error message with printf.

void rek_mkdir(char *path) {
    char *sep = strrchr(path, '/');
    if(sep != NULL) {
        *sep = 0;
        rek_mkdir(path);
        *sep = '/';
    }
    if(mkdir(path, 0777) && errno != EEXIST)
        printf("error while trying to create '%s'\n%m\n", path); 
}

FILE *fopen_mkdir(char *path, char *mode) {
    char *sep = strrchr(path, '/');
    if(sep) { 
        char *path0 = strdup(path);
        path0[ sep - path ] = 0;
        rek_mkdir(path0);
        free(path0);
    }
    return fopen(path,mode);
}
Max Base
  • 639
  • 1
  • 7
  • 15
Jens Harms
  • 406
  • 3
  • 5
  • 4
    just my 5 cents - mode 0777 for dir may be not desired - maybe 0755 is better, or even pass by parameter? – ivan.ukr Aug 12 '18 at 22:51
  • 2
    @ivan.ukr 0777 is correct, the mode will by modified by the users umask. Eg. for umask 022 it results in 755 or for umask 007 in 770. – imix Oct 29 '20 at 04:46
5

int mkdir (const char *filename, mode_t mode)

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

if (mkdir("/some/directory", S_IRWXU | S_IRWXG | S_IRWXO) == -1) {
    printf("Error: %s\n", strerror(errno));
}

For best practice it is recommended to use an integer-alias for mode. The argument mode specifies the file permissions for the new directory.

Read + Write + Execute: S_IRWXU (User), S_IRWXG (Group), S_IRWXO (Others)

Source: https://www.gnu.org/software/libc/manual/html_node/Permission-Bits.html

If you want to know that the directory exists, lookup the errno's for EEXIST.

ShinyHero
  • 73
  • 1
  • 6