diff options
Diffstat (limited to 'commit.c')
| -rw-r--r-- | commit.c | 224 | 
1 files changed, 136 insertions, 88 deletions
| @@ -10,13 +10,13 @@  #include "mergesort.h"  #include "commit-slab.h"  #include "prio-queue.h" +#include "sha1-lookup.h"  static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);  int save_commit_buffer = 1;  const char *commit_type = "commit"; -static int commit_count;  static struct commit *check_commit(struct object *obj,  				   const unsigned char *sha1, @@ -63,7 +63,6 @@ struct commit *lookup_commit(const unsigned char *sha1)  	struct object *obj = lookup_object(sha1);  	if (!obj) {  		struct commit *c = alloc_commit_node(); -		c->index = commit_count++;  		return create_object(sha1, OBJ_COMMIT, c);  	}  	if (!obj->type) @@ -79,7 +78,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)  	if (get_sha1_committish(name, sha1))  		return NULL;  	commit = lookup_commit_reference(sha1); -	if (!commit || parse_commit(commit)) +	if (parse_commit(commit))  		return NULL;  	return commit;  } @@ -114,23 +113,16 @@ static unsigned long parse_commit_date(const char *buf, const char *tail)  static struct commit_graft **commit_graft;  static int commit_graft_alloc, commit_graft_nr; +static const unsigned char *commit_graft_sha1_access(size_t index, void *table) +{ +	struct commit_graft **commit_graft_table = table; +	return commit_graft_table[index]->sha1; +} +  static int commit_graft_pos(const unsigned char *sha1)  { -	int lo, hi; -	lo = 0; -	hi = commit_graft_nr; -	while (lo < hi) { -		int mi = (lo + hi) / 2; -		struct commit_graft *graft = commit_graft[mi]; -		int cmp = hashcmp(sha1, graft->sha1); -		if (!cmp) -			return mi; -		if (cmp < 0) -			hi = mi; -		else -			lo = mi + 1; -	} -	return -lo - 1; +	return sha1_pos(sha1, commit_graft, commit_graft_nr, +			commit_graft_sha1_access);  }  int register_commit_graft(struct commit_graft *graft, int ignore_dups) @@ -147,12 +139,8 @@ int register_commit_graft(struct commit_graft *graft, int ignore_dups)  		return 1;  	}  	pos = -pos - 1; -	if (commit_graft_alloc <= ++commit_graft_nr) { -		commit_graft_alloc = alloc_nr(commit_graft_alloc); -		commit_graft = xrealloc(commit_graft, -					sizeof(*commit_graft) * -					commit_graft_alloc); -	} +	ALLOC_GROW(commit_graft, commit_graft_nr + 1, commit_graft_alloc); +	commit_graft_nr++;  	if (pos < commit_graft_nr)  		memmove(commit_graft + pos + 1,  			commit_graft + pos, @@ -257,6 +245,76 @@ int unregister_shallow(const unsigned char *sha1)  	return 0;  } +struct commit_buffer { +	void *buffer; +	unsigned long size; +}; +define_commit_slab(buffer_slab, struct commit_buffer); +static struct buffer_slab buffer_slab = COMMIT_SLAB_INIT(1, buffer_slab); + +void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size) +{ +	struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); +	v->buffer = buffer; +	v->size = size; +} + +const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep) +{ +	struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); +	if (sizep) +		*sizep = v->size; +	return v->buffer; +} + +const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep) +{ +	const void *ret = get_cached_commit_buffer(commit, sizep); +	if (!ret) { +		enum object_type type; +		unsigned long size; +		ret = read_sha1_file(commit->object.sha1, &type, &size); +		if (!ret) +			die("cannot read commit object %s", +			    sha1_to_hex(commit->object.sha1)); +		if (type != OBJ_COMMIT) +			die("expected commit for %s, got %s", +			    sha1_to_hex(commit->object.sha1), typename(type)); +		if (sizep) +			*sizep = size; +	} +	return ret; +} + +void unuse_commit_buffer(const struct commit *commit, const void *buffer) +{ +	struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); +	if (v->buffer != buffer) +		free((void *)buffer); +} + +void free_commit_buffer(struct commit *commit) +{ +	struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); +	free(v->buffer); +	v->buffer = NULL; +	v->size = 0; +} + +const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep) +{ +	struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); +	void *ret; + +	ret = v->buffer; +	if (sizep) +		*sizep = v->size; + +	v->buffer = NULL; +	v->size = 0; +	return ret; +} +  int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size)  {  	const char *tail = buffer; @@ -334,13 +392,20 @@ int parse_commit(struct commit *item)  	}  	ret = parse_commit_buffer(item, buffer, size);  	if (save_commit_buffer && !ret) { -		item->buffer = buffer; +		set_commit_buffer(item, buffer, size);  		return 0;  	}  	free(buffer);  	return ret;  } +void parse_commit_or_die(struct commit *item) +{ +	if (parse_commit(item)) +		die("unable to parse commit %s", +		    item ? sha1_to_hex(item->object.sha1) : "(null)"); +} +  int find_commit_subject(const char *commit_buffer, const char **subject)  {  	const char *eol; @@ -541,32 +606,22 @@ define_commit_slab(author_date_slab, unsigned long);  static void record_author_date(struct author_date_slab *author_date,  			       struct commit *commit)  { -	const char *buf, *line_end; -	char *buffer = NULL; +	const char *buf, *line_end, *ident_line; +	const char *buffer = get_commit_buffer(commit, NULL);  	struct ident_split ident;  	char *date_end;  	unsigned long date; -	if (!commit->buffer) { -		unsigned long size; -		enum object_type type; -		buffer = read_sha1_file(commit->object.sha1, &type, &size); -		if (!buffer) -			return; -	} - -	for (buf = commit->buffer ? commit->buffer : buffer; -	     buf; -	     buf = line_end + 1) { +	for (buf = buffer; buf; buf = line_end + 1) {  		line_end = strchrnul(buf, '\n'); -		if (prefixcmp(buf, "author ")) { +		ident_line = skip_prefix(buf, "author "); +		if (!ident_line) {  			if (!line_end[0] || line_end[1] == '\n')  				return; /* end of header */  			continue;  		}  		if (split_ident_line(&ident, -				     buf + strlen("author "), -				     line_end - (buf + strlen("author "))) || +				     ident_line, line_end - ident_line) ||  		    !ident.date_begin || !ident.date_end)  			goto fail_exit; /* malformed "author" line */  		break; @@ -578,7 +633,7 @@ static void record_author_date(struct author_date_slab *author_date,  	*(author_date_slab_at(author_date, commit)) = date;  fail_exit: -	free(buffer); +	unuse_commit_buffer(commit, buffer);  }  static int compare_commits_by_author_date(const void *a_, const void *b_, @@ -724,7 +779,7 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so  /* merge-base stuff */ -/* bits #0..15 in revision.h */ +/* Remember to update object flag allocation in object.h */  #define PARENT1		(1u<<16)  #define PARENT2		(1u<<17)  #define STALE		(1u<<18) @@ -834,26 +889,26 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co  struct commit_list *get_octopus_merge_bases(struct commit_list *in)  {  	struct commit_list *i, *j, *k, *ret = NULL; -	struct commit_list **pptr = &ret; -	for (i = in; i; i = i->next) { -		if (!ret) -			pptr = &commit_list_insert(i->item, pptr)->next; -		else { -			struct commit_list *new = NULL, *end = NULL; - -			for (j = ret; j; j = j->next) { -				struct commit_list *bases; -				bases = get_merge_bases(i->item, j->item, 1); -				if (!new) -					new = bases; -				else -					end->next = bases; -				for (k = bases; k; k = k->next) -					end = k; -			} -			ret = new; +	if (!in) +		return ret; + +	commit_list_insert(in->item, &ret); + +	for (i = in->next; i; i = i->next) { +		struct commit_list *new = NULL, *end = NULL; + +		for (j = ret; j; j = j->next) { +			struct commit_list *bases; +			bases = get_merge_bases(i->item, j->item, 1); +			if (!new) +				new = bases; +			else +				end->next = bases; +			for (k = bases; k; k = k->next) +				end = k;  		} +		ret = new;  	}  	return ret;  } @@ -1083,17 +1138,14 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid)  	return 0;  } -int parse_signed_commit(const unsigned char *sha1, +int parse_signed_commit(const struct commit *commit,  			struct strbuf *payload, struct strbuf *signature)  { +  	unsigned long size; -	enum object_type type; -	char *buffer = read_sha1_file(sha1, &type, &size); +	const char *buffer = get_commit_buffer(commit, &size);  	int in_signature, saw_signature = -1; -	char *line, *tail; - -	if (!buffer || type != OBJ_COMMIT) -		goto cleanup; +	const char *line, *tail;  	line = buffer;  	tail = buffer + size; @@ -1101,12 +1153,12 @@ int parse_signed_commit(const unsigned char *sha1,  	saw_signature = 0;  	while (line < tail) {  		const char *sig = NULL; -		char *next = memchr(line, '\n', tail - line); +		const 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) && +		else if (starts_with(line, gpg_sig_header) &&  			 line[gpg_sig_header_len] == ' ')  			sig = line + gpg_sig_header_len + 1;  		if (sig) { @@ -1122,8 +1174,7 @@ int parse_signed_commit(const unsigned char *sha1,  		}  		line = next;  	} - cleanup: -	free(buffer); +	unuse_commit_buffer(commit, buffer);  	return saw_signature;  } @@ -1186,10 +1237,8 @@ static void parse_gpg_output(struct signature_check *sigc)  	for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {  		const char *found, *next; -		if (!prefixcmp(buf, sigcheck_gpg_status[i].check + 1)) { -			/* At the very beginning of the buffer */ -			found = buf + strlen(sigcheck_gpg_status[i].check + 1); -		} else { +		found = skip_prefix(buf, sigcheck_gpg_status[i].check + 1); +		if (!found) {  			found = strstr(buf, sigcheck_gpg_status[i].check);  			if (!found)  				continue; @@ -1216,8 +1265,7 @@ void check_commit_signature(const struct commit* commit, struct signature_check  	sigc->result = 'N'; -	if (parse_signed_commit(commit->object.sha1, -				&payload, &signature) <= 0) +	if (parse_signed_commit(commit, &payload, &signature) <= 0)  		goto out;  	status = verify_signed_buffer(payload.buf, payload.len,  				      signature.buf, signature.len, @@ -1262,11 +1310,9 @@ struct commit_extra_header *read_commit_extra_headers(struct commit *commit,  {  	struct commit_extra_header *extra = NULL;  	unsigned long size; -	enum object_type type; -	char *buffer = read_sha1_file(commit->object.sha1, &type, &size); -	if (buffer && type == OBJ_COMMIT) -		extra = read_commit_extra_header_lines(buffer, size, exclude); -	free(buffer); +	const char *buffer = get_commit_buffer(commit, &size); +	extra = read_commit_extra_header_lines(buffer, size, exclude); +	unuse_commit_buffer(commit, buffer);  	return extra;  } @@ -1349,7 +1395,8 @@ void free_commit_extra_headers(struct commit_extra_header *extra)  	}  } -int commit_tree(const struct strbuf *msg, unsigned char *tree, +int commit_tree(const char *msg, size_t msg_len, +		const unsigned char *tree,  		struct commit_list *parents, unsigned char *ret,  		const char *author, const char *sign_commit)  { @@ -1357,7 +1404,7 @@ int commit_tree(const struct strbuf *msg, unsigned char *tree,  	int result;  	append_merge_tag_headers(parents, &tail); -	result = commit_tree_extended(msg, tree, parents, ret, +	result = commit_tree_extended(msg, msg_len, tree, parents, ret,  				      author, sign_commit, extra);  	free_commit_extra_headers(extra);  	return result; @@ -1478,7 +1525,8 @@ static const char commit_utf8_warn[] =  "You may want to amend it after fixing the message, or set the config\n"  "variable i18n.commitencoding to the encoding your project uses.\n"; -int commit_tree_extended(const struct strbuf *msg, unsigned char *tree, +int commit_tree_extended(const char *msg, size_t msg_len, +			 const unsigned char *tree,  			 struct commit_list *parents, unsigned char *ret,  			 const char *author, const char *sign_commit,  			 struct commit_extra_header *extra) @@ -1489,7 +1537,7 @@ int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,  	assert_sha1_type(tree, OBJ_TREE); -	if (memchr(msg->buf, '\0', msg->len)) +	if (memchr(msg, '\0', msg_len))  		return error("a NUL byte in commit log message not allowed.");  	/* Not having i18n.commitencoding is the same as having utf-8 */ @@ -1528,7 +1576,7 @@ int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,  	strbuf_addch(&buffer, '\n');  	/* And add the comment */ -	strbuf_addbuf(&buffer, msg); +	strbuf_add(&buffer, msg, msg_len);  	/* And check the encoding */  	if (encoding_is_utf8 && !verify_utf8(&buffer)) | 
