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
This commit is contained in:
@ -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"
|
||||
@ -394,50 +396,55 @@ static void copy_alternates(struct strbuf *src, const char *src_repo)
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
|
||||
const char *src_repo, int src_baselen)
|
||||
static void mkdir_if_missing(const char *pathname, mode_t mode)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (!mkdir(pathname, mode))
|
||||
return;
|
||||
|
||||
if (errno != EEXIST)
|
||||
die_errno(_("failed to create directory '%s'"), pathname);
|
||||
else if (stat(pathname, &st))
|
||||
die_errno(_("failed to stat '%s'"), pathname);
|
||||
else if (!S_ISDIR(st.st_mode))
|
||||
die(_("%s exists and is not a directory"), pathname);
|
||||
}
|
||||
|
||||
static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
|
||||
const char *src_repo)
|
||||
{
|
||||
struct dirent *de;
|
||||
struct stat buf;
|
||||
int src_len, dest_len;
|
||||
DIR *dir;
|
||||
struct dir_iterator *iter;
|
||||
int iter_status;
|
||||
unsigned int flags;
|
||||
|
||||
dir = opendir(src->buf);
|
||||
if (!dir)
|
||||
die_errno(_("failed to open '%s'"), src->buf);
|
||||
mkdir_if_missing(dest->buf, 0777);
|
||||
|
||||
if (mkdir(dest->buf, 0777)) {
|
||||
if (errno != EEXIST)
|
||||
die_errno(_("failed to create directory '%s'"), dest->buf);
|
||||
else if (stat(dest->buf, &buf))
|
||||
die_errno(_("failed to stat '%s'"), dest->buf);
|
||||
else if (!S_ISDIR(buf.st_mode))
|
||||
die(_("%s exists and is not a directory"), dest->buf);
|
||||
}
|
||||
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 (de->d_name[0] != '.')
|
||||
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 (!fspathcmp(iter->relative_path, "info/alternates")) {
|
||||
copy_alternates(src, src_repo);
|
||||
continue;
|
||||
}
|
||||
@ -445,7 +452,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
|
||||
if (unlink(dest->buf) && errno != ENOENT)
|
||||
die_errno(_("failed to unlink '%s'"), dest->buf);
|
||||
if (!option_no_hardlinks) {
|
||||
if (!link(src->buf, dest->buf))
|
||||
if (!link(real_path(src->buf), dest->buf))
|
||||
continue;
|
||||
if (option_local > 0)
|
||||
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,
|
||||
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)
|
||||
@ -472,7 +483,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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user