OSDN Git Service

archive: don't queue excluded directories
authorRené Scharfe <l.s.r@web.de>
Sat, 19 Aug 2017 05:32:37 +0000 (07:32 +0200)
committerJunio C Hamano <gitster@pobox.com>
Sat, 19 Aug 2017 07:40:25 +0000 (00:40 -0700)
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>
archive.c
t/t5001-archive-attr.sh

index 66f1abe..2ad7e6c 100644 (file)
--- a/archive.c
+++ b/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);
 }
 
+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,
                int baselen, const char *filename, unsigned mode, int stage,
                void *context)
 {
        static struct strbuf path = STRBUF_INIT;
-       const struct attr_check *check;
        struct archiver_context *c = context;
        struct archiver_args *args = c->args;
        write_archive_entry_fn_t write_entry = c->write_entry;
-       const char *path_without_prefix;
        int err;
+       const char *path_without_prefix;
 
        args->convert = 0;
        strbuf_reset(&path);
@@ -143,10 +147,13 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
                strbuf_addch(&path, '/');
        path_without_prefix = path.buf + args->baselen;
 
-       check = get_archive_attrs(path_without_prefix);
-       if (check_attr_export_ignore(check))
-               return 0;
-       args->convert = check_attr_export_subst(check);
+       if (!S_ISDIR(mode) || !should_queue_directories(args)) {
+               const struct attr_check *check;
+               check = get_archive_attrs(path_without_prefix);
+               if (check_attr_export_ignore(check))
+                       return 0;
+               args->convert = check_attr_export_subst(check);
+       }
 
        if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
                if (args->verbose)
@@ -219,6 +226,17 @@ static int queue_or_write_archive_entry(const unsigned char *sha1,
        }
 
        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,
                                mode, stage, c);
                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,
-                                 args->pathspec.has_wildcard ?
+                                 should_queue_directories(args) ?
                                  queue_or_write_archive_entry :
                                  write_archive_entry_buf,
                                  &context);
index 063622b..897f6f0 100755 (executable)
@@ -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/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 &&
        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.d
 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/file