From 333dd6026ff874a60552e656b678cbf32fcf64c6 Mon Sep 17 00:00:00 2001 From: Nedko Arnaudov Date: Sun, 19 Sep 2010 20:24:13 +0300 Subject: [PATCH] improved dirhelpers * ensure_dir_exist() now acts as recursive mkdir * ensure_dir_exist_varg() is a new function that accepts multiple path components --- common/dirhelpers.c | 205 +++++++++++++++++++++++++++++++++++++++----- common/dirhelpers.h | 1 + 2 files changed, 184 insertions(+), 22 deletions(-) diff --git a/common/dirhelpers.c b/common/dirhelpers.c index 2e1a281c..5edccaad 100644 --- a/common/dirhelpers.c +++ b/common/dirhelpers.c @@ -30,38 +30,199 @@ #include #include #include +#include -bool -ensure_dir_exist( - const char * dirname, - int mode) +/* ret=true, err=0 - directory was created successfully */ +/* ret=true, err=EEXIST - directory already exists */ +/* ret=true, err=ENOENT - A directory component in dirname does not exist or is a dangling symbolic link */ +/* ret=true, err=error - directory creation failed in a bad way */ +/* ret=false, err=error - dirname is not valid directory path */ +static bool safe_mkdir(const char * dirname, int mode, int * err) { struct stat st; + + ASSERT(*dirname); /* empty string? */ + + if (mkdir(dirname, mode) == 0) + { + *err = 0; + return true; + } + + if (errno != EEXIST) + { + *err = errno; + return true; + } + + /* dirname path exists, not necessarily as a directory. + This includes the case where pathname is a symbolic link, + dangling or not. */ + if (stat(dirname, &st) != 0) { - if (errno == ENOENT) - { - log_info("Directory \"%s\" does not exist. Creating...", dirname); - if (mkdir(dirname, mode) != 0) - { - log_error("Failed to create \"%s\" directory: %d (%s)", dirname, errno, strerror(errno)); - return false; - } - } - else - { - log_error("Failed to stat \"%s\": %d (%s)", dirname, errno, strerror(errno)); - return false; - } + *err = errno; + log_error("Failed to stat \"%s\": %d (%s)", dirname, errno, strerror(errno)); + return false; } - else + else if (!S_ISDIR(st.st_mode)) { - if (!S_ISDIR(st.st_mode)) + *err = ENOTDIR; + log_error("\"%s\" exists but is not directory.", dirname); + return false; + } + + *err = EEXIST; + return true; +} + +static bool rmkdir(char * buffer, int mode) +{ + int err; + char * p; + size_t len; + bool last; + + len = 0; + p = buffer; +loop: + last = *p == 0; + if (!last) + { + if (*p != '/') { - log_error("\"%s\" exists but is not directory.", dirname); - return false; + len++; + p++; + goto loop; } + + if (len == 0) + { + /* skip extra '/' chars */ + p++; + goto loop; + } + + *p = 0; + } + else if (len == 0) + { + return true; + } + + if (!safe_mkdir(buffer, mode, &err)) + { + return false; + } + + switch (err) + { + case 0: + log_info("Directory \"%s\" created", buffer); + /* fall through */ + case EEXIST: + break; + default: + log_error("Failed to create \"%s\" directory: %d (%s)", buffer, errno, strerror(errno)); + return false; + } + + if (!last) + { + *p = '/'; + len = 0; + p++; + goto loop; } return true; } + +bool ensure_dir_exist(const char * dirname, int mode) +{ + size_t len; + char * buffer; + int err; + bool ret; + + if (!safe_mkdir(dirname, mode, &err)) + { + return false; + } + + if (err == 0 || err == EEXIST) + { + return true; + } + + if (errno != ENOENT) + { + log_error("Failed to create \"%s\" directory: %d (%s)", dirname, errno, strerror(errno)); + return false; + } + + /* A directory component in dirname does not exist or is a dangling symbolic link */ + + len = strlen(dirname); + + buffer = malloc(len + 1); + if (buffer == NULL) + { + log_error("malloc(%zu) failed.", len); + return false; + } + + memcpy(buffer, dirname, len); + buffer[len] = 0; + + ret = rmkdir(buffer, mode); + + free(buffer); + + return ret; +} + +bool ensure_dir_exist_varg(int mode, ...) +{ + va_list ap; + const char * str; + size_t len; + char * buffer; + char * p; + int ret; + + len = 0; + va_start(ap, mode); + while ((str = va_arg(ap, const char *)) != NULL) + { + len += strlen(str); + } + va_end(ap); + ASSERT(len > 0); + len++; + + buffer = malloc(len); + if (buffer == NULL) + { + log_error("malloc(%zu) failed.", len); + return false; + } + + p = buffer; + va_start(ap, mode); + while ((str = va_arg(ap, const char *)) != NULL) + { + len = strlen(str); + memcpy(buffer, str, len); + p += len; + } + va_end(ap); + ASSERT(p != buffer); + *p = 0; + + ret = rmkdir(buffer, mode); + + free(buffer); + + return ret; +} diff --git a/common/dirhelpers.h b/common/dirhelpers.h index 0b473383..1e135e41 100644 --- a/common/dirhelpers.h +++ b/common/dirhelpers.h @@ -28,5 +28,6 @@ #define DIRHELPERS_H__805193D2_2662_40FA_8814_AF8A4E08F4B0__INCLUDED bool ensure_dir_exist(const char * dirname, int mode); +bool ensure_dir_exist_varg(int mode, ...); #endif /* #ifndef DIRHELPERS_H__805193D2_2662_40FA_8814_AF8A4E08F4B0__INCLUDED */