From: Junio C Hamano <gitster@pobox.com>
Date: Mon, 21 Nov 2011 23:04:11 +0000 (-0800)
Subject: Merge branch 'jk/maint-1.6.2-upload-archive' into jk/maint-upload-archive
X-Git-Tag: v1.7.8.1~5^2
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7b51c33b376d22195dba1c4e067180164fd35dbf;p=git

Merge branch 'jk/maint-1.6.2-upload-archive' into jk/maint-upload-archive

* jk/maint-1.6.2-upload-archive:
  archive: don't let remote clients get unreachable commits

Conflicts:
	archive.c
	archive.h
	builtin-archive.c
	builtin/upload-archive.c
	t/t5000-tar-tree.sh
---

7b51c33b376d22195dba1c4e067180164fd35dbf
diff --cc archive.c
index 3fd7f475f1,251d69e153..5f0a3fc6d2
--- a/archive.c
+++ b/archive.c
@@@ -397,49 -339,14 +407,49 @@@ int write_archive(int argc, const char 
  	const struct archiver *ar = NULL;
  	struct archiver_args args;
  
 -	argc = parse_archive_args(argc, argv, &ar, &args);
  	if (setup_prefix && prefix == NULL)
 -		prefix = setup_git_directory();
 +		prefix = setup_git_directory_gently(&nongit);
 +
 +	git_config(git_default_config, NULL);
 +	init_tar_archiver();
 +	init_zip_archiver();
 +
 +	argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
 +	if (nongit) {
 +		/*
 +		 * We know this will die() with an error, so we could just
 +		 * die ourselves; but its error message will be more specific
 +		 * than what we could write here.
 +		 */
 +		setup_git_directory();
 +	}
  
- 	parse_treeish_arg(argv, &args, prefix);
+ 	parse_treeish_arg(argv, &args, prefix, remote);
  	parse_pathspec_arg(argv + 1, &args);
  
 -	git_config(git_default_config, NULL);
 +	return ar->write_archive(ar, &args);
 +}
  
 -	return ar->write_archive(&args);
 +static int match_extension(const char *filename, const char *ext)
 +{
 +	int prefixlen = strlen(filename) - strlen(ext);
 +
 +	/*
 +	 * We need 1 character for the '.', and 1 character to ensure that the
 +	 * prefix is non-empty (k.e., we don't match .tar.gz with no actual
 +	 * filename).
 +	 */
 +	if (prefixlen < 2 || filename[prefixlen-1] != '.')
 +		return 0;
 +	return !strcmp(filename + prefixlen, ext);
 +}
 +
 +const char *archive_format_from_filename(const char *filename)
 +{
 +	int i;
 +
 +	for (i = 0; i < nr_archivers; i++)
 +		if (match_extension(filename, archivers[i]->name))
 +			return archivers[i]->name;
 +	return NULL;
  }
diff --cc t/t5000-tar-tree.sh
index d9068981f8,1a2ee105a4..c05c676ca2
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@@ -242,114 -213,12 +242,122 @@@ test_expect_success 
      'git archive --list outside of a git repo' \
      'GIT_DIR=some/non-existing/directory git archive --list'
  
