archive: don't queue excluded directories
Reject directories with the attribute export-ignore already while queuing them. This prevents read_tree_recursive() from descending into them and this avoids write_archive_entry() rejecting them later on, which queue_or_write_archive_entry() is not prepared for. Borrow the existing strbuf to build the full path to avoid string copies and extra allocations; just make sure we restore the original value before moving on. Keep checking any other attributes in write_archive_entry() as before, but avoid checking them twice. Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
c6c08f7e9a
commit
5ff247ac0c
24
archive.c
24
archive.c
@ -121,17 +121,21 @@ static int check_attr_export_subst(const struct attr_check *check)
|
|||||||
return check && ATTR_TRUE(check->items[1].value);
|
return check && ATTR_TRUE(check->items[1].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int should_queue_directories(const struct archiver_args *args)
|
||||||
|
{
|
||||||
|
return args->pathspec.has_wildcard;
|
||||||
|
}
|
||||||
|
|
||||||
static int write_archive_entry(const unsigned char *sha1, const char *base,
|
static int write_archive_entry(const unsigned char *sha1, const char *base,
|
||||||
int baselen, const char *filename, unsigned mode, int stage,
|
int baselen, const char *filename, unsigned mode, int stage,
|
||||||
void *context)
|
void *context)
|
||||||
{
|
{
|
||||||
static struct strbuf path = STRBUF_INIT;
|
static struct strbuf path = STRBUF_INIT;
|
||||||
const struct attr_check *check;
|
|
||||||
struct archiver_context *c = context;
|
struct archiver_context *c = context;
|
||||||
struct archiver_args *args = c->args;
|
struct archiver_args *args = c->args;
|
||||||
write_archive_entry_fn_t write_entry = c->write_entry;
|
write_archive_entry_fn_t write_entry = c->write_entry;
|
||||||
const char *path_without_prefix;
|
|
||||||
int err;
|
int err;
|
||||||
|
const char *path_without_prefix;
|
||||||
|
|
||||||
args->convert = 0;
|
args->convert = 0;
|
||||||
strbuf_reset(&path);
|
strbuf_reset(&path);
|
||||||
@ -143,10 +147,13 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
|
|||||||
strbuf_addch(&path, '/');
|
strbuf_addch(&path, '/');
|
||||||
path_without_prefix = path.buf + args->baselen;
|
path_without_prefix = path.buf + args->baselen;
|
||||||
|
|
||||||
|
if (!S_ISDIR(mode) || !should_queue_directories(args)) {
|
||||||
|
const struct attr_check *check;
|
||||||
check = get_archive_attrs(path_without_prefix);
|
check = get_archive_attrs(path_without_prefix);
|
||||||
if (check_attr_export_ignore(check))
|
if (check_attr_export_ignore(check))
|
||||||
return 0;
|
return 0;
|
||||||
args->convert = check_attr_export_subst(check);
|
args->convert = check_attr_export_subst(check);
|
||||||
|
}
|
||||||
|
|
||||||
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
|
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
|
||||||
if (args->verbose)
|
if (args->verbose)
|
||||||
@ -219,6 +226,17 @@ static int queue_or_write_archive_entry(const unsigned char *sha1,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISDIR(mode)) {
|
if (S_ISDIR(mode)) {
|
||||||
|
size_t baselen = base->len;
|
||||||
|
const struct attr_check *check;
|
||||||
|
|
||||||
|
/* Borrow base, but restore its original value when done. */
|
||||||
|
strbuf_addstr(base, filename);
|
||||||
|
strbuf_addch(base, '/');
|
||||||
|
check = get_archive_attrs(base->buf);
|
||||||
|
strbuf_setlen(base, baselen);
|
||||||
|
|
||||||
|
if (check_attr_export_ignore(check))
|
||||||
|
return 0;
|
||||||
queue_directory(sha1, base, filename,
|
queue_directory(sha1, base, filename,
|
||||||
mode, stage, c);
|
mode, stage, c);
|
||||||
return READ_TREE_RECURSIVE;
|
return READ_TREE_RECURSIVE;
|
||||||
@ -272,7 +290,7 @@ int write_archive_entries(struct archiver_args *args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
|
err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
|
||||||
args->pathspec.has_wildcard ?
|
should_queue_directories(args) ?
|
||||||
queue_or_write_archive_entry :
|
queue_or_write_archive_entry :
|
||||||
write_archive_entry_buf,
|
write_archive_entry_buf,
|
||||||
&context);
|
&context);
|
||||||
|
@ -76,7 +76,7 @@ test_expect_exists archive-pathspec/ignored-by-worktree
|
|||||||
test_expect_missing archive-pathspec/excluded-by-pathspec.d failure
|
test_expect_missing archive-pathspec/excluded-by-pathspec.d failure
|
||||||
test_expect_missing archive-pathspec/excluded-by-pathspec.d/file
|
test_expect_missing archive-pathspec/excluded-by-pathspec.d/file
|
||||||
|
|
||||||
test_expect_failure 'git archive with wildcard pathspec' '
|
test_expect_success 'git archive with wildcard pathspec' '
|
||||||
git archive HEAD ":!excluded-by-p*" >archive-pathspec-wildcard.tar &&
|
git archive HEAD ":!excluded-by-p*" >archive-pathspec-wildcard.tar &&
|
||||||
extract_tar_to_dir archive-pathspec-wildcard
|
extract_tar_to_dir archive-pathspec-wildcard
|
||||||
'
|
'
|
||||||
@ -85,7 +85,7 @@ test_expect_missing archive-pathspec-wildcard/ignored
|
|||||||
test_expect_missing archive-pathspec-wildcard/ignored-by-tree
|
test_expect_missing archive-pathspec-wildcard/ignored-by-tree
|
||||||
test_expect_missing archive-pathspec-wildcard/ignored-by-tree.d
|
test_expect_missing archive-pathspec-wildcard/ignored-by-tree.d
|
||||||
test_expect_missing archive-pathspec-wildcard/ignored-by-tree.d/file
|
test_expect_missing archive-pathspec-wildcard/ignored-by-tree.d/file
|
||||||
test_expect_exists archive-pathspec-wildcard/ignored-by-worktree failure
|
test_expect_exists archive-pathspec-wildcard/ignored-by-worktree
|
||||||
test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d
|
test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d
|
||||||
test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d/file
|
test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d/file
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user