From 035cdaa00bd5d46984129789dbd5189e86b74bac Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 28 Mar 2013 14:46:45 +0000 Subject: [PATCH] Introduce a virFileDeleteTree method Introduce a method virFileDeleteTree for recursively deleting an entire directory tree Signed-off-by: Daniel P. Berrange --- src/libvirt_private.syms | 1 + src/util/virfile.c | 83 ++++++++++++++++++++++++++++++++++++++++ src/util/virfile.h | 2 + 3 files changed, 86 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8d8d56d2e9..ee42735851 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1264,6 +1264,7 @@ virEventPollUpdateTimeout; # util/virfile.h virFileClose; +virFileDeleteTree; virFileDirectFdFlag; virFileFclose; virFileFdopen; diff --git a/src/util/virfile.c b/src/util/virfile.c index 4a9fa811b2..fbaeeddbe8 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -644,3 +644,86 @@ int virFileLoopDeviceAssociate(const char *file, } #endif /* __linux__ */ + + +/** + * virFileDeleteTree: + * + * Recursively deletes all files / directories + * starting from the directory @dir. Does not + * follow symlinks + * + * NB the algorithm is not efficient, and is subject to + * race conditions which can be exploited by malicious + * code. It should not be used in any scenarios where + * performance is important, or security is critical. + */ +int virFileDeleteTree(const char *dir) +{ + DIR *dh = opendir(dir); + struct dirent *de; + char *filepath = NULL; + int ret = -1; + + if (!dh) { + virReportSystemError(errno, _("Cannot open dir '%s'"), + dir); + return -1; + } + + errno = 0; + while ((de = readdir(dh)) != NULL) { + struct stat sb; + + if (STREQ(de->d_name, ".") || + STREQ(de->d_name, "..")) + continue; + + if (virAsprintf(&filepath, "%s/%s", + dir, de->d_name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (lstat(filepath, &sb) < 0) { + virReportSystemError(errno, _("Cannot access '%s'"), + filepath); + goto cleanup; + } + + if (S_ISDIR(sb.st_mode)) { + if (virFileDeleteTree(filepath) < 0) + goto cleanup; + } else { + if (unlink(filepath) < 0 && errno != ENOENT) { + virReportSystemError(errno, + _("Cannot delete file '%s'"), + filepath); + goto cleanup; + } + } + + VIR_FREE(filepath); + errno = 0; + } + + if (errno) { + virReportSystemError(errno, _("Cannot read dir '%s'"), + dir); + goto cleanup; + } + + if (rmdir(dir) < 0 && errno != ENOENT) { + virReportSystemError(errno, + _("Cannot delete directory '%s'"), + dir); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(filepath); + closedir(dh); + return ret; +} diff --git a/src/util/virfile.h b/src/util/virfile.h index c885b73c36..5f0dd2ba2a 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -108,4 +108,6 @@ int virFileUpdatePerm(const char *path, int virFileLoopDeviceAssociate(const char *file, char **dev); +int virFileDeleteTree(const char *dir); + #endif /* __VIR_FILES_H */ -- GitLab