remove_dir_recurse(): handle disappearing files and directories

If a file or directory that we are trying to remove disappears (e.g., because another process has pruned it), do not consider it an error. However, if REMOVE_DIR_KEEP_TOPLEVEL is set, and the toplevel directory is missing, then consider it an error (like before). Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Jan 18, 2014 at 23:48 UTC 863808cd1a7bd23dc12a3b54e32eb3f25d9487bc
1 file changed +16 -6
dir.c
+16 -6
@@ -1476,7 +1476,9 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
1476 flag &= ~REMOVE_DIR_KEEP_TOPLEVEL;
1477 dir = opendir(path->buf);
1478 if (!dir) {
1479 - if (errno == EACCES && !keep_toplevel)
1479 + if (errno == ENOENT)
1480 + return keep_toplevel ? -1 : 0;
1481 + else if (errno == EACCES && !keep_toplevel)
1482 /*
1483 * An empty dir could be removable even if it
1484 * is unreadable:
@@ -1496,13 +1498,21 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
1498
1499 strbuf_setlen(path, len);
1500 strbuf_addstr(path, e->d_name);
1499 - if (lstat(path->buf, &st))
1500 - ; /* fall thru */
1501 - else if (S_ISDIR(st.st_mode)) {
1501 + if (lstat(path->buf, &st)) {
1502 + if (errno == ENOENT)
1503 + /*
1504 + * file disappeared, which is what we
1505 + * wanted anyway
1506 + */
1507 + continue;
1508 + /* fall thru */
1509 + } else if (S_ISDIR(st.st_mode)) {
1510 if (!remove_dir_recurse(path, flag, &kept_down))
1511 continue; /* happy */
1504 - } else if (!only_empty && !unlink(path->buf))
1512 + } else if (!only_empty &&
1513 + (!unlink(path->buf) || errno == ENOENT)) {
1514 continue; /* happy, too */
1515 + }
1516
1517 /* path too long, stat fails, or non-directory still exists */
1518 ret = -1;
@@ -1512,7 +1522,7 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
1522
1523 strbuf_setlen(path, original_len);
1524 if (!ret && !keep_toplevel && !kept_down)
1515 - ret = rmdir(path->buf);
1525 + ret = (!rmdir(path->buf) || errno == ENOENT) ? 0 : -1;
1526 else if (kept_up)
1527 /*
1528 * report the uplevel that it is not an error that we