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 <matheus.bernardino@usp.br> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Matheus Tavares committed
Jul 10, 2019 at 20:59 UTC
ff7ccc8c9a6e61a7225c161c743a49ac079f1425
1 file changed
+25
-22
builtin/clone.c
+25
-22
@@ -23,6 +23,8 @@
23
#include "transport.h"
24
#include "strbuf.h"
25
#include "dir.h"
26
+#include "dir-iterator.h"
27
+#include "iterator.h"
28
#include "sigchain.h"
29
#include "branch.h"
30
#include "remote.h"
@@ -407,42 +409,39 @@ static void mkdir_if_missing(const char *pathname, mode_t mode)
409
}
410
411
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)
413
{
412
- struct dirent *de;
413
- struct stat buf;
414
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;
418
419
mkdir_if_missing(dest->buf, 0777);
420
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
+
427
strbuf_addch(src, '/');
428
src_len = src->len;
429
strbuf_addch(dest, '/');
430
dest_len = dest->len;
431
428
- while ((de = readdir(dir)) != NULL) {
432
+ while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
433
strbuf_setlen(src, src_len);
430
- strbuf_addstr(src, de->d_name);
434
+ strbuf_addstr(src, iter->relative_path);
435
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);
440
continue;
441
}
442
443
/* 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")) {
445
copy_alternates(src, src_repo);
446
continue;
447
}
@@ -459,7 +458,11 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
458
if (copy_file_with_time(dest->buf, src->buf, 0666))
459
die_errno(_("failed to copy file to '%s'"), dest->buf);
460
}
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
+ }
466
}
467
468
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)
480
get_common_dir(&dest, dest_repo);
481
strbuf_addstr(&src, "/objects");
482
strbuf_addstr(&dest, "/objects");
480
- copy_or_link_directory(&src, &dest, src_repo, src.len);
483
+ copy_or_link_directory(&src, &dest, src_repo);
484
strbuf_release(&src);
485
strbuf_release(&dest);
486
}