Merge branch 'jk/chopped-ident'
authorJunio C Hamano <gitster@pobox.com>
Mon, 22 Apr 2013 18:11:36 +0000 (11:11 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 22 Apr 2013 18:11:36 +0000 (11:11 -0700)
A commit object whose author or committer ident are malformed
crashed some code that trusted that a name, an email and an
timestamp can always be found in it.

* jk/chopped-ident:
blame: handle broken commit headers gracefully
pretty: handle broken commit headers gracefully
cat-file: print tags raw for "cat-file -p"

1  2 
pretty.c
diff --combined pretty.c
index d3a82d22d398ae7234f8917f4d8b0770ba4d0c47,acbfceb5fea49e49f5cc8eaef816c4b0a6ffe05a..c11624832bf09d9b4630d8a9b5e213fe2de69c7f
+++ b/pretty.c
@@@ -393,6 -393,19 +393,19 @@@ static void add_rfc2047(struct strbuf *
        strbuf_addstr(sb, "?=");
  }
  
+ static const char *show_ident_date(const struct ident_split *ident,
+                                  enum date_mode mode)
+ {
+       unsigned long date = 0;
+       int tz = 0;
+       if (ident->date_begin && ident->date_end)
+               date = strtoul(ident->date_begin, NULL, 10);
+       if (ident->tz_begin && ident->tz_end)
+               tz = strtol(ident->tz_begin, NULL, 10);
+       return show_date(date, tz, mode);
+ }
  void pp_user_info(const struct pretty_print_context *pp,
                  const char *what, struct strbuf *sb,
                  const char *line, const char *encoding)
        struct strbuf mail;
        struct ident_split ident;
        int linelen;
-       char *line_end, *date;
+       char *line_end;
        const char *mailbuf, *namebuf;
        size_t namelen, maillen;
        int max_length = 78; /* per rfc2822 */
-       unsigned long time;
-       int tz;
  
        if (pp->fmt == CMIT_FMT_ONELINE)
                return;
        strbuf_add(&name, namebuf, namelen);
  
        namelen = name.len + mail.len + 3; /* ' ' + '<' + '>' */
-       time = strtoul(ident.date_begin, &date, 10);
-       tz = strtol(date, NULL, 10);
  
        if (pp->fmt == CMIT_FMT_EMAIL) {
                strbuf_addstr(sb, "From: ");
  
        switch (pp->fmt) {
        case CMIT_FMT_MEDIUM:
-               strbuf_addf(sb, "Date:   %s\n", show_date(time, tz, pp->date_mode));
+               strbuf_addf(sb, "Date:   %s\n",
+                           show_ident_date(&ident, pp->date_mode));
                break;
        case CMIT_FMT_EMAIL:
-               strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
+               strbuf_addf(sb, "Date: %s\n",
+                           show_ident_date(&ident, DATE_RFC2822));
                break;
        case CMIT_FMT_FULLER:
-               strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, pp->date_mode));
+               strbuf_addf(sb, "%sDate: %s\n", what,
+                           show_ident_date(&ident, pp->date_mode));
                break;
        default:
                /* notin' */
@@@ -688,8 -700,6 +700,6 @@@ static size_t format_person_part(struc
  {
        /* currently all placeholders have same length */
        const int placeholder_len = 2;
-       int tz;
-       unsigned long date = 0;
        struct ident_split s;
        const char *name, *mail;
        size_t maillen, namelen;
        if (!s.date_begin)
                goto skip;
  
-       date = strtoul(s.date_begin, NULL, 10);
        if (part == 't') {      /* date, UNIX timestamp */
                strbuf_add(sb, s.date_begin, s.date_end - s.date_begin);
                return placeholder_len;
        }
  
-       /* parse tz */
-       tz = strtoul(s.tz_begin + 1, NULL, 10);
-       if (*s.tz_begin == '-')
-               tz = -tz;
        switch (part) {
        case 'd':       /* date */
-               strbuf_addstr(sb, show_date(date, tz, dmode));
+               strbuf_addstr(sb, show_ident_date(&s, dmode));
                return placeholder_len;
        case 'D':       /* date, RFC2822 style */
-               strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
+               strbuf_addstr(sb, show_ident_date(&s, DATE_RFC2822));
                return placeholder_len;
        case 'r':       /* date, relative */
-               strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
+               strbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE));
                return placeholder_len;
        case 'i':       /* date, ISO 8601 */
-               strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
+               strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601));
                return placeholder_len;
        }
  
@@@ -766,7 -769,14 +769,7 @@@ struct format_commit_context 
        const struct pretty_print_context *pretty_ctx;
        unsigned commit_header_parsed:1;
        unsigned commit_message_parsed:1;
 -      unsigned commit_signature_parsed:1;
 -      struct {
 -              char *gpg_output;
 -              char *gpg_status;
 -              char good_bad;
 -              char *signer;
 -              char *key;
 -      } signature;
 +      struct signature_check signature_check;
        char *message;
        size_t width, indent1, indent2;
  
@@@ -949,6 -959,64 +952,6 @@@ static void rewrap_message_tail(struct 
        c->indent2 = new_indent2;
  }
  
 -static struct {
 -      char result;
 -      const char *check;
 -} signature_check[] = {
 -      { 'G', "\n[GNUPG:] GOODSIG " },
 -      { 'B', "\n[GNUPG:] BADSIG " },
 -};
 -
 -static void parse_signature_lines(struct format_commit_context *ctx)
 -{
 -      const char *buf = ctx->signature.gpg_status;
 -      int i;
 -
 -      for (i = 0; i < ARRAY_SIZE(signature_check); i++) {
 -              const char *found = strstr(buf, signature_check[i].check);
 -              const char *next;
 -              if (!found)
 -                      continue;
 -              ctx->signature.good_bad = signature_check[i].result;
 -              found += strlen(signature_check[i].check);
 -              ctx->signature.key = xmemdupz(found, 16);
 -              found += 17;
 -              next = strchrnul(found, '\n');
 -              ctx->signature.signer = xmemdupz(found, next - found);
 -              break;
 -      }
 -}
 -
 -static void parse_commit_signature(struct format_commit_context *ctx)
 -{
 -      struct strbuf payload = STRBUF_INIT;
 -      struct strbuf signature = STRBUF_INIT;
 -      struct strbuf gpg_output = STRBUF_INIT;
 -      struct strbuf gpg_status = STRBUF_INIT;
 -      int status;
 -
 -      ctx->commit_signature_parsed = 1;
 -
 -      if (parse_signed_commit(ctx->commit->object.sha1,
 -                              &payload, &signature) <= 0)
 -              goto out;
 -      status = verify_signed_buffer(payload.buf, payload.len,
 -                                    signature.buf, signature.len,
 -                                    &gpg_output, &gpg_status);
 -      if (status && !gpg_output.len)
 -              goto out;
 -      ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL);
 -      ctx->signature.gpg_status = strbuf_detach(&gpg_status, NULL);
 -      parse_signature_lines(ctx);
 -
 - out:
 -      strbuf_release(&gpg_status);
 -      strbuf_release(&gpg_output);
 -      strbuf_release(&payload);
 -      strbuf_release(&signature);
 -}
 -
 -
  static int format_reflog_person(struct strbuf *sb,
                                char part,
                                struct reflog_walk_info *log,
@@@ -1134,29 -1202,27 +1137,29 @@@ static size_t format_commit_one(struct 
        }
  
        if (placeholder[0] == 'G') {
 -              if (!c->commit_signature_parsed)
 -                      parse_commit_signature(c);
 +              if (!c->signature_check.result)
 +                      check_commit_signature(c->commit, &(c->signature_check));
                switch (placeholder[1]) {
                case 'G':
 -                      if (c->signature.gpg_output)
 -                              strbuf_addstr(sb, c->signature.gpg_output);
 +                      if (c->signature_check.gpg_output)
 +                              strbuf_addstr(sb, c->signature_check.gpg_output);
                        break;
                case '?':
 -                      switch (c->signature.good_bad) {
 +                      switch (c->signature_check.result) {
                        case 'G':
                        case 'B':
 -                              strbuf_addch(sb, c->signature.good_bad);
 +                      case 'U':
 +                      case 'N':
 +                              strbuf_addch(sb, c->signature_check.result);
                        }
                        break;
                case 'S':
 -                      if (c->signature.signer)
 -                              strbuf_addstr(sb, c->signature.signer);
 +                      if (c->signature_check.signer)
 +                              strbuf_addstr(sb, c->signature_check.signer);
                        break;
                case 'K':
 -                      if (c->signature.key)
 -                              strbuf_addstr(sb, c->signature.key);
 +                      if (c->signature_check.key)
 +                              strbuf_addstr(sb, c->signature_check.key);
                        break;
                }
                return 2;
@@@ -1294,8 -1360,8 +1297,8 @@@ void format_commit_message(const struc
        rewrap_message_tail(sb, &context, 0, 0, 0);
  
        logmsg_free(context.message, commit);
 -      free(context.signature.gpg_output);
 -      free(context.signature.signer);
 +      free(context.signature_check.gpg_output);
 +      free(context.signature_check.signer);
  }
  
  static void pp_header(const struct pretty_print_context *pp,