readdir() used to do a single pass, which is not always enough. If you unlink some files/rmdir some subdirs then there might be some files you haven't seen yet *before* the readdir cursor (files get rearranged in the directory, etc.). The fix is to do an additional readdir() pass if we unlinked/rmdired something. This is easily accomplished by using rewinddir. Signed-off-by: Török Edwin <edwintorok@xxxxxxxxx> --- dir.c | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-) diff --git a/dir.c b/dir.c index 5615f33..7260907 100644 --- a/dir.c +++ b/dir.c @@ -999,6 +999,7 @@ int remove_dir_recursively(struct strbuf *path, int flag) struct dirent *e; int ret = 0, original_len = path->len, len; int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY); + int did_rm; unsigned char submodule_head[20]; if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) && @@ -1013,6 +1014,8 @@ int remove_dir_recursively(struct strbuf *path, int flag) strbuf_addch(path, '/'); len = path->len; + do { + did_rm = 0; while ((e = readdir(dir)) != NULL) { struct stat st; if (is_dot_or_dotdot(e->d_name)) @@ -1023,15 +1026,24 @@ int remove_dir_recursively(struct strbuf *path, int flag) if (lstat(path->buf, &st)) ; /* fall thru */ else if (S_ISDIR(st.st_mode)) { - if (!remove_dir_recursively(path, only_empty)) + if (!remove_dir_recursively(path, only_empty)) { + did_rm = 1; continue; /* happy */ - } else if (!only_empty && !unlink(path->buf)) + } + } else if (!only_empty && !unlink(path->buf)) { + did_rm = 1; continue; /* happy, too */ + } /* path too long, stat fails, or non-directory still exists */ ret = -1; break; } + /* if we unlinked/rmdir-ed anything there might be files we haven't seen + * yet before the readdir() cursor, rewind and walk directory again + * until we can't unlink any more. */ + rewinddir(dir); + } while (did_rm && !ret); closedir(dir); strbuf_setlen(path, original_len); -- 1.7.0 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html