+ test_expect_success 'clients cannot access unreachable commits' '
+ 	test_commit unreachable &&
+ 	sha1=`git rev-parse HEAD` &&
+ 	git reset --hard HEAD^ &&
+ 	git archive $sha1 >remote.tar &&
+ 	test_must_fail git archive --remote=. $sha1 >remote.tar
+ '
+ 
 +test_expect_success 'git-archive --prefix=olde-' '
 +	git archive --prefix=olde- >h.tar HEAD &&
 +	(
 +		mkdir h &&
 +		cd h &&
 +		"$TAR" xf - <../h.tar
 +	) &&
 +	test -d h/olde-a &&
 +	test -d h/olde-a/bin &&
 +	test -f h/olde-a/bin/sh
 +'
 +
 +test_expect_success 'setup tar filters' '
 +	git config tar.tar.foo.command "tr ab ba" &&
 +	git config tar.bar.command "tr ab ba" &&
 +	git config tar.bar.remote true
 +'
 +
 +test_expect_success 'archive --list mentions user filter' '
 +	git archive --list >output &&
 +	grep "^tar\.foo\$" output &&
 +	grep "^bar\$" output
 +'
 +
 +test_expect_success NOT_MINGW 'archive --list shows only enabled remote filters' '
 +	git archive --list --remote=. >output &&
 +	! grep "^tar\.foo\$" output &&
 +	grep "^bar\$" output
 +'
 +
 +test_expect_success 'invoke tar filter by format' '
 +	git archive --format=tar.foo HEAD >config.tar.foo &&
 +	tr ab ba <config.tar.foo >config.tar &&
 +	test_cmp b.tar config.tar &&
 +	git archive --format=bar HEAD >config.bar &&
 +	tr ab ba <config.bar >config.tar &&
 +	test_cmp b.tar config.tar
 +'
 +
 +test_expect_success 'invoke tar filter by extension' '
 +	git archive -o config-implicit.tar.foo HEAD &&
 +	test_cmp config.tar.foo config-implicit.tar.foo &&
 +	git archive -o config-implicit.bar HEAD &&
 +	test_cmp config.tar.foo config-implicit.bar
 +'
 +
 +test_expect_success 'default output format remains tar' '
 +	git archive -o config-implicit.baz HEAD &&
 +	test_cmp b.tar config-implicit.baz
 +'
 +
 +test_expect_success 'extension matching requires dot' '
 +	git archive -o config-implicittar.foo HEAD &&
 +	test_cmp b.tar config-implicittar.foo
 +'
 +
 +test_expect_success NOT_MINGW 'only enabled filters are available remotely' '
 +	test_must_fail git archive --remote=. --format=tar.foo HEAD \
 +		>remote.tar.foo &&
 +	git archive --remote=. --format=bar >remote.bar HEAD &&
 +	test_cmp remote.bar config.bar
 +'
 +
 +if $GZIP --version >/dev/null 2>&1; then
 +	test_set_prereq GZIP
 +else
 +	say "Skipping some tar.gz tests because gzip not found"
 +fi
 +
 +test_expect_success GZIP 'git archive --format=tgz' '
 +	git archive --format=tgz HEAD >j.tgz
 +'
 +
 +test_expect_success GZIP 'git archive --format=tar.gz' '
 +	git archive --format=tar.gz HEAD >j1.tar.gz &&
 +	test_cmp j.tgz j1.tar.gz
 +'
 +
 +test_expect_success GZIP 'infer tgz from .tgz filename' '
 +	git archive --output=j2.tgz HEAD &&
 +	test_cmp j.tgz j2.tgz
 +'
 +
 +test_expect_success GZIP 'infer tgz from .tar.gz filename' '
 +	git archive --output=j3.tar.gz HEAD &&
 +	test_cmp j.tgz j3.tar.gz
 +'
 +
 +if $GUNZIP --version >/dev/null 2>&1; then
 +	test_set_prereq GUNZIP
 +else
 +	say "Skipping some tar.gz tests because gunzip was not found"
 +fi
 +
 +test_expect_success GZIP,GUNZIP 'extract tgz file' '
 +	$GUNZIP -c <j.tgz >j.tar &&
 +	test_cmp b.tar j.tar
 +'
 +
 +test_expect_success GZIP,NOT_MINGW 'remote tar.gz is allowed by default' '
 +	git archive --remote=. --format=tar.gz HEAD >remote.tar.gz &&
 +	test_cmp j.tgz remote.tar.gz
 +'
 +
 +test_expect_success GZIP,NOT_MINGW 'remote tar.gz can be disabled' '
 +	git config tar.tar.gz.remote false &&
 +	test_must_fail git archive --remote=. --format=tar.gz HEAD \
 +		>remote.tar.gz
 +'
 +
  test_done