mkdir_p()

pオプション的動作のmkdir()。そーゆー動作の関数ってなかったっけなー?

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

#ifdef _WIN32
#include <direct.h>
#include <malloc.h>
#define mkdir(p, m) _mkdir(p)
typedef int mode_t;
#else
#include <unistd.h>
#include <alloca.h>
#endif

#define IS_SEPARATOR(c) (((c) == '/') || ((c) == '\\'))

static int mkdir_p0(const char *pathname, mode_t mode) {
  int r;

  r = mkdir(pathname, mode);

  if (r != 0 && errno == EEXIST) {
    r = 0;
  }

  return r;
}

int mkdir_p(const char *pathname, mode_t mode) {
  size_t len = strlen(pathname);
  char *p = alloca(len + 1);
  unsigned int i;
  int r;

  memcpy(p, pathname, len);
  p[len] = '\0';

  for (i = 0; i < len; i++) {
    if (IS_SEPARATOR(p[i])) {
      p[i] = '\0';
    }
  }

  if (len >= 1 && IS_SEPARATOR(pathname[0])) {
    p[0] = pathname[0];
  } else if (len >= 3 && pathname[1] == ':' && IS_SEPARATOR(pathname[2])) {
    p[2] = pathname[2];
  }

  if ((r = mkdir_p0(p, mode)) != 0) {
    return r;
  }

  while (1) {
    for(i = 0; i < len; i++) {
      if (p[i] == '\0') {
        p[i] = pathname[i];
        break;
      }
    }

    if (i >= len - 1) {
      break;
    }
    
    if ((r = mkdir_p0(p, mode)) != 0) {
      return r;
    }
  }

  return 0;
}

int main() {
  mkdir_p("foo/bar/zoo", 0755);

  return 0;
}