summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2018-01-12 13:38:09 -0800
committerJunio C Hamano <gitster@pobox.com>2018-01-12 13:38:09 -0800
commit2ebeec435e7bbc12e3a9e83d70499d0f8216343d (patch)
tree3985b63a74aabba0c9171c09b54fed6992d974b1
parent50ff595721cae7da9420a604761cc228190d88bc (diff)
downloadgit-jc/remove-dir-recursively.tar.gz
dir.c: report errors from remove_dir_recurse()jc/remove-dir-recursively
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--dir.c58
-rw-r--r--dir.h11
2 files changed, 57 insertions, 12 deletions
diff --git a/dir.c b/dir.c
index 1ec6276014..da8f966baa 100644
--- a/dir.c
+++ b/dir.c
@@ -15,6 +15,7 @@
#include "refs.h"
#include "wildmatch.h"
#include "pathspec.h"
+#include "quote.h"
#include "utf8.h"
#include "varint.h"
#include "ewah/ewok.h"
@@ -2389,17 +2390,44 @@ int is_empty_dir(const char *path)
return ret;
}
-static int remove_dir_recurse(struct strbuf *path, unsigned flags, int *kept_up)
+static void report_path(const char *msg, const char *pathbuf, const char *prefix)
+{
+ struct strbuf quoted = STRBUF_INIT;
+
+ quote_path_relative(pathbuf, prefix, &quoted);
+ printf(_(msg), quoted.buf);
+ strbuf_release(&quoted);
+}
+
+static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
+static const char *msg_warn_remove_failed = N_("failed to remove %s");
+
+static void warn_path(const char *msg, const char *pathbuf, const char *prefix)
+{
+ struct strbuf quoted = STRBUF_INIT;
+ int saved_errno = errno;
+
+ quote_path_relative(pathbuf, prefix, &quoted);
+ errno = saved_errno;
+ warning_errno(_(msg), quoted.buf);
+ strbuf_release(&quoted);
+}
+
+static int remove_dir_recurse(struct strbuf *path, const char *prefix,
+ unsigned flags, int *kept_up)
{
DIR *dir;
struct dirent *e;
int ret = 0, original_len = path->len, len, kept_down = 0;
int only_empty = !!(flags & REMOVE_DIR_EMPTY_ONLY);
int keep_toplevel = !!(flags & REMOVE_DIR_KEEP_TOPLEVEL);
+ unsigned verbosity = (flags & REMOVE_DIR_VERBOSITY_MASK);
if ((flags & REMOVE_DIR_KEEP_NESTED_GIT) &&
is_nonbare_repository_dir(path)) {
/* Do not descend and nuke a nested git work tree. */
+ if (REMOVE_DIR_VERBOSELY <= verbosity)
+ report_path(msg_skip_git_dir, path->buf, prefix);
if (kept_up)
*kept_up = 1;
return 0;
@@ -2408,16 +2436,19 @@ static int remove_dir_recurse(struct strbuf *path, unsigned flags, int *kept_up)
flags &= ~REMOVE_DIR_KEEP_TOPLEVEL;
dir = opendir(path->buf);
if (!dir) {
- if (errno == ENOENT)
+ if (errno == ENOENT) {
return keep_toplevel ? -1 : 0;
- else if (errno == EACCES && !keep_toplevel)
+ } else if (errno == EACCES && !keep_toplevel) {
/*
* An empty dir could be removable even if it
* is unreadable:
*/
- return rmdir(path->buf);
- else
- return -1;
+ if (!rmdir(path->buf))
+ return 0;
+ }
+ if (REMOVE_DIR_WITH_WARNING <= verbosity)
+ warn_path(msg_warn_remove_failed, path->buf, prefix);
+ return -1;
}
strbuf_complete(path, '/');
@@ -2438,7 +2469,7 @@ static int remove_dir_recurse(struct strbuf *path, unsigned flags, int *kept_up)
continue;
/* fall thru */
} else if (S_ISDIR(st.st_mode)) {
- if (!remove_dir_recurse(path, flags, &kept_down))
+ if (!remove_dir_recurse(path, prefix, flags, &kept_down))
continue; /* happy */
} else if (!only_empty &&
(!unlink(path->buf) || errno == ENOENT)) {
@@ -2446,26 +2477,31 @@ static int remove_dir_recurse(struct strbuf *path, unsigned flags, int *kept_up)
}
/* path too long, stat fails, or non-directory still exists */
+ if (REMOVE_DIR_WITH_WARNING <= verbosity)
+ warn_path(msg_warn_remove_failed, path->buf, prefix);
ret = -1;
break;
}
closedir(dir);
strbuf_setlen(path, original_len);
- if (!ret && !keep_toplevel && !kept_down)
+ if (!ret && !keep_toplevel && !kept_down) {
ret = (!rmdir(path->buf) || errno == ENOENT) ? 0 : -1;
- else if (kept_up)
+ if (ret && (REMOVE_DIR_WITH_WARNING <= verbosity))
+ warn_path(msg_warn_remove_failed, path->buf, prefix);
+ } else if (kept_up) {
/*
* report the uplevel that it is not an error that we
* did not rmdir() our directory.
*/
*kept_up = !ret;
+ }
return ret;
}
-int remove_dir_recursively(struct strbuf *path, unsigned flags)
+int remove_dir_re(struct strbuf *path, const char *prefix, unsigned flags)
{
- return remove_dir_recurse(path, flags, NULL);
+ return remove_dir_recurse(path, prefix, flags, NULL);
}
static GIT_PATH_FUNC(git_path_info_exclude, "info/exclude")
diff --git a/dir.h b/dir.h
index 65eec658c2..f46c52b021 100644
--- a/dir.h
+++ b/dir.h
@@ -302,6 +302,11 @@ extern void setup_standard_excludes(struct dir_struct *dir);
/* Remove the contents of path, but leave path itself. */
#define REMOVE_DIR_KEEP_TOPLEVEL 04
+/* Verbosity levels (2 bits at 060) */
+#define REMOVE_DIR_VERBOSITY_MASK 060
+#define REMOVE_DIR_WITH_WARNING 020
+#define REMOVE_DIR_VERBOSELY 040
+
/*
* Remove path and its contents, recursively. flags is a combination
* of the above REMOVE_DIR_* constants. Return 0 on success.
@@ -309,7 +314,11 @@ extern void setup_standard_excludes(struct dir_struct *dir);
* This function uses path as temporary scratch space, but restores it
* before returning.
*/
-extern int remove_dir_recursively(struct strbuf *path, unsigned flags);
+#define remove_dir_recursively(path, flags) remove_dir_re((path), NULL, (flags))
+
+/* The same as above, but paths are reported relative to prefix */
+extern int remove_dir_re(struct strbuf *path, const char *prefix, unsigned flags);
+
/* tries to remove the path with empty directories along it, ignores ENOENT */
extern int remove_path(const char *path);