Files
libucore/src/mkdirp.c
T
2015-02-10 20:45:40 +01:00

101 lines
1.7 KiB
C

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
static int uc_mkdir(const char *full_path, mode_t mode)
{
struct stat st;
int rc;
rc = stat(full_path, &st);
if (rc == -1 && errno == ENOENT) {
rc = mkdir(full_path, mode);
if (rc == -1 && errno != EEXIST) {
return -1;
}
} else if (rc == 0) {
if (!S_ISDIR(st.st_mode)) {
errno = ENOTDIR;
return -1;
}
} else {
return -1;
}
return 0;
}
int uc_mkdir_p(const char *full_path, mode_t mode)
{
struct stat st;
int rc;
char *path;
char *p;
int create_final = 1;
if (full_path == NULL || full_path[0] == 0) {
errno = EINVAL;
return -1;
}
rc = stat(full_path, &st);
if (rc == 0) { //already exists
if (!S_ISDIR(st.st_mode)) {
errno = ENOTDIR;
return -1;
}
return 0;
}
path = strdup(full_path);
if (path == NULL) {
return -1;
}
//skip leading /
for (p = path; *p == '/'; p++)
;
for (;;) {
p = strchr(p, '/');
if (p == NULL) {
break;
}
*p = 0;
rc = uc_mkdir(path, mode);
if (rc != 0) {
free(path);
return -1;
}
*p = '/';
//in case of multiple / , e.g. foo//bar
for (; *p == '/'; p++)
;
if (*p == 0) {
create_final = 0;
break;
}
}
//last part, in case full_path does not end with a /
if (create_final) {
rc = uc_mkdir(path, mode);
} else {
rc = 0;
}
free(path);
return rc;
}