summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archive.c20
-rw-r--r--archive.h3
-rw-r--r--builtin-archive.c2
-rw-r--r--builtin-upload-archive.c2
-rwxr-xr-xt/t5000-tar-tree.sh8
5 files changed, 27 insertions, 8 deletions
diff --git a/archive.c b/archive.c
index e6de0397cc..251d69e153 100644
--- a/archive.c
+++ b/archive.c
@@ -196,7 +196,8 @@ static void parse_pathspec_arg(const char **pathspec,
}
static void parse_treeish_arg(const char **argv,
- struct archiver_args *ar_args, const char *prefix)
+ struct archiver_args *ar_args, const char *prefix,
+ int remote)
{
const char *name = argv[0];
const unsigned char *commit_sha1;
@@ -205,8 +206,17 @@ static void parse_treeish_arg(const char **argv,
const struct commit *commit;
unsigned char sha1[20];
- if (get_sha1(name, sha1))
- die("Not a valid object name");
+ /* Remotes are only allowed to fetch actual refs */
+ if (remote) {
+ char *ref = NULL;
+ if (!dwim_ref(name, strlen(name), sha1, &ref))
+ die("no such ref: %s", name);
+ free(ref);
+ }
+ else {
+ if (get_sha1(name, sha1))
+ die("Not a valid object name");
+ }
commit = lookup_commit_reference_gently(sha1, 1);
if (commit) {
@@ -324,7 +334,7 @@ static int parse_archive_args(int argc, const char **argv,
}
int write_archive(int argc, const char **argv, const char *prefix,
- int setup_prefix)
+ int setup_prefix, int remote)
{
const struct archiver *ar = NULL;
struct archiver_args args;
@@ -333,7 +343,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
if (setup_prefix && prefix == NULL)
prefix = 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);
diff --git a/archive.h b/archive.h
index 0b15b35143..9375057d72 100644
--- a/archive.h
+++ b/archive.h
@@ -24,6 +24,7 @@ extern int write_tar_archive(struct archiver_args *);
extern int write_zip_archive(struct archiver_args *);
extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
-extern int write_archive(int argc, const char **argv, const char *prefix, int setup_prefix);
+extern int write_archive(int argc, const char **argv, const char *prefix,
+ int setup_prefix, int remote);
#endif /* ARCHIVE_H */
diff --git a/builtin-archive.c b/builtin-archive.c
index 5ceec433fd..a081a6bf17 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -117,5 +117,5 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
- return write_archive(argc, argv, prefix, 1);
+ return write_archive(argc, argv, prefix, 1, 0);
}
diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c
index a9b02fa32f..47efadc465 100644
--- a/builtin-upload-archive.c
+++ b/builtin-upload-archive.c
@@ -64,7 +64,7 @@ static int run_upload_archive(int argc, const char **argv, const char *prefix)
sent_argv[sent_argc] = NULL;
/* parse all options sent by the client */
- return write_archive(sent_argc, sent_argv, prefix, 0);
+ return write_archive(sent_argc, sent_argv, prefix, 0, 1);
}
static void error_clnt(const char *fmt, ...)
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index c942c8be85..1a2ee105a4 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -213,4 +213,12 @@ 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_done