Merge branch 'jk/commit-buffer-length'

Move "commit->buffer" out of the in-core commit object and keep
track of their lengths.  Use this to optimize the code paths to
validate GPG signatures in commit objects.

* jk/commit-buffer-length:
  reuse cached commit buffer when parsing signatures
  commit: record buffer length in cache
  commit: convert commit->buffer to a slab
  commit-slab: provide a static initializer
  use get_commit_buffer everywhere
  convert logmsg_reencode to get_commit_buffer
  use get_commit_buffer to avoid duplicate code
  use get_cached_commit_buffer where appropriate
  provide helpers to access the commit buffer
  provide a helper to set the commit buffer
  provide a helper to free commit buffer
  sequencer: use logmsg_reencode in get_message
  logmsg_reencode: return const buffer
  do not create "struct commit" with xcalloc
  commit: push commit_index update into alloc_commit_node
  alloc: include any-object allocations in alloc_report
  replace dangerous uses of strbuf_attach
  commit_tree: take a pointer/len pair rather than a const strbuf
This commit is contained in:
Junio C Hamano 2014-07-02 12:53:02 -07:00
Родитель 95acfc2479 218aa3a616
Коммит 8061ae8b46
27 изменённых файлов: 285 добавлений и 198 удалений

23
alloc.c
Просмотреть файл

