From f79b291646cf3ca6ed09d5a7356f34b8ea32b4e3 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 14 May 2009 17:22:42 +0200 Subject: [PATCH] Add a c_rmdirs() function. --- src/std/c_dir.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++--- src/std/c_dir.h | 11 ++++++++ 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/std/c_dir.c b/src/std/c_dir.c index 99fe8b1d0b..9d2a2bf92a 100644 --- a/src/std/c_dir.c +++ b/src/std/c_dir.c @@ -1,10 +1,13 @@ +#include #include +#include #include #include #include #include #include "c_macro.h" +#include "c_alloc.h" #include "c_dir.h" int c_mkdirs(const char *path, mode_t mode) { @@ -53,13 +56,76 @@ int c_mkdirs(const char *path, mode_t mode) { return tmp; } +int c_rmdirs(const char *path) { + DIR *d; + struct dirent *dp; + struct stat sb; + char *fname; + + if ((d = opendir(path)) != NULL) { + while(stat(path, &sb) == 0) { + /* if we can remove the directory we're done */ + if (rmdir(path) == 0) { + break; + } + switch (errno) { + case ENOTEMPTY: + case EEXIST: + case EBADF: + break; /* continue */ + default: + closedir(d); + return 0; + } + + while ((dp = readdir(d)) != NULL) { + size_t len; + /* skip '.' and '..' */ + if (dp->d_name[0] == '.' && + (dp->d_name[1] == '\0' || + (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) { + continue; + } + + len = strlen(path) + strlen(dp->d_name) + 2; + fname = c_malloc(len); + if (fname == NULL) { + return -1; + } + snprintf(fname, len, "%s/%s", path, dp->d_name); + + /* stat the file */ + if (lstat(fname, &sb) != -1) { + if (S_ISDIR(sb.st_mode) && !S_ISLNK(sb.st_mode)) { + if (rmdir(fname) < 0) { /* can't be deleted */ + if (errno == EACCES) { + closedir(d); + SAFE_FREE(fname); + return -1; + } + c_rmdirs(fname); + } + } else { + unlink(fname); + } + } /* lstat */ + SAFE_FREE(fname); + } /* readdir */ + + rewinddir(d); + } + } else { + return -1; + } + + closedir(d); + return 0; +} + int c_isdir(const char *path) { struct stat sb; - if (lstat (path, &sb) < 0) { - return 0; - } - if (S_ISDIR (sb.st_mode)) { + if (lstat (path, &sb) == 0 && S_ISDIR(sb.st_mode)) { return 1; } diff --git a/src/std/c_dir.h b/src/std/c_dir.h index 23c39529e5..ac2b559a5a 100644 --- a/src/std/c_dir.h +++ b/src/std/c_dir.h @@ -60,6 +60,17 @@ */ int c_mkdirs(const char *path, mode_t mode); +/** + * @brief Remove the directory and subdirectories including the content. + * + * This removes all directories and files recursivly. + * + * @param dir The directory to remove recusively. + * + * @return 0 on success, < 0 on error with errno set. + */ +int c_rmdirs(const char *dir); + /** * @brief Check if a path is a directory. *