Skip to content

Commit 080af91

Browse files
committed
Merge branch 'mt/dir-iterator-updates'
Adjust the dir-iterator API and apply it to the local clone optimization codepath. * mt/dir-iterator-updates: clone: replace strcmp by fspathcmp clone: use dir-iterator to avoid explicit dir traversal clone: extract function from copy_or_link_directory clone: copy hidden paths at local clone dir-iterator: add flags parameter to dir_iterator_begin dir-iterator: refactor state machine model dir-iterator: use warning_errno when possible dir-iterator: add tests for dir-iterator API clone: better handle symlinked files at .git/objects/ clone: test for our behavior on odd objects/* content
2 parents e13966d + c4d9c50 commit 080af91

10 files changed

+597
-164
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,7 @@ TEST_BUILTINS_OBJS += test-config.o
704704
TEST_BUILTINS_OBJS += test-ctype.o
705705
TEST_BUILTINS_OBJS += test-date.o
706706
TEST_BUILTINS_OBJS += test-delta.o
707+
TEST_BUILTINS_OBJS += test-dir-iterator.o
707708
TEST_BUILTINS_OBJS += test-drop-caches.o
708709
TEST_BUILTINS_OBJS += test-dump-cache-tree.o
709710
TEST_BUILTINS_OBJS += test-dump-fsmonitor.o

builtin/clone.c

+43-32
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"
@@ -394,58 +396,63 @@ static void copy_alternates(struct strbuf *src, const char *src_repo)
394396
fclose(in);
395397
}
396398

399+
static void mkdir_if_missing(const char *pathname, mode_t mode)
400+
{
401+
struct stat st;
402+
403+
if (!mkdir(pathname, mode))
404+
return;
405+
406+
if (errno != EEXIST)
407+
die_errno(_("failed to create directory '%s'"), pathname);
408+
else if (stat(pathname, &st))
409+
die_errno(_("failed to stat '%s'"), pathname);
410+
else if (!S_ISDIR(st.st_mode))
411+
die(_("%s exists and is not a directory"), pathname);
412+
}
413+
397414
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
398-
const char *src_repo, int src_baselen)
415+
const char *src_repo)
399416
{
400-
struct dirent *de;
401-
struct stat buf;
402417
int src_len, dest_len;
403-
DIR *dir;
404-
405-
dir = opendir(src->buf);
406-
if (!dir)
407-
die_errno(_("failed to open '%s'"), src->buf);
408-
409-
if (mkdir(dest->buf, 0777)) {
410-
if (errno != EEXIST)
411-
die_errno(_("failed to create directory '%s'"), dest->buf);
412-
else if (stat(dest->buf, &buf))
413-
die_errno(_("failed to stat '%s'"), dest->buf);
414-
else if (!S_ISDIR(buf.st_mode))
415-
die(_("%s exists and is not a directory"), dest->buf);
416-
}
418+
struct dir_iterator *iter;
419+
int iter_status;
420+
unsigned int flags;
421+
422+
mkdir_if_missing(dest->buf, 0777);
423+
424+
flags = DIR_ITERATOR_PEDANTIC | DIR_ITERATOR_FOLLOW_SYMLINKS;
425+
iter = dir_iterator_begin(src->buf, flags);
426+
427+
if (!iter)
428+
die_errno(_("failed to start iterator over '%s'"), src->buf);
417429

418430
strbuf_addch(src, '/');
419431
src_len = src->len;
420432
strbuf_addch(dest, '/');
421433
dest_len = dest->len;
422434

423-
while ((de = readdir(dir)) != NULL) {
435+
while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
424436
strbuf_setlen(src, src_len);
425-
strbuf_addstr(src, de->d_name);
437+
strbuf_addstr(src, iter->relative_path);
426438
strbuf_setlen(dest, dest_len);
427-
strbuf_addstr(dest, de->d_name);
428-
if (stat(src->buf, &buf)) {
429-
warning (_("failed to stat %s\n"), src->buf);
430-
continue;
431-
}
432-
if (S_ISDIR(buf.st_mode)) {
433-
if (de->d_name[0] != '.')
434-
copy_or_link_directory(src, dest,
435-
src_repo, src_baselen);
439+
strbuf_addstr(dest, iter->relative_path);
440+
441+
if (S_ISDIR(iter->st.st_mode)) {
442+
mkdir_if_missing(dest->buf, 0777);
436443
continue;
437444
}
438445

439446
/* Files that cannot be copied bit-for-bit... */
440-
if (!strcmp(src->buf + src_baselen, "/info/alternates")) {
447+
if (!fspathcmp(iter->relative_path, "info/alternates")) {
441448
copy_alternates(src, src_repo);
442449
continue;
443450
}
444451

445452
if (unlink(dest->buf) && errno != ENOENT)
446453
die_errno(_("failed to unlink '%s'"), dest->buf);
447454
if (!option_no_hardlinks) {
448-
if (!link(src->buf, dest->buf))
455+
if (!link(real_path(src->buf), dest->buf))
449456
continue;
450457
if (option_local > 0)
451458
die_errno(_("failed to create link '%s'"), dest->buf);
@@ -454,7 +461,11 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
454461
if (copy_file_with_time(dest->buf, src->buf, 0666))
455462
die_errno(_("failed to copy file to '%s'"), dest->buf);
456463
}
457-
closedir(dir);
464+
465+
if (iter_status != ITER_DONE) {
466+
strbuf_setlen(src, src_len);
467+
die(_("failed to iterate over '%s'"), src->buf);
468+
}
458469
}
459470

460471
static void clone_local(const char *src_repo, const char *dest_repo)
@@ -472,7 +483,7 @@ static void clone_local(const char *src_repo, const char *dest_repo)
472483
get_common_dir(&dest, dest_repo);
473484
strbuf_addstr(&src, "/objects");
474485
strbuf_addstr(&dest, "/objects");
475-
copy_or_link_directory(&src, &dest, src_repo, src.len);
486+
copy_or_link_directory(&src, &dest, src_repo);
476487
strbuf_release(&src);
477488
strbuf_release(&dest);
478489
}

0 commit comments

Comments
 (0)