diff options
author | Junio C Hamano <gitster@pobox.com> | 2018-01-12 13:38:09 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2018-01-12 13:38:09 -0800 |
commit | 2ebeec435e7bbc12e3a9e83d70499d0f8216343d (patch) | |
tree | 3985b63a74aabba0c9171c09b54fed6992d974b1 | |
parent | 50ff595721cae7da9420a604761cc228190d88bc (diff) | |
download | git-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.c | 58 | ||||
-rw-r--r-- | dir.h | 11 |
2 files changed, 57 insertions, 12 deletions
@@ -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, "ed); + printf(_(msg), quoted.buf); + strbuf_release("ed); +} + +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, "ed); + errno = saved_errno; + warning_errno(_(msg), quoted.buf); + strbuf_release("ed); +} + +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") @@ -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); |