Replace usage of opendir/readdir/closedir API to traverse directories
recursively, at copy_or_link_directory function, by the dir-iterator
API. This simplifies the code and avoids recursive calls to
copy_or_link_directory.

This process also makes copy_or_link_directory call die() in case of an
error on readdir or stat inside dir_iterator_advance. Previously it
would just print a warning for errors on stat and ignore errors on
readdir, which isn't nice because a local git clone could succeed even
though the .git/objects copy didn't fully succeed. Also, with the
dir-iterator API, recursive symlinks will be detected and skipped. This
is another behavior improvement, since the current version would
continue to copy the same content over and over until stat() returned an
ELOOP error.

Signed-off-by: Matheus Tavares <matheus.bernard...@usp.br>
---
 builtin/clone.c | 47 +++++++++++++++++++++++++----------------------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index 1ee6d6050e..f99acd878f 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -23,6 +23,8 @@
 #include "transport.h"
 #include "strbuf.h"
 #include "dir.h"
+#include "dir-iterator.h"
+#include "iterator.h"
 #include "sigchain.h"
 #include "branch.h"
 #include "remote.h"
@@ -408,42 +410,39 @@ static void mkdir_if_missing(const char *pathname, mode_t 
mode)
 }
 
 static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
-                                  const char *src_repo, int src_baselen)
+                                  const char *src_repo)
 {
-       struct dirent *de;
-       struct stat buf;
        int src_len, dest_len;
-       DIR *dir;
-
-       dir = opendir(src->buf);
-       if (!dir)
-               die_errno(_("failed to open '%s'"), src->buf);
+       struct dir_iterator *iter;
+       int iter_status;
+       unsigned int flags;
 
        mkdir_if_missing(dest->buf, 0777);
 
+       flags = DIR_ITERATOR_PEDANTIC | DIR_ITERATOR_FOLLOW_SYMLINKS;
+       iter = dir_iterator_begin(src->buf, flags);
+
+       if (!iter)
+               die_errno(_("failed to start iterator over '%s'"), src->buf);
+
        strbuf_addch(src, '/');
        src_len = src->len;
        strbuf_addch(dest, '/');
        dest_len = dest->len;
 
-       while ((de = readdir(dir)) != NULL) {
+       while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
                strbuf_setlen(src, src_len);
-               strbuf_addstr(src, de->d_name);
+               strbuf_addstr(src, iter->relative_path);
                strbuf_setlen(dest, dest_len);
-               strbuf_addstr(dest, de->d_name);
-               if (stat(src->buf, &buf)) {
-                       warning (_("failed to stat %s\n"), src->buf);
-                       continue;
-               }
-               if (S_ISDIR(buf.st_mode)) {
-                       if (!is_dot_or_dotdot(de->d_name))
-                               copy_or_link_directory(src, dest,
-                                                      src_repo, src_baselen);
+               strbuf_addstr(dest, iter->relative_path);
+
+               if (S_ISDIR(iter->st.st_mode)) {
+                       mkdir_if_missing(dest->buf, 0777);
                        continue;
                }
 
                /* Files that cannot be copied bit-for-bit... */
-               if (!strcmp(src->buf + src_baselen, "/info/alternates")) {
+               if (!strcmp(iter->relative_path, "info/alternates")) {
                        copy_alternates(src, dest, src_repo);
                        continue;
                }
@@ -460,7 +459,11 @@ static void copy_or_link_directory(struct strbuf *src, 
struct strbuf *dest,
                if (copy_file_with_time(dest->buf, src->buf, 0666))
                        die_errno(_("failed to copy file to '%s'"), dest->buf);
        }
-       closedir(dir);
+
+       if (iter_status != ITER_DONE) {
+               strbuf_setlen(src, src_len);
+               die(_("failed to iterate over '%s'"), src->buf);
+       }
 }
 
 static void clone_local(const char *src_repo, const char *dest_repo)
@@ -478,7 +481,7 @@ static void clone_local(const char *src_repo, const char 
*dest_repo)
                get_common_dir(&dest, dest_repo);
                strbuf_addstr(&src, "/objects");
                strbuf_addstr(&dest, "/objects");
-               copy_or_link_directory(&src, &dest, src_repo, src.len);
+               copy_or_link_directory(&src, &dest, src_repo);
                strbuf_release(&src);
                strbuf_release(&dest);
        }
-- 
2.20.1

Reply via email to