diff options
Diffstat (limited to 'commit.c')
| -rw-r--r-- | commit.c | 92 | 
1 files changed, 89 insertions, 3 deletions
| @@ -6,6 +6,7 @@  #include "diff.h"  #include "revision.h"  #include "notes.h" +#include "gpg-interface.h"  int save_commit_buffer = 1; @@ -840,6 +841,86 @@ struct commit_list *reduce_heads(struct commit_list *heads)  	return result;  } +static const char gpg_sig_header[] = "gpgsig"; +static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1; + +static int do_sign_commit(struct strbuf *buf, const char *keyid) +{ +	struct strbuf sig = STRBUF_INIT; +	int inspos, copypos; + +	/* find the end of the header */ +	inspos = strstr(buf->buf, "\n\n") - buf->buf + 1; + +	if (!keyid || !*keyid) +		keyid = get_signing_key(); +	if (sign_buffer(buf, &sig, keyid)) { +		strbuf_release(&sig); +		return -1; +	} + +	for (copypos = 0; sig.buf[copypos]; ) { +		const char *bol = sig.buf + copypos; +		const char *eol = strchrnul(bol, '\n'); +		int len = (eol - bol) + !!*eol; + +		if (!copypos) { +			strbuf_insert(buf, inspos, gpg_sig_header, gpg_sig_header_len); +			inspos += gpg_sig_header_len; +		} +		strbuf_insert(buf, inspos++, " ", 1); +		strbuf_insert(buf, inspos, bol, len); +		inspos += len; +		copypos += len; +	} +	strbuf_release(&sig); +	return 0; +} + +int parse_signed_commit(const unsigned char *sha1, +			struct strbuf *payload, struct strbuf *signature) +{ +	unsigned long size; +	enum object_type type; +	char *buffer = read_sha1_file(sha1, &type, &size); +	int in_signature, saw_signature = -1; +	char *line, *tail; + +	if (!buffer || type != OBJ_COMMIT) +		goto cleanup; + +	line = buffer; +	tail = buffer + size; +	in_signature = 0; +	saw_signature = 0; +	while (line < tail) { +		const char *sig = NULL; +		char *next = memchr(line, '\n', tail - line); + +		next = next ? next + 1 : tail; +		if (in_signature && line[0] == ' ') +			sig = line + 1; +		else if (!prefixcmp(line, gpg_sig_header) && +			 line[gpg_sig_header_len] == ' ') +			sig = line + gpg_sig_header_len + 1; +		if (sig) { +			strbuf_add(signature, sig, next - sig); +			saw_signature = 1; +			in_signature = 1; +		} else { +			if (*line == '\n') +				/* dump the whole remainder of the buffer */ +				next = tail; +			strbuf_add(payload, line, next - line); +			in_signature = 0; +		} +		line = next; +	} + cleanup: +	free(buffer); +	return saw_signature; +} +  static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail)  {  	struct merge_remote_desc *desc; @@ -975,13 +1056,14 @@ void free_commit_extra_headers(struct commit_extra_header *extra)  int commit_tree(const char *msg, unsigned char *tree,  		struct commit_list *parents, unsigned char *ret, -		const char *author) +		const char *author, const char *sign_commit)  {  	struct commit_extra_header *extra = NULL, **tail = &extra;  	int result;  	append_merge_tag_headers(parents, &tail); -	result = commit_tree_extended(msg, tree, parents, ret, author, extra); +	result = commit_tree_extended(msg, tree, parents, ret, +				      author, sign_commit, extra);  	free_commit_extra_headers(extra);  	return result;  } @@ -993,7 +1075,8 @@ static const char commit_utf8_warn[] =  int commit_tree_extended(const char *msg, unsigned char *tree,  			 struct commit_list *parents, unsigned char *ret, -			 const char *author, struct commit_extra_header *extra) +			 const char *author, const char *sign_commit, +			 struct commit_extra_header *extra)  {  	int result;  	int encoding_is_utf8; @@ -1043,6 +1126,9 @@ int commit_tree_extended(const char *msg, unsigned char *tree,  	if (encoding_is_utf8 && !is_utf8(buffer.buf))  		fprintf(stderr, commit_utf8_warn); +	if (sign_commit && do_sign_commit(&buffer, sign_commit)) +		return -1; +  	result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);  	strbuf_release(&buffer);  	return result; | 
