Skip to content

Commit ff7ccc8

Browse files
matheustavaresgitster
authored andcommitted
clone: use dir-iterator to avoid explicit dir traversal
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. Signed-off-by: Matheus Tavares <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 14954b7 commit ff7ccc8

File tree

1 file changed

+25
-22
lines changed

1 file changed

+25
-22
lines changed

builtin/clone.c

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "transport.h"
2424
#include "strbuf.h"
2525
#include "dir.h"
26+
#include "dir-iterator.h"
27+
#include "iterator.h"
2628
#include "sigchain.h"
2729
#include "branch.h"
2830
#include "remote.h"
@@ -407,42 +409,39 @@ static void mkdir_if_missing(const char *pathname, mode_t mode)
407409
}
408410

409411
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
410-
const char *src_repo, int src_baselen)
412+
const char *src_repo)
411413
{
412-
struct dirent *de;
413-
struct stat buf;
414414
int src_len, dest_len;
415-
DIR *dir;
416-
417-
dir = opendir(src->buf);
418-
if (!dir)
419-
die_errno(_("failed to open '%s'"), src->buf);
415+
struct dir_iterator *iter;
416+
int iter_status;
417+
unsigned int flags;
420418

421419
mkdir_if_missing(dest->buf, 0777);
422420

421+
flags = DIR_ITERATOR_PEDANTIC | DIR_ITERATOR_FOLLOW_SYMLINKS;
422+
iter = dir_iterator_begin(src->buf, flags);
423+
424+
if (!iter)
425+
die_errno(_("failed to start iterator over '%s'"), src->buf);
426+
423427
strbuf_addch(src, '/');
424428
src_len = src->len;
425429
strbuf_addch(dest, '/');
426430
dest_len = dest->len;
427431

428-
while ((de = readdir(dir)) != NULL) {
432+
while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
429433
strbuf_setlen(src, src_len);
430-
strbuf_addstr(src, de->d_name);
434+
strbuf_addstr(src, iter->relative_path);
431435
strbuf_setlen(dest, dest_len);
432-
strbuf_addstr(dest, de->d_name);
433-
if (stat(src->buf, &buf)) {
434-
warning (_("failed to stat %s\n"), src->buf);
435-
continue;
436-
}
437-
if (S_ISDIR(buf.st_mode)) {
438-
if (!is_dot_or_dotdot(de->d_name))
439-
copy_or_link_directory(src, dest,
440-
src_repo, src_baselen);
436+
strbuf_addstr(dest, iter->relative_path);
437+
438+
if (S_ISDIR(iter->st.st_mode)) {
439+
mkdir_if_missing(dest->buf, 0777);
441440
continue;
442441
}
443442

444443
/* Files that cannot be copied bit-for-bit... */
445-
if (!strcmp(src->buf + src_baselen, "/info/alternates")) {
444+
if (!strcmp(iter->relative_path, "info/alternates")) {
446445
copy_alternates(src, src_repo);
447446
continue;
448447
}
@@ -459,7 +458,11 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
459458
if (copy_file_with_time(dest->buf, src->buf, 0666))
460459
die_errno(_("failed to copy file to '%s'"), dest->buf);
461460
}
462-
closedir(dir);
461+
462+
if (iter_status != ITER_DONE) {
463+
strbuf_setlen(src, src_len);
464+
die(_("failed to iterate over '%s'"), src->buf);
465+
}
463466
}
464467

465468
static void clone_local(const char *src_repo, const char *dest_repo)
@@ -477,7 +480,7 @@ static void clone_local(const char *src_repo, const char *dest_repo)
477480
get_common_dir(&dest, dest_repo);
478481
strbuf_addstr(&src, "/objects");
479482
strbuf_addstr(&dest, "/objects");
480-
copy_or_link_directory(&src, &dest, src_repo, src.len);
483+
copy_or_link_directory(&src, &dest, src_repo);
481484
strbuf_release(&src);
482485
strbuf_release(&dest);
483486
}

0 commit comments

Comments
 (0)