Initial mkdir -p function
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int uc_mkdir_p(const char *full_path, mode_t mode)
|
||||
{
|
||||
struct stat st;
|
||||
int rc = 0;
|
||||
char *path;
|
||||
char *p;
|
||||
|
||||
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;
|
||||
}
|
||||
if (st.st_mode != (mode | S_IFDIR) && chmod(full_path, mode) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
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 = stat(path, &st);
|
||||
if (rc != 0) { //doesn't exist
|
||||
if (mkdir(path, mode) != 0) {
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
} else if (!S_ISDIR(st.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
free(path);
|
||||
return -1;
|
||||
} else { //dir already exist
|
||||
|
||||
if (st.st_mode != (mode | S_IFDIR) && chmod(path, mode) != 0) {
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//in case of multiple / , e.g. foo//bar
|
||||
*p = '/';
|
||||
for (; *p == '/'; p++)
|
||||
;
|
||||
}
|
||||
|
||||
//last part, in case full_path does not end with a /
|
||||
rc = stat(path, &st);
|
||||
if (rc != 0) {
|
||||
rc = mkdir(path, mode);
|
||||
}
|
||||
|
||||
free(path);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
uc_mkdir_p("a/b//c/d", 0777);
|
||||
}
|
||||
Reference in New Issue
Block a user