@ -47,23 +47,32 @@ union any_object {
DEFINE_ALLOCATOR(blob, struct blob)
DEFINE_ALLOCATOR(tree, struct tree)
DEFINE_ALLOCATOR(commit, struct commit)
DEFINE_ALLOCATOR(raw_commit, struct commit)
DEFINE_ALLOCATOR(tag, struct tag)
DEFINE_ALLOCATOR(object, union any_object)
void *alloc_commit_node(void)
{
static int commit_count;
struct commit *c = alloc_raw_commit_node();
c->index = commit_count++;
return c;
}
static void report(const char *name, unsigned int count, size_t size)
{
fprintf(stderr, "%10s: %8u (%"PRIuMAX" kB)\n",
name, count, (uintmax_t) size);
}
#define REPORT(name) \
report(#name, name##_allocs, name##_allocs * sizeof(struct name) >> 10)
#define REPORT(name, type) \
report(#name, name##_allocs, name##_allocs * sizeof(type) >> 10)
void alloc_report(void)
{
REPORT(blob);
REPORT(tree);
REPORT(commit);
REPORT(tag);
REPORT(blob, struct blob);
REPORT(tree, struct tree);
REPORT(raw_commit, struct commit);
REPORT(tag, struct tag);
REPORT(object, union any_object);
}

Просмотреть файл

@ -1655,7 +1655,7 @@ static void get_commit_info(struct commit *commit,
{
int len;
const char *subject, *encoding;
char *message;
const char *message;
commit_info_init(ret);
@ -1666,7 +1666,7 @@ static void get_commit_info(struct commit *commit,
&ret->author_time, &ret->author_tz);
if (!detailed) {
logmsg_free(message, commit);
unuse_commit_buffer(commit, message);
return;
}
@ -1680,7 +1680,7 @@ static void get_commit_info(struct commit *commit,
else
strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1));
logmsg_free(message, commit);
unuse_commit_buffer(commit, message);
}
/*
@ -2251,6 +2251,18 @@ static void append_merge_parents(struct commit_list **tail)
strbuf_release(&line);
}
/*
* This isn't as simple as passing sb->buf and sb->len, because we
* want to transfer ownership of the buffer to the commit (so we
* must use detach).
*/
static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb)
{
size_t len;
void *buf = strbuf_detach(sb, &len);
set_commit_buffer(c, buf, len);
}
/*
* Prepare a dummy commit that represents the work tree (or staged) item.
* Note that annotating work tree item never works in the reverse.
@ -2272,7 +2284,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
struct strbuf msg = STRBUF_INIT;
time(&now);
commit = xcalloc(1, sizeof(*commit));
commit = alloc_commit_node();
commit->object.parsed = 1;
commit->date = now;
commit->object.type = OBJ_COMMIT;
@ -2299,7 +2311,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
ident, ident, path,
(!contents_from ? path :
(!strcmp(contents_from, "-") ? "standard input" : contents_from)));
commit->buffer = strbuf_detach(&msg, NULL);
set_commit_buffer_from_strbuf(commit, &msg);
if (!contents_from || strcmp("-", contents_from)) {
struct stat st;

Просмотреть файл

@ -123,8 +123,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
die_errno("git commit-tree: failed to read");
}
if (commit_tree(&buffer, tree_sha1, parents, commit_sha1,
NULL, sign_commit)) {
if (commit_tree(buffer.buf, buffer.len, tree_sha1, parents,
commit_sha1, NULL, sign_commit)) {
strbuf_release(&buffer);
return 1;
}

Просмотреть файл

@ -1745,8 +1745,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
append_merge_tag_headers(parents, &tail);
}
if (commit_tree_extended(&sb, active_cache_tree->sha1, parents, sha1,
author_ident.buf, sign_commit, extra)) {
if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->sha1,
parents, sha1, author_ident.buf, sign_commit, extra)) {
rollback_index_files();
die(_("failed to write commit object"));
}

Просмотреть файл

@ -282,6 +282,7 @@ static const char *find_encoding(const char *begin, const char *end)
static void handle_commit(struct commit *commit, struct rev_info *rev)
{
int saved_output_format = rev->diffopt.output_format;
const char *commit_buffer;
const char *author, *author_end, *committer, *committer_end;
const char *encoding, *message;
char *reencoded = NULL;
@ -291,7 +292,8 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
parse_commit_or_die(commit);
author = strstr(commit->buffer, "\nauthor ");
commit_buffer = get_commit_buffer(commit, NULL);
author = strstr(commit_buffer, "\nauthor ");
if (!author)
die ("Could not find author in commit %s",
sha1_to_hex(commit->object.sha1));
@ -338,6 +340,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
? strlen(message) : 0),
reencoded ? reencoded : message ? message : "");
free(reencoded);
unuse_commit_buffer(commit, commit_buffer);
for (i = 0, p = commit->parents; p; p = p->next) {
int mark = get_object_mark(&p->item->object);

Просмотреть файл

@ -230,12 +230,14 @@ static void add_branch_desc(struct strbuf *out, const char *name)
static void record_person(int which, struct string_list *people,
struct commit *commit)
{
const char *buffer;
char *name_buf, *name, *name_end;
struct string_list_item *elem;
const char *field;
field = (which == 'a') ? "\nauthor " : "\ncommitter ";
name = strstr(commit->buffer, field);
buffer = get_commit_buffer(commit, NULL);
name = strstr(buffer, field);
if (!name)
return;
name += strlen(field);
@ -247,6 +249,7 @@ static void record_person(int which, struct string_list *people,
if (name_end < name)
return;
name_buf = xmemdupz(name, name_end - name + 1);
unuse_commit_buffer(commit, buffer);
elem = string_list_lookup(people, name_buf);
if (!elem) {

Просмотреть файл

@ -310,8 +310,7 @@ static int fsck_obj(struct object *obj)
if (obj->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *) obj;
free(commit->buffer);
commit->buffer = NULL;
free_commit_buffer(commit);
if (!commit->parents && show_root)
printf("root %s\n", sha1_to_hex(commit->object.sha1));

Просмотреть файл

@ -786,7 +786,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
}
if (obj->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *) obj;
commit->buffer = NULL;
if (detach_commit_buffer(commit, NULL) != data)
die("BUG: parse_object_buffer transmogrified our buffer");
}
obj->flags |= FLAG_CHECKED;
}

Просмотреть файл

@ -347,8 +347,7 @@ static int cmd_log_walk(struct rev_info *rev)
rev->max_count++;
if (!rev->reflog_info) {
/* we allow cycles in reflog ancestry */
free(commit->buffer);
commit->buffer = NULL;
free_commit_buffer(commit);
}
free_commit_list(commit->parents);
commit->parents = NULL;
@ -925,9 +924,12 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
log_write_email_headers(rev, head, &pp.subject, &pp.after_subject,
&need_8bit_cte);
for (i = 0; !need_8bit_cte && i < nr; i++)
if (has_non_ascii(list[i]->buffer))
for (i = 0; !need_8bit_cte && i < nr; i++) {
const char *buf = get_commit_buffer(list[i], NULL);
if (has_non_ascii(buf))
need_8bit_cte = 1;
unuse_commit_buffer(list[i], buf);
}
if (!branch_name)
branch_name = find_branch_name(rev);
@ -1528,8 +1530,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
reopen_stdout(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
die(_("Failed to create output files"));
shown = log_tree_commit(&rev, commit);
free(commit->buffer);
commit->buffer = NULL;
free_commit_buffer(commit);
/* We put one extra blank line between formatted
* patches and this flag is used by log-tree code

Просмотреть файл

@ -852,8 +852,8 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
parent->next->item = remoteheads->item;
parent->next->next = NULL;
prepare_to_commit(remoteheads);
if (commit_tree(&merge_msg, result_tree, parent, result_commit, NULL,
sign_commit))
if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parent,
result_commit, NULL, sign_commit))
die(_("failed to write commit object"));
finish(head, remoteheads, result_commit, "In-index merge");
drop_save();
@ -877,8 +877,8 @@ static int finish_automerge(struct commit *head,
commit_list_insert(head, &parents);
strbuf_addch(&merge_msg, '\n');
prepare_to_commit(remoteheads);
if (commit_tree(&merge_msg, result_tree, parents, result_commit,
NULL, sign_commit))
if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
result_commit, NULL, sign_commit))
die(_("failed to write commit object"));
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
finish(head, remoteheads, result_commit, buf.buf);

Просмотреть файл

@ -93,7 +93,7 @@ static int reset_index(const unsigned char *sha1, int reset_type, int quiet)
static void print_new_head_line(struct commit *commit)
{
const char *hex, *body;
char *msg;
const char *msg;
hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
printf(_("HEAD is now at %s"), hex);
@ -109,7 +109,7 @@ static void print_new_head_line(struct commit *commit)
}
else
printf("\n");
logmsg_free(msg, commit);
unuse_commit_buffer(commit, msg);
}
static void update_index_from_diff(struct diff_queue_struct *q,

Просмотреть файл

@ -106,7 +106,7 @@ static void show_commit(struct commit *commit, void *data)
else
putchar('\n');
if (revs->verbose_header && commit->buffer) {
if (revs->verbose_header && get_cached_commit_buffer(commit, NULL)) {
struct strbuf buf = STRBUF_INIT;
struct pretty_print_context ctx = {0};
ctx.abbrev = revs->abbrev;
@ -173,8 +173,7 @@ static void finish_commit(struct commit *commit, void *data)
free_commit_list(commit->parents);
commit->parents = NULL;
}
free(commit->buffer);
commit->buffer = NULL;
free_commit_buffer(commit);
}
static void finish_object(struct object *obj,

Просмотреть файл

@ -117,4 +117,16 @@ static int stat_ ##slabname## realloc
* catch because GCC silently parses it by default.
*/
/*
* Statically initialize a commit slab named "var". Note that this
* evaluates "stride" multiple times! Example:
*
* struct indegree indegrees = COMMIT_SLAB_INIT(1, indegrees);
*
*/
#define COMMIT_SLAB_INIT(stride, var) { \
COMMIT_SLAB_SIZE / sizeof(**((var).slab)) / (stride), \
(stride), 0, NULL \
}
#endif /* COMMIT_SLAB_H */

131
commit.c
Просмотреть файл

@ -17,7 +17,6 @@ static struct commit_extra_header *read_commit_extra_header_lines(const char *bu
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,
@ -64,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)
@ -247,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;
@ -324,7 +392,7 @@ 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);
@ -539,22 +607,12 @@ static void record_author_date(struct author_date_slab *author_date,
struct commit *commit)
{
const char *buf, *line_end, *ident_line;
char *buffer = NULL;
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');
ident_line = skip_prefix(buf, "author ");
if (!ident_line) {
@ -575,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_,
@ -1080,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);
int in_signature, saw_signature = -1;
char *line, *tail;
if (!buffer || type != OBJ_COMMIT)
goto cleanup;
unsigned long size;
const char *buffer = get_commit_buffer(commit, &size);
int in_signature, saw_signature = -1;
const char *line, *tail;
line = buffer;
tail = buffer + size;
@ -1098,7 +1153,7 @@ 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] == ' ')
@ -1119,8 +1174,7 @@ int parse_signed_commit(const unsigned char *sha1,
}
line = next;
}
cleanup:
free(buffer);
unuse_commit_buffer(commit, buffer);
return saw_signature;
}
@ -1211,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,
@ -1257,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;
}
@ -1344,7 +1395,8 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
}
}
int commit_tree(const struct strbuf *msg, const 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)
{
@ -1352,7 +1404,7 @@ int commit_tree(const struct strbuf *msg, const 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;
@ -1473,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, const 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)
@ -1484,7 +1537,7 @@ int commit_tree_extended(const struct strbuf *msg, const 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 */
@ -1523,7 +1576,7 @@ int commit_tree_extended(const struct strbuf *msg, const 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))

Просмотреть файл

@ -20,7 +20,6 @@ struct commit {
unsigned long date;
struct commit_list *parents;
struct tree *tree;
char *buffer;
};
extern int save_commit_buffer;
@ -51,6 +50,44 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
int parse_commit(struct commit *item);
void parse_commit_or_die(struct commit *item);
/*
* Associate an object buffer with the commit. The ownership of the
* memory is handed over to the commit, and must be free()-able.
*/
void set_commit_buffer(struct commit *, void *buffer, unsigned long size);
/*
* Get any cached object buffer associated with the commit. Returns NULL
* if none. The resulting memory should not be freed.
*/
const void *get_cached_commit_buffer(const struct commit *, unsigned long *size);
/*
* Get the commit's object contents, either from cache or by reading the object
* from disk. The resulting memory should not be modified, and must be given
* to unuse_commit_buffer when the caller is done.
*/
const void *get_commit_buffer(const struct commit *, unsigned long *size);
/*
* Tell the commit subsytem that we are done with a particular commit buffer.
* The commit and buffer should be the input and return value, respectively,
* from an earlier call to get_commit_buffer. The buffer may or may not be
* freed by this call; callers should not access the memory afterwards.
*/
void unuse_commit_buffer(const struct commit *, const void *buffer);
/*
* Free any cached object buffer associated with the commit.
*/
void free_commit_buffer(struct commit *);
/*
* Disassociate any cached object buffer from the commit, but do not free it.
* The buffer (or NULL, if none) is returned.
*/
const void *detach_commit_buffer(struct commit *, unsigned long *sizep);
/* Find beginning and length of commit subject. */
int find_commit_subject(const char *commit_buffer, const char **subject);
@ -115,10 +152,9 @@ struct userformat_want {
extern int has_non_ascii(const char *text);
struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
extern char *logmsg_reencode(const struct commit *commit,
char **commit_encoding,
const char *output_encoding);
extern void logmsg_free(char *msg, const struct commit *commit);
extern const char *logmsg_reencode(const struct commit *commit,
char **commit_encoding,
const char *output_encoding);
extern void get_commit_format(const char *arg, struct rev_info *);
extern const char *format_subject(struct strbuf *sb, const char *msg,
const char *line_separator);
@ -261,11 +297,13 @@ struct commit_extra_header {
extern void append_merge_tag_headers(struct commit_list *parents,
struct commit_extra_header ***tail);
extern int commit_tree(const struct strbuf *msg, const unsigned char *tree,
extern 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);
extern int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
extern 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 *);
@ -287,7 +325,7 @@ struct merge_remote_desc {
*/
struct commit *get_merge_parent(const char *name);
extern int parse_signed_commit(const unsigned char *sha1,
extern int parse_signed_commit(const struct commit *commit,
struct strbuf *message, struct strbuf *signature);
extern void print_commit_list(struct commit_list *list,
const char *format_cur,

13
fsck.c
Просмотреть файл

@ -276,9 +276,10 @@ static int fsck_ident(const char **ident, struct object *obj, fsck_error error_f
return 0;
}
static int fsck_commit(struct commit *commit, fsck_error error_func)
static int fsck_commit_buffer(struct commit *commit, const char *buffer,
fsck_error error_func)
{
const char *buffer = commit->buffer, *tmp;
const char *tmp;
unsigned char tree_sha1[20], sha1[20];
struct commit_graft *graft;
int parents = 0;
@ -336,6 +337,14 @@ static int fsck_commit(struct commit *commit, fsck_error error_func)
return 0;
}
static int fsck_commit(struct commit *commit, fsck_error error_func)
{
const char *buffer = get_commit_buffer(commit, NULL);
int ret = fsck_commit_buffer(commit, buffer, error_func);
unuse_commit_buffer(commit, buffer);
return ret;
}
static int fsck_tag(struct tag *tag, fsck_error error_func)
{
struct object *tagged = tag->tagged;

Просмотреть файл

@ -376,7 +376,7 @@ static void show_signature(struct rev_info *opt, struct commit *commit)
struct strbuf gpg_output = STRBUF_INIT;
int status;
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,
@ -588,7 +588,7 @@ void show_log(struct rev_info *opt)
show_mergetag(opt, commit);
}
if (!commit->buffer)
if (!get_cached_commit_buffer(commit, NULL))
return;
if (opt->show_notes) {

Просмотреть файл

@ -40,7 +40,7 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two,
static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
{
struct commit *commit = xcalloc(1, sizeof(struct commit));
struct commit *commit = alloc_commit_node();
struct merge_remote_desc *desc = xmalloc(sizeof(*desc));
desc->name = comment;
@ -190,9 +190,11 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
printf(_("(bad commit)\n"));
else {
const char *title;
int len = find_commit_subject(commit->buffer, &title);
const char *msg = get_commit_buffer(commit, NULL);
int len = find_commit_subject(msg, &title);
if (len)
printf("%.*s\n", len, title);
unuse_commit_buffer(commit, msg);
}
}
}

Просмотреть файл

@ -48,7 +48,6 @@ int notes_cache_write(struct notes_cache *c)
{
unsigned char tree_sha1[20];
unsigned char commit_sha1[20];
struct strbuf msg = STRBUF_INIT;
if (!c || !c->tree.initialized || !c->tree.ref || !*c->tree.ref)
return -1;
@ -57,9 +56,8 @@ int notes_cache_write(struct notes_cache *c)
if (write_notes_tree(&c->tree, tree_sha1))
return -1;
strbuf_attach(&msg, c->validity,
strlen(c->validity), strlen(c->validity) + 1);
if (commit_tree(&msg, tree_sha1, NULL, commit_sha1, NULL, NULL) < 0)
if (commit_tree(c->validity, strlen(c->validity), tree_sha1, NULL,
commit_sha1, NULL, NULL) < 0)
return -1;
if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL,
0, UPDATE_REFS_QUIET_ON_ERR) < 0)

Просмотреть файл

@ -644,7 +644,8 @@ int notes_merge(struct notes_merge_options *o,
struct commit_list *parents = NULL;
commit_list_insert(remote, &parents); /* LIFO order */
commit_list_insert(local, &parents);
create_notes_commit(local_tree, parents, &o->commit_msg,
create_notes_commit(local_tree, parents,
o->commit_msg.buf, o->commit_msg.len,
result_sha1);
}
@ -671,8 +672,8 @@ int notes_merge_commit(struct notes_merge_options *o,
DIR *dir;
struct dirent *e;
struct strbuf path = STRBUF_INIT;
char *msg = strstr(partial_commit->buffer, "\n\n");
struct strbuf sb_msg = STRBUF_INIT;
const char *buffer = get_commit_buffer(partial_commit, NULL);
const char *msg = strstr(buffer, "\n\n");
int baselen;
strbuf_addstr(&path, git_path(NOTES_MERGE_WORKTREE));
@ -719,9 +720,9 @@ int notes_merge_commit(struct notes_merge_options *o,
strbuf_setlen(&path, baselen);
}
strbuf_attach(&sb_msg, msg, strlen(msg), strlen(msg) + 1);
create_notes_commit(partial_tree, partial_commit->parents, &sb_msg,
result_sha1);
create_notes_commit(partial_tree, partial_commit->parents,
msg, strlen(msg), result_sha1);
unuse_commit_buffer(partial_commit, buffer);
if (o->verbosity >= 4)
printf("Finalized notes merge commit: %s\n",
sha1_to_hex(result_sha1));

Просмотреть файл

@ -4,7 +4,8 @@
#include "notes-utils.h"
void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
const struct strbuf *msg, unsigned char *result_sha1)
const char *msg, size_t msg_len,
unsigned char *result_sha1)
{
unsigned char tree_sha1[20];
@ -25,7 +26,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
/* else: t->ref points to nothing, assume root/orphan commit */
}
if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL))
if (commit_tree(msg, msg_len, tree_sha1, parents, result_sha1, NULL, NULL))
die("Failed to commit notes tree to database");
}
@ -46,7 +47,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
if (buf.buf[buf.len - 1] != '\n')
strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */
create_notes_commit(t, NULL, &buf, commit_sha1);
create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1);
strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
update_ref(buf.buf, t->ref, commit_sha1, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);

Просмотреть файл

@ -15,7 +15,7 @@
* The resulting commit SHA1 is stored in result_sha1.
*/
void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
const struct strbuf *msg, unsigned char *result_sha1);
const char *msg, size_t msg_len, unsigned char *result_sha1);
void commit_notes(struct notes_tree *t, const char *msg);

Просмотреть файл

@ -197,8 +197,8 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t
if (commit) {
if (parse_commit_buffer(commit, buffer, size))
return NULL;
if (!commit->buffer) {
commit->buffer = buffer;
if (!get_cached_commit_buffer(commit, NULL)) {
set_commit_buffer(commit, buffer, size);
*eaten_p = 1;
}
obj = &commit->object;

Просмотреть файл

@ -606,29 +606,16 @@ static char *replace_encoding_header(char *buf, const char *encoding)
return strbuf_detach(&tmp, NULL);
}
char *logmsg_reencode(const struct commit *commit,
char **commit_encoding,
const char *output_encoding)
const char *logmsg_reencode(const struct commit *commit,
char **commit_encoding,
const char *output_encoding)
{
static const char *utf8 = "UTF-8";
const char *use_encoding;
char *encoding;
char *msg = commit->buffer;
const char *msg = get_commit_buffer(commit, NULL);
char *out;
if (!msg) {
enum object_type type;
unsigned long size;
msg = read_sha1_file(commit->object.sha1, &type, &size);
if (!msg)
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 (!output_encoding || !*output_encoding) {
if (commit_encoding)
*commit_encoding =
@ -652,12 +639,13 @@ char *logmsg_reencode(const struct commit *commit,
* Otherwise, we still want to munge the encoding header in the
* result, which will be done by modifying the buffer. If we
* are using a fresh copy, we can reuse it. But if we are using
* the cached copy from commit->buffer, we need to duplicate it
* to avoid munging commit->buffer.
* the cached copy from get_commit_buffer, we need to duplicate it
* to avoid munging the cached copy.
*/
out = msg;
if (out == commit->buffer)
out = xstrdup(out);
if (msg == get_cached_commit_buffer(commit, NULL))
out = xstrdup(msg);
else
out = (char *)msg;
}
else {
/*
@ -667,8 +655,8 @@ char *logmsg_reencode(const struct commit *commit,
* copy, we can free it.
*/
out = reencode_string(msg, output_encoding, use_encoding);
if (out && msg != commit->buffer)
free(msg);
if (out)
unuse_commit_buffer(commit, msg);
}
/*
@ -687,12 +675,6 @@ char *logmsg_reencode(const struct commit *commit,
return out ? out : msg;
}
void logmsg_free(char *msg, const struct commit *commit)
{
if (msg != commit->buffer)
free(msg);
}
static int mailmap_name(const char **email, size_t *email_len,
const char **name, size_t *name_len)
{
@ -796,7 +778,7 @@ struct format_commit_context {
struct signature_check signature_check;
enum flush_type flush_type;
enum trunc_type truncate;
char *message;
const char *message;
char *commit_encoding;
size_t width, indent1, indent2;
int auto_color;
@ -1536,7 +1518,7 @@ void format_commit_message(const struct commit *commit,
}
free(context.commit_encoding);
logmsg_free(context.message, commit);
unuse_commit_buffer(commit, context.message);
free(context.signature_check.gpg_output);
free(context.signature_check.signer);
}
@ -1705,7 +1687,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
unsigned long beginning_of_body;
int indent = 4;
const char *msg;
char *reencoded;
const char *reencoded;
const char *encoding;
int need_8bit_cte = pp->need_8bit_cte;
@ -1772,7 +1754,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
strbuf_addch(sb, '\n');
logmsg_free(reencoded, commit);
unuse_commit_buffer(commit, reencoded);
}
void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,

Просмотреть файл

@ -2791,7 +2791,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
{
int retval;
const char *encoding;
char *message;
const char *message;
struct strbuf buf = STRBUF_INIT;
if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list)
@ -2833,14 +2833,21 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
format_display_notes(commit->object.sha1, &buf, encoding, 1);
}
/* Find either in the original commit message, or in the temporary */
/*
* Find either in the original commit message, or in the temporary.
* Note that we cast away the constness of "message" here. It is
* const because it may come from the cached commit buffer. That's OK,
* because we know that it is modifiable heap memory, and that while
* grep_buffer may modify it for speed, it will restore any
* changes before returning.
*/
if (buf.len)
retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len);
else
retval = grep_buffer(&opt->grep_filter,
message, strlen(message));
(char *)message, strlen(message));
strbuf_release(&buf);
logmsg_free(message, commit);
unuse_commit_buffer(commit, message);
return retval;
}

Просмотреть файл

@ -116,39 +116,23 @@ static const char *action_name(const struct replay_opts *opts)
return opts->action == REPLAY_REVERT ? "revert" : "cherry-pick";
}
static char *get_encoding(const char *message);
struct commit_message {
char *parent_label;
const char *label;
const char *subject;
char *reencoded_message;
const char *message;
};
static int get_message(struct commit *commit, struct commit_message *out)
{
const char *encoding;
const char *abbrev, *subject;
int abbrev_len, subject_len;
char *q;
if (!commit->buffer)
return -1;
encoding = get_encoding(commit->buffer);
if (!encoding)
encoding = "UTF-8";
if (!git_commit_encoding)
git_commit_encoding = "UTF-8";
out->reencoded_message = NULL;
out->message = commit->buffer;
if (same_encoding(encoding, git_commit_encoding))
out->reencoded_message = reencode_string(commit->buffer,
git_commit_encoding, encoding);
if (out->reencoded_message)
out->message = out->reencoded_message;
out->message = logmsg_reencode(commit, NULL, git_commit_encoding);
abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
abbrev_len = strlen(abbrev);
@ -167,29 +151,10 @@ static int get_message(struct commit *commit, struct commit_message *out)
return 0;
}
static void free_message(struct commit_message *msg)
static void free_message(struct commit *commit, struct commit_message *msg)
{
free(msg->parent_label);
free(msg->reencoded_message);
}
static char *get_encoding(const char *message)
{
const char *p = message, *eol;
while (*p && *p != '\n') {
for (eol = p + 1; *eol && *eol != '\n'; eol++)
; /* do nothing */
if (starts_with(p, "encoding ")) {
char *result = xmalloc(eol - 8 - p);
strlcpy(result, p + 9, eol - 8 - p);
return result;
}
p = eol;
if (*p == '\n')
p++;
}
return NULL;
unuse_commit_buffer(commit, msg->message);
}
static void write_cherry_pick_head(struct commit *commit, const char *pseudoref)
@ -489,7 +454,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
unsigned char head[20];
struct commit *base, *next, *parent;
const char *base_label, *next_label;
struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
struct commit_message msg = { NULL, NULL, NULL, NULL };
char *defmsg = NULL;
struct strbuf msgbuf = STRBUF_INIT;
int res, unborn = 0, allow;
@ -654,7 +619,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
res = run_git_commit(defmsg, opts, allow);
leave:
free_message(&msg);
free_message(commit, &msg);
free(defmsg);
return res;
@ -701,10 +666,12 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
int subject_len;
for (cur = todo_list; cur; cur = cur->next) {
const char *commit_buffer = get_commit_buffer(cur->item, NULL);
sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
subject_len = find_commit_subject(cur->item->buffer, &subject);
subject_len = find_commit_subject(commit_buffer, &subject);
strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
subject_len, subject);
unuse_commit_buffer(cur->item, commit_buffer);
}
return 0;
}

Просмотреть файл

@ -862,27 +862,17 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
commit_list_insert(l->item, &backup);
}
while (list) {
char *p, *to_free = NULL;
const char *p, *buf;
struct commit *commit;
enum object_type type;
unsigned long size;
int matches;
commit = pop_most_recent_commit(&list, ONELINE_SEEN);
if (!parse_object(commit->object.sha1))
continue;
if (commit->buffer)
p = commit->buffer;
else {
p = read_sha1_file(commit->object.sha1, &type, &size);
if (!p)
continue;
to_free = p;
}
p = strstr(p, "\n\n");
buf = get_commit_buffer(commit, NULL);
p = strstr(buf, "\n\n");
matches = p && !regexec(&regex, p + 2, 0, NULL, 0);
free(to_free);
unuse_commit_buffer(commit, buf);
if (matches) {
hashcpy(sha1, commit->object.sha1);