Awhile back I wrote a function to recursively create directories in C. It used a string builder to split the parts and rebuild the path.

The way mkdir works is by taking a single directory that does not exist and creates it. If there are multiple path parts that don’t exit it will error. Hence needing to split the string into parts and create each part of the path separately. Earlier parts of the path must exist before trying to add a later part.

For a project I was working on I needed to recursively make directories but I wasn’t able to utilize the string builder. So I wrote a version without it.

#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#  include <Windows.h>
#else
#  include <sys/stat.h>
#endif

#ifdef _WIN32
const char SEP = '\\';
#else
const char SEP = '/';
#endif

bool recurse_mkdir(const char *dirname)
{
    const char *p;
    char       *temp;
    bool        ret = true;

    temp = calloc(1, strlen(dirname)+1);
    /* Skip Windows drive letter. */
#ifdef _WIN32
    if ((p = strchr(dirname, ':') != NULL) {
        p++;
    } else {
#endif
        p = dirname;
#ifdef _WIN32
    }
#endif

    while ((p = strchr(p, SEP)) != NULL) {
        /* Skip empty elements. Could be a Windows UNC path or
           just multiple separators which is okay. */
        if (p != dirname && *(p-1) == SEP) {
            p++;
            continue;
        }
        /* Put the path up to this point into a temporary to
           pass to the make directory function. */
        memcpy(temp, dirname, p-dirname);
        temp[p-dirname] = '\0';
        p++;
#ifdef _WIN32
        if (CreateDirectory(temp, NULL) == FALSE) {
            if (GetLastError() != ERROR_ALREADY_EXISTS) {
                ret = false;
                break;
            }
        }
#else
        if (mkdir(str_builder_peek(sb), 0774) != 0) {
            if (errno != EEXIST) {
                ret = false;
                break;
            }
        }
#endif
    }
    free(temp);
    return ret;
}

This version is similar but uses strchr to search for parts and a memcpy to a temporary buffer to hold the path segment. The temporary is necessary because CreateDirectory and mkdir take NULL terminated string, so we can’t pass a sub string directly.

Just like the previous version it will continue processing if it encounters a directory that already exists. Also, it only returns false on error so the caller needs to check GetLastError or errno themselves if they want a detailed reason.