diff options
Diffstat (limited to 'builtin/receive-pack.c')
-rw-r--r-- | builtin/receive-pack.c | 113 |
1 files changed, 79 insertions, 34 deletions
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 3f05d971ec..e3eb5fc058 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -12,6 +12,7 @@ #include "string-list.h" #include "sha1-array.h" #include "connected.h" +#include "version.h" static const char receive_pack_usage[] = "git receive-pack <git-dir>"; @@ -58,6 +59,11 @@ static enum deny_action parse_deny_action(const char *var, const char *value) static int receive_pack_config(const char *var, const char *value, void *cb) { + int status = parse_hide_refs_config(var, value, "receive"); + + if (status) + return status; + if (strcmp(var, "receive.denydeletes") == 0) { deny_deletes = git_config_bool(var, value); return 0; @@ -118,13 +124,17 @@ static int receive_pack_config(const char *var, const char *value, void *cb) static void show_ref(const char *path, const unsigned char *sha1) { + if (ref_is_hidden(path)) + return; + if (sent_capabilities) packet_write(1, "%s %s\n", sha1_to_hex(sha1), path); else - packet_write(1, "%s %s%c%s%s\n", + packet_write(1, "%s %s%c%s%s agent=%s\n", sha1_to_hex(sha1), path, 0, " report-status delete-refs side-band-64k quiet", - prefer_ofs_delta ? " ofs-delta" : ""); + prefer_ofs_delta ? " ofs-delta" : "", + git_user_agent_sanitized()); sent_capabilities = 1; } @@ -180,9 +190,6 @@ struct command { char ref_name[FLEX_ARRAY]; /* more */ }; -static const char pre_receive_hook[] = "hooks/pre-receive"; -static const char post_receive_hook[] = "hooks/post-receive"; - static void rp_error(const char *err, ...) __attribute__((format (printf, 1, 2))); static void rp_warning(const char *err, ...) __attribute__((format (printf, 1, 2))); @@ -240,10 +247,10 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta const char *argv[2]; int code; - if (access(hook_name, X_OK) < 0) + argv[0] = find_hook(hook_name); + if (!argv[0]) return 0; - argv[0] = hook_name; argv[1] = NULL; memset(&proc, 0, sizeof(proc)); @@ -329,15 +336,14 @@ static int run_receive_hook(struct command *commands, const char *hook_name, static int run_update_hook(struct command *cmd) { - static const char update_hook[] = "hooks/update"; const char *argv[5]; struct child_process proc; int code; - if (access(update_hook, X_OK) < 0) + argv[0] = find_hook("update"); + if (!argv[0]) return 0; - argv[0] = update_hook; argv[1] = cmd->ref_name; argv[2] = sha1_to_hex(cmd->old_sha1); argv[3] = sha1_to_hex(cmd->new_sha1); @@ -478,7 +484,6 @@ static const char *update(struct command *cmd) !prefixcmp(name, "refs/heads/")) { struct object *old_object, *new_object; struct commit *old_commit, *new_commit; - struct commit_list *bases, *ent; old_object = parse_object(old_sha1); new_object = parse_object(new_sha1); @@ -491,12 +496,7 @@ static const char *update(struct command *cmd) } old_commit = (struct commit *)old_object; new_commit = (struct commit *)new_object; - bases = get_merge_bases(old_commit, new_commit, 1); - for (ent = bases; ent; ent = ent->next) - if (!hashcmp(old_sha1, ent->item->object.sha1)) - break; - free_commit_list(bases); - if (!ent) { + if (!in_merge_bases(old_commit, new_commit)) { rp_error("denying non-fast-forward %s" " (you should pull first)", name); return "non-fast-forward"; @@ -536,24 +536,25 @@ static const char *update(struct command *cmd) } } -static char update_post_hook[] = "hooks/post-update"; - static void run_update_post_hook(struct command *commands) { struct command *cmd; int argc; const char **argv; struct child_process proc; + char *hook; + hook = find_hook("post-update"); for (argc = 0, cmd = commands; cmd; cmd = cmd->next) { if (cmd->error_string || cmd->did_not_exist) continue; argc++; } - if (!argc || access(update_post_hook, X_OK) < 0) + if (!argc || !hook) return; + argv = xmalloc(sizeof(*argv) * (2 + argc)); - argv[0] = update_post_hook; + argv[0] = hook; for (argc = 1, cmd = commands; cmd; cmd = cmd->next) { char *p; @@ -692,6 +693,20 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20]) return -1; /* end of list */ } +static void reject_updates_to_hidden(struct command *commands) +{ + struct command *cmd; + + for (cmd = commands; cmd; cmd = cmd->next) { + if (cmd->error_string || !ref_is_hidden(cmd->ref_name)) + continue; + if (is_null_sha1(cmd->new_sha1)) + cmd->error_string = "deny deleting a hidden ref"; + else + cmd->error_string = "deny updating a hidden ref"; + } +} + static void execute_commands(struct command *commands, const char *unpacker_error) { struct command *cmd; @@ -699,7 +714,7 @@ static void execute_commands(struct command *commands, const char *unpacker_erro if (unpacker_error) { for (cmd = commands; cmd; cmd = cmd->next) - cmd->error_string = "n/a (unpacker error)"; + cmd->error_string = "unpacker error"; return; } @@ -708,7 +723,9 @@ static void execute_commands(struct command *commands, const char *unpacker_erro 0, &cmd)) set_connectivity_errors(commands); - if (run_receive_hook(commands, pre_receive_hook, 0)) { + reject_updates_to_hidden(commands); + + if (run_receive_hook(commands, "pre-receive", 0)) { for (cmd = commands; cmd; cmd = cmd->next) { if (!cmd->error_string) cmd->error_string = "pre-receive hook declined"; @@ -737,17 +754,15 @@ static struct command *read_head_info(void) struct command *commands = NULL; struct command **p = &commands; for (;;) { - static char line[1000]; + char *line; unsigned char old_sha1[20], new_sha1[20]; struct command *cmd; char *refname; int len, reflen; - len = packet_read_line(0, line, sizeof(line)); - if (!len) + line = packet_read_line(0, &len); + if (!line) break; - if (line[len-1] == '\n') - line[--len] = 0; if (len < 83 || line[40] != ' ' || line[81] != ' ' || @@ -799,7 +814,7 @@ static const char *parse_pack_header(struct pack_header *hdr) static const char *pack_lockfile; -static const char *unpack(void) +static const char *unpack(int err_fd) { struct pack_header hdr; const char *hdr_err; @@ -811,14 +826,18 @@ static const char *unpack(void) : 0); hdr_err = parse_pack_header(&hdr); - if (hdr_err) + if (hdr_err) { + if (err_fd > 0) + close(err_fd); return hdr_err; + } snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%"PRIu32",%"PRIu32, ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (ntohl(hdr.hdr_entries) < unpack_limit) { int code, i = 0; + struct child_process child; const char *unpacker[5]; unpacker[i++] = "unpack-objects"; if (quiet) @@ -827,7 +846,12 @@ static const char *unpack(void) unpacker[i++] = "--strict"; unpacker[i++] = hdr_arg; unpacker[i++] = NULL; - code = run_command_v_opt(unpacker, RUN_GIT_CMD); + memset(&child, 0, sizeof(child)); + child.argv = unpacker; + child.no_stdout = 1; + child.err = err_fd; + child.git_cmd = 1; + code = run_command(&child); if (!code) return NULL; return "unpack-objects abnormal exit"; @@ -852,6 +876,7 @@ static const char *unpack(void) memset(&ip, 0, sizeof(ip)); ip.argv = keeper; ip.out = -1; + ip.err = err_fd; ip.git_cmd = 1; status = start_command(&ip); if (status) { @@ -868,6 +893,26 @@ static const char *unpack(void) } } +static const char *unpack_with_sideband(void) +{ + struct async muxer; + const char *ret; + + if (!use_sideband) + return unpack(0); + + memset(&muxer, 0, sizeof(muxer)); + muxer.proc = copy_to_sideband; + muxer.in = -1; + if (start_async(&muxer)) + return NULL; + + ret = unpack(muxer.in); + + finish_async(&muxer); + return ret; +} + static void report(struct command *commands, const char *unpack_status) { struct command *cmd; @@ -888,7 +933,7 @@ static void report(struct command *commands, const char *unpack_status) if (use_sideband) send_sideband(1, 1, buf.buf, buf.len, use_sideband); else - safe_write(1, buf.buf, buf.len); + write_or_die(1, buf.buf, buf.len); strbuf_release(&buf); } @@ -965,13 +1010,13 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) const char *unpack_status = NULL; if (!delete_only(commands)) - unpack_status = unpack(); + unpack_status = unpack_with_sideband(); execute_commands(commands, unpack_status); if (pack_lockfile) unlink_or_warn(pack_lockfile); if (report_status) report(commands, unpack_status); - run_receive_hook(commands, post_receive_hook, 1); + run_receive_hook(commands, "post-receive", 1); run_update_post_hook(commands); if (auto_gc) { const char *argv_gc_auto[] = { |