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>

René Scharfe committed Aug 19, 2017 at 07:32 UTC 5ff247ac0cc9b2d09c8c24bd0c8df12eed94aebc
2 files changed +27 -9
archive.c
+25 -7
@@ -121,17 +121,21 @@ static int check_attr_export_subst(const struct attr_check *check)
121 return check && ATTR_TRUE(check->items[1].value);
122 }
123
124 +static int should_queue_directories(const struct archiver_args *args)
125 +{
126 + return args->pathspec.has_wildcard;
127 +}
128 +
129 static int write_archive_entry(const unsigned char *sha1, const char *base,
130 int baselen, const char *filename, unsigned mode, int stage,
131 void *context)
132 {
133 static struct strbuf path = STRBUF_INIT;
129 - const struct attr_check *check;
134 struct archiver_context *c = context;
135 struct archiver_args *args = c->args;
136 write_archive_entry_fn_t write_entry = c->write_entry;
133 - const char *path_without_prefix;
137 int err;
138 + const char *path_without_prefix;
139
140 args->convert = 0;
141 strbuf_reset(&path);
@@ -143,10 +147,13 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
147 strbuf_addch(&path, '/');
148 path_without_prefix = path.buf + args->baselen;
149
146 - check = get_archive_attrs(path_without_prefix);
147 - if (check_attr_export_ignore(check))
148 - return 0;
149 - args->convert = check_attr_export_subst(check);
150 + if (!S_ISDIR(mode) || !should_queue_directories(args)) {
151 + const struct attr_check *check;
152 + check = get_archive_attrs(path_without_prefix);
153 + if (check_attr_export_ignore(check))
154 + return 0;
155 + args->convert = check_attr_export_subst(check);
156 + }
157
158 if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
159 if (args->verbose)
@@ -219,6 +226,17 @@ static int queue_or_write_archive_entry(const unsigned char *sha1,
226 }
227
228 if (S_ISDIR(mode)) {
229 + size_t baselen = base->len;
230 + const struct attr_check *check;
231 +
232 + /* Borrow base, but restore its original value when done. */
233 + strbuf_addstr(base, filename);
234 + strbuf_addch(base, '/');
235 + check = get_archive_attrs(base->buf);
236 + strbuf_setlen(base, baselen);
237 +
238 + if (check_attr_export_ignore(check))
239 + return 0;
240 queue_directory(sha1, base, filename,
241 mode, stage, c);
242 return READ_TREE_RECURSIVE;
@@ -272,7 +290,7 @@ int write_archive_entries(struct archiver_args *args,
290 }
291
292 err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
275 - args->pathspec.has_wildcard ?
293 + should_queue_directories(args) ?
294 queue_or_write_archive_entry :
295 write_archive_entry_buf,
296 &context);
t/t5001-archive-attr.sh
+2 -2
@@ -76,7 +76,7 @@ test_expect_exists archive-pathspec/ignored-by-worktree
76 test_expect_missing archive-pathspec/excluded-by-pathspec.d failure
77 test_expect_missing archive-pathspec/excluded-by-pathspec.d/file
78
79 -test_expect_failure 'git archive with wildcard pathspec' '
79 +test_expect_success 'git archive with wildcard pathspec' '
80 git archive HEAD ":!excluded-by-p*" >archive-pathspec-wildcard.tar &&
81 extract_tar_to_dir archive-pathspec-wildcard
82 '
@@ -85,7 +85,7 @@ test_expect_missing archive-pathspec-wildcard/ignored
85 test_expect_missing archive-pathspec-wildcard/ignored-by-tree
86 test_expect_missing archive-pathspec-wildcard/ignored-by-tree.d
87 test_expect_missing archive-pathspec-wildcard/ignored-by-tree.d/file
88 -test_expect_exists archive-pathspec-wildcard/ignored-by-worktree failure
88 +test_expect_exists archive-pathspec-wildcard/ignored-by-worktree
89 test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d
90 test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d/file
91