tag.con commit test/send-email: --[no-]xmailer tests (2cf770f)
   1#include "cache.h"
   2#include "tag.h"
   3#include "commit.h"
   4#include "tree.h"
   5#include "blob.h"
   6
   7#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
   8#define PGP_MESSAGE "-----BEGIN PGP MESSAGE-----"
   9
  10const char *tag_type = "tag";
  11
  12struct object *deref_tag(struct object *o, const char *warn, int warnlen)
  13{
  14        while (o && o->type == OBJ_TAG)
  15                if (((struct tag *)o)->tagged)
  16                        o = parse_object(((struct tag *)o)->tagged->sha1);
  17                else
  18                        o = NULL;
  19        if (!o && warn) {
  20                if (!warnlen)
  21                        warnlen = strlen(warn);
  22                error("missing object referenced by '%.*s'", warnlen, warn);
  23        }
  24        return o;
  25}
  26
  27struct object *deref_tag_noverify(struct object *o)
  28{
  29        while (o && o->type == OBJ_TAG) {
  30                o = parse_object(o->sha1);
  31                if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged)
  32                        o = ((struct tag *)o)->tagged;
  33                else
  34                        o = NULL;
  35        }
  36        return o;
  37}
  38
  39struct tag *lookup_tag(const unsigned char *sha1)
  40{
  41        struct object *obj = lookup_object(sha1);
  42        if (!obj)
  43                return create_object(sha1, alloc_tag_node());
  44        return object_as_type(obj, OBJ_TAG, 0);
  45}
  46
  47static unsigned long parse_tag_date(const char *buf, const char *tail)
  48{
  49        const char *dateptr;
  50
  51        while (buf < tail && *buf++ != '>')
  52                /* nada */;
  53        if (buf >= tail)
  54                return 0;
  55        dateptr = buf;
  56        while (buf < tail && *buf++ != '\n')
  57                /* nada */;
  58        if (buf >= tail)
  59                return 0;
  60        /* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
  61        return strtoul(dateptr, NULL, 10);
  62}
  63
  64int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)
  65{
  66        unsigned char sha1[20];
  67        char type[20];
  68        const char *bufptr = data;
  69        const char *tail = bufptr + size;
  70        const char *nl;
  71
  72        if (item->object.parsed)
  73                return 0;
  74        item->object.parsed = 1;
  75
  76        if (size < 64)
  77                return -1;
  78        if (memcmp("object ", bufptr, 7) || get_sha1_hex(bufptr + 7, sha1) || bufptr[47] != '\n')
  79                return -1;
  80        bufptr += 48; /* "object " + sha1 + "\n" */
  81
  82        if (!starts_with(bufptr, "type "))
  83                return -1;
  84        bufptr += 5;
  85        nl = memchr(bufptr, '\n', tail - bufptr);
  86        if (!nl || sizeof(type) <= (nl - bufptr))
  87                return -1;
  88        strncpy(type, bufptr, nl - bufptr);
  89        type[nl - bufptr] = '\0';
  90        bufptr = nl + 1;
  91
  92        if (!strcmp(type, blob_type)) {
  93                item->tagged = &lookup_blob(sha1)->object;
  94        } else if (!strcmp(type, tree_type)) {
  95                item->tagged = &lookup_tree(sha1)->object;
  96        } else if (!strcmp(type, commit_type)) {
  97                item->tagged = &lookup_commit(sha1)->object;
  98        } else if (!strcmp(type, tag_type)) {
  99                item->tagged = &lookup_tag(sha1)->object;
 100        } else {
 101                error("Unknown type %s", type);
 102                item->tagged = NULL;
 103        }
 104
 105        if (bufptr + 4 < tail && starts_with(bufptr, "tag "))
 106                ;               /* good */
 107        else
 108                return -1;
 109        bufptr += 4;
 110        nl = memchr(bufptr, '\n', tail - bufptr);
 111        if (!nl)
 112                return -1;
 113        item->tag = xmemdupz(bufptr, nl - bufptr);
 114        bufptr = nl + 1;
 115
 116        if (bufptr + 7 < tail && starts_with(bufptr, "tagger "))
 117                item->date = parse_tag_date(bufptr, tail);
 118        else
 119                item->date = 0;
 120
 121        return 0;
 122}
 123
 124int parse_tag(struct tag *item)
 125{
 126        enum object_type type;
 127        void *data;
 128        unsigned long size;
 129        int ret;
 130
 131        if (item->object.parsed)
 132                return 0;
 133        data = read_sha1_file(item->object.sha1, &type, &size);
 134        if (!data)
 135                return error("Could not read %s",
 136                             sha1_to_hex(item->object.sha1));
 137        if (type != OBJ_TAG) {
 138                free(data);
 139                return error("Object %s not a tag",
 140                             sha1_to_hex(item->object.sha1));
 141        }
 142        ret = parse_tag_buffer(item, data, size);
 143        free(data);
 144        return ret;
 145}
 146
 147/*
 148 * Look at a signed tag object, and return the offset where
 149 * the embedded detached signature begins, or the end of the
 150 * data when there is no such signature.
 151 */
 152size_t parse_signature(const char *buf, unsigned long size)
 153{
 154        char *eol;
 155        size_t len = 0;
 156        while (len < size && !starts_with(buf + len, PGP_SIGNATURE) &&
 157                        !starts_with(buf + len, PGP_MESSAGE)) {
 158                eol = memchr(buf + len, '\n', size - len);
 159                len += eol ? eol - (buf + len) + 1 : size - len;
 160        }
 161        return len;
 162}