git-compat-util.h: xsize_t() - avoid -Wsign-compare warnings
[git] / tag.c
1 #include "cache.h"
2 #include "tag.h"
3 #include "commit.h"
4 #include "tree.h"
5 #include "blob.h"
6 #include "gpg-interface.h"
7
8 const char *tag_type = "tag";
9
10 static int run_gpg_verify(const char *buf, unsigned long size, unsigned flags)
11 {
12         struct signature_check sigc;
13         size_t payload_size;
14         int ret;
15
16         memset(&sigc, 0, sizeof(sigc));
17
18         payload_size = parse_signature(buf, size);
19
20         if (size == payload_size) {
21                 if (flags & GPG_VERIFY_VERBOSE)
22                         write_in_full(1, buf, payload_size);
23                 return error("no signature found");
24         }
25
26         ret = check_signature(buf, payload_size, buf + payload_size,
27                                 size - payload_size, &sigc);
28
29         if (!(flags & GPG_VERIFY_OMIT_STATUS))
30                 print_signature_buffer(&sigc, flags);
31
32         signature_check_clear(&sigc);
33         return ret;
34 }
35
36 int gpg_verify_tag(const unsigned char *sha1, const char *name_to_report,
37                 unsigned flags)
38 {
39         enum object_type type;
40         char *buf;
41         unsigned long size;
42         int ret;
43
44         type = sha1_object_info(sha1, NULL);
45         if (type != OBJ_TAG)
46                 return error("%s: cannot verify a non-tag object of type %s.",
47                                 name_to_report ?
48                                 name_to_report :
49                                 find_unique_abbrev(sha1, DEFAULT_ABBREV),
50                                 typename(type));
51
52         buf = read_sha1_file(sha1, &type, &size);
53         if (!buf)
54                 return error("%s: unable to read file.",
55                                 name_to_report ?
56                                 name_to_report :
57                                 find_unique_abbrev(sha1, DEFAULT_ABBREV));
58
59         ret = run_gpg_verify(buf, size, flags);
60
61         free(buf);
62         return ret;
63 }
64
65 struct object *deref_tag(struct object *o, const char *warn, int warnlen)
66 {
67         while (o && o->type == OBJ_TAG)
68                 if (((struct tag *)o)->tagged)
69                         o = parse_object(&((struct tag *)o)->tagged->oid);
70                 else
71                         o = NULL;
72         if (!o && warn) {
73                 if (!warnlen)
74                         warnlen = strlen(warn);
75                 error("missing object referenced by '%.*s'", warnlen, warn);
76         }
77         return o;
78 }
79
80 struct object *deref_tag_noverify(struct object *o)
81 {
82         while (o && o->type == OBJ_TAG) {
83                 o = parse_object(&o->oid);
84                 if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged)
85                         o = ((struct tag *)o)->tagged;
86                 else
87                         o = NULL;
88         }
89         return o;
90 }
91
92 struct tag *lookup_tag(const struct object_id *oid)
93 {
94         struct object *obj = lookup_object(oid->hash);
95         if (!obj)
96                 return create_object(oid->hash, alloc_tag_node());
97         return object_as_type(obj, OBJ_TAG, 0);
98 }
99
100 static timestamp_t parse_tag_date(const char *buf, const char *tail)
101 {
102         const char *dateptr;
103
104         while (buf < tail && *buf++ != '>')
105                 /* nada */;
106         if (buf >= tail)
107                 return 0;
108         dateptr = buf;
109         while (buf < tail && *buf++ != '\n')
110                 /* nada */;
111         if (buf >= tail)
112                 return 0;
113         /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */
114         return parse_timestamp(dateptr, NULL, 10);
115 }
116
117 int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)
118 {
119         struct object_id oid;
120         char type[20];
121         const char *bufptr = data;
122         const char *tail = bufptr + size;
123         const char *nl;
124
125         if (item->object.parsed)
126                 return 0;
127         item->object.parsed = 1;
128
129         if (size < GIT_SHA1_HEXSZ + 24)
130                 return -1;
131         if (memcmp("object ", bufptr, 7) || parse_oid_hex(bufptr + 7, &oid, &bufptr) || *bufptr++ != '\n')
132                 return -1;
133
134         if (!starts_with(bufptr, "type "))
135                 return -1;
136         bufptr += 5;
137         nl = memchr(bufptr, '\n', tail - bufptr);
138         if (!nl || sizeof(type) <= (nl - bufptr))
139                 return -1;
140         memcpy(type, bufptr, nl - bufptr);
141         type[nl - bufptr] = '\0';
142         bufptr = nl + 1;
143
144         if (!strcmp(type, blob_type)) {
145                 item->tagged = &lookup_blob(&oid)->object;
146         } else if (!strcmp(type, tree_type)) {
147                 item->tagged = &lookup_tree(&oid)->object;
148         } else if (!strcmp(type, commit_type)) {
149                 item->tagged = &lookup_commit(&oid)->object;
150         } else if (!strcmp(type, tag_type)) {
151                 item->tagged = &lookup_tag(&oid)->object;
152         } else {
153                 error("Unknown type %s", type);
154                 item->tagged = NULL;
155         }
156
157         if (bufptr + 4 < tail && starts_with(bufptr, "tag "))
158                 ;               /* good */
159         else
160                 return -1;
161         bufptr += 4;
162         nl = memchr(bufptr, '\n', tail - bufptr);
163         if (!nl)
164                 return -1;
165         item->tag = xmemdupz(bufptr, nl - bufptr);
166         bufptr = nl + 1;
167
168         if (bufptr + 7 < tail && starts_with(bufptr, "tagger "))
169                 item->date = parse_tag_date(bufptr, tail);
170         else
171                 item->date = 0;
172
173         return 0;
174 }
175
176 int parse_tag(struct tag *item)
177 {
178         enum object_type type;
179         void *data;
180         unsigned long size;
181         int ret;
182
183         if (item->object.parsed)
184                 return 0;
185         data = read_sha1_file(item->object.oid.hash, &type, &size);
186         if (!data)
187                 return error("Could not read %s",
188                              oid_to_hex(&item->object.oid));
189         if (type != OBJ_TAG) {
190                 free(data);
191                 return error("Object %s not a tag",
192                              oid_to_hex(&item->object.oid));
193         }
194         ret = parse_tag_buffer(item, data, size);
195         free(data);
196         return ret;
197 }