2005-04-28 18:46:33 +04:00
|
|
|
#include "cache.h"
|
2006-01-07 12:33:54 +03:00
|
|
|
#include "tag.h"
|
2018-05-16 02:42:15 +03:00
|
|
|
#include "object-store.h"
|
2007-02-26 22:56:00 +03:00
|
|
|
#include "commit.h"
|
|
|
|
#include "tree.h"
|
|
|
|
#include "blob.h"
|
2018-05-16 00:48:42 +03:00
|
|
|
#include "alloc.h"
|
2017-01-18 02:37:18 +03:00
|
|
|
#include "gpg-interface.h"
|
2005-04-28 18:46:33 +04:00
|
|
|
|
|
|
|
const char *tag_type = "tag";
|
|
|
|
|
2016-04-22 17:52:04 +03:00
|
|
|
static int run_gpg_verify(const char *buf, unsigned long size, unsigned flags)
|
|
|
|
{
|
|
|
|
struct signature_check sigc;
|
|
|
|
size_t payload_size;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&sigc, 0, sizeof(sigc));
|
|
|
|
|
|
|
|
payload_size = parse_signature(buf, size);
|
|
|
|
|
|
|
|
if (size == payload_size) {
|
|
|
|
if (flags & GPG_VERIFY_VERBOSE)
|
|
|
|
write_in_full(1, buf, payload_size);
|
|
|
|
return error("no signature found");
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = check_signature(buf, payload_size, buf + payload_size,
|
|
|
|
size - payload_size, &sigc);
|
2017-01-18 02:37:18 +03:00
|
|
|
|
|
|
|
if (!(flags & GPG_VERIFY_OMIT_STATUS))
|
|
|
|
print_signature_buffer(&sigc, flags);
|
2016-04-22 17:52:04 +03:00
|
|
|
|
|
|
|
signature_check_clear(&sigc);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-07-13 03:44:15 +03:00
|
|
|
int gpg_verify_tag(const struct object_id *oid, const char *name_to_report,
|
2016-04-22 17:52:04 +03:00
|
|
|
unsigned flags)
|
|
|
|
{
|
|
|
|
enum object_type type;
|
|
|
|
char *buf;
|
|
|
|
unsigned long size;
|
|
|
|
int ret;
|
|
|
|
|
2018-04-25 21:20:59 +03:00
|
|
|
type = oid_object_info(the_repository, oid, NULL);
|
2016-04-22 17:52:04 +03:00
|
|
|
if (type != OBJ_TAG)
|
|
|
|
return error("%s: cannot verify a non-tag object of type %s.",
|
|
|
|
name_to_report ?
|
|
|
|
name_to_report :
|
2018-03-12 05:27:30 +03:00
|
|
|
find_unique_abbrev(oid, DEFAULT_ABBREV),
|
2018-02-14 21:59:24 +03:00
|
|
|
type_name(type));
|
2016-04-22 17:52:04 +03:00
|
|
|
|
sha1_file: convert read_sha1_file to struct object_id
Convert read_sha1_file to take a pointer to struct object_id and rename
it read_object_file. Do the same for read_sha1_file_extended.
Convert one use in grep.c to use the new function without any other code
change, since the pointer being passed is a void pointer that is already
initialized with a pointer to struct object_id. Update the declaration
and definitions of the modified functions, and apply the following
semantic patch to convert the remaining callers:
@@
expression E1, E2, E3;
@@
- read_sha1_file(E1.hash, E2, E3)
+ read_object_file(&E1, E2, E3)
@@
expression E1, E2, E3;
@@
- read_sha1_file(E1->hash, E2, E3)
+ read_object_file(E1, E2, E3)
@@
expression E1, E2, E3, E4;
@@
- read_sha1_file_extended(E1.hash, E2, E3, E4)
+ read_object_file_extended(&E1, E2, E3, E4)
@@
expression E1, E2, E3, E4;
@@
- read_sha1_file_extended(E1->hash, E2, E3, E4)
+ read_object_file_extended(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-03-12 05:27:53 +03:00
|
|
|
buf = read_object_file(oid, &type, &size);
|
2016-04-22 17:52:04 +03:00
|
|
|
if (!buf)
|
|
|
|
return error("%s: unable to read file.",
|
|
|
|
name_to_report ?
|
|
|
|
name_to_report :
|
2018-03-12 05:27:30 +03:00
|
|
|
find_unique_abbrev(oid, DEFAULT_ABBREV));
|
2016-04-22 17:52:04 +03:00
|
|
|
|
|
|
|
ret = run_gpg_verify(buf, size, flags);
|
|
|
|
|
|
|
|
free(buf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-06-29 04:22:05 +03:00
|
|
|
struct object *deref_tag_the_repository(struct object *o, const char *warn, int warnlen)
|
2005-08-05 11:47:56 +04:00
|
|
|
{
|
2006-07-12 07:45:31 +04:00
|
|
|
while (o && o->type == OBJ_TAG)
|
2008-02-18 10:31:55 +03:00
|
|
|
if (((struct tag *)o)->tagged)
|
2018-06-29 04:21:51 +03:00
|
|
|
o = parse_object(the_repository,
|
|
|
|
&((struct tag *)o)->tagged->oid);
|
2008-02-18 10:31:55 +03:00
|
|
|
else
|
|
|
|
o = NULL;
|
2005-11-03 02:19:13 +03:00
|
|
|
if (!o && warn) {
|
|
|
|
if (!warnlen)
|
|
|
|
warnlen = strlen(warn);
|
|
|
|
error("missing object referenced by '%.*s'", warnlen, warn);
|
|
|
|
}
|
2005-08-05 11:47:56 +04:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
upload-pack: avoid parsing tag destinations
When upload-pack advertises refs, it dereferences any tags
it sees, and shows the resulting sha1 to the client. It does
this by calling deref_tag. That function must load and parse
each tag object to find the sha1 of the tagged object.
However, it also ends up parsing the tagged object itself,
which is not strictly necessary for upload-pack's use.
Each tag produces two object loads (assuming it is not a
recursive tag), when it could get away with only a single
one. Dropping the second load halves the effort we spend.
The downside is that we are no longer verifying the
resulting object by loading it. In particular:
1. We never cross-check the "type" field given in the tag
object with the type of the pointed-to object. If the
tag says it points to a tag but doesn't, then we will
keep peeling and realize the error. If the tag says it
points to a non-tag but actually points to a tag, we
will stop peeling and just advertise the pointed-to
tag.
2. If we are missing the pointed-to object, we will not
realize (because we never even look it up in the object
db).
However, both of these are errors in the object database,
and both will be detected if a client actually requests the
broken objects in question. So we are simply pushing the
verification away from the advertising stage, and down to
the actual fetching stage.
On my test repo with 120K refs, this drops the time to
advertise the refs from ~3.2s to ~2.0s.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-01-06 23:18:01 +04:00
|
|
|
struct object *deref_tag_noverify(struct object *o)
|
|
|
|
{
|
|
|
|
while (o && o->type == OBJ_TAG) {
|
2018-06-29 04:21:51 +03:00
|
|
|
o = parse_object(the_repository, &o->oid);
|
upload-pack: avoid parsing tag destinations
When upload-pack advertises refs, it dereferences any tags
it sees, and shows the resulting sha1 to the client. It does
this by calling deref_tag. That function must load and parse
each tag object to find the sha1 of the tagged object.
However, it also ends up parsing the tagged object itself,
which is not strictly necessary for upload-pack's use.
Each tag produces two object loads (assuming it is not a
recursive tag), when it could get away with only a single
one. Dropping the second load halves the effort we spend.
The downside is that we are no longer verifying the
resulting object by loading it. In particular:
1. We never cross-check the "type" field given in the tag
object with the type of the pointed-to object. If the
tag says it points to a tag but doesn't, then we will
keep peeling and realize the error. If the tag says it
points to a non-tag but actually points to a tag, we
will stop peeling and just advertise the pointed-to
tag.
2. If we are missing the pointed-to object, we will not
realize (because we never even look it up in the object
db).
However, both of these are errors in the object database,
and both will be detected if a client actually requests the
broken objects in question. So we are simply pushing the
verification away from the advertising stage, and down to
the actual fetching stage.
On my test repo with 120K refs, this drops the time to
advertise the refs from ~3.2s to ~2.0s.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-01-06 23:18:01 +04:00
|
|
|
if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged)
|
|
|
|
o = ((struct tag *)o)->tagged;
|
|
|
|
else
|
|
|
|
o = NULL;
|
|
|
|
}
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2018-06-29 04:22:11 +03:00
|
|
|
struct tag *lookup_tag(struct repository *r, const struct object_id *oid)
|
2005-04-28 18:46:33 +04:00
|
|
|
{
|
2018-06-29 04:22:11 +03:00
|
|
|
struct object *obj = lookup_object(r, oid->hash);
|
2007-04-17 09:11:43 +04:00
|
|
|
if (!obj)
|
2018-06-29 04:22:11 +03:00
|
|
|
return create_object(r, oid->hash,
|
|
|
|
alloc_tag_node(r));
|
|
|
|
return object_as_type(r, obj, OBJ_TAG, 0);
|
2005-04-28 18:46:33 +04:00
|
|
|
}
|
|
|
|
|
2017-04-26 22:29:31 +03:00
|
|
|
static timestamp_t parse_tag_date(const char *buf, const char *tail)
|
2010-04-13 03:25:28 +04:00
|
|
|
{
|
|
|
|
const char *dateptr;
|
|
|
|
|
|
|
|
while (buf < tail && *buf++ != '>')
|
|
|
|
/* nada */;
|
|
|
|
if (buf >= tail)
|
|
|
|
return 0;
|
|
|
|
dateptr = buf;
|
|
|
|
while (buf < tail && *buf++ != '\n')
|
|
|
|
/* nada */;
|
|
|
|
if (buf >= tail)
|
|
|
|
return 0;
|
2017-04-21 13:45:44 +03:00
|
|
|
/* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */
|
|
|
|
return parse_timestamp(dateptr, NULL, 10);
|
2010-04-13 03:25:28 +04:00
|
|
|
}
|
|
|
|
|
2018-05-16 00:48:42 +03:00
|
|
|
void release_tag_memory(struct tag *t)
|
|
|
|
{
|
|
|
|
free(t->tag);
|
|
|
|
t->tagged = NULL;
|
|
|
|
t->object.parsed = 0;
|
|
|
|
t->date = 0;
|
|
|
|
}
|
|
|
|
|
2018-06-29 04:22:04 +03:00
|
|
|
int parse_tag_buffer_the_repository(struct tag *item, const void *data, unsigned long size)
|
2005-04-28 18:46:33 +04:00
|
|
|
{
|
2017-05-07 01:10:02 +03:00
|
|
|
struct object_id oid;
|
2005-06-22 04:35:10 +04:00
|
|
|
char type[20];
|
2010-04-13 03:25:27 +04:00
|
|
|
const char *bufptr = data;
|
|
|
|
const char *tail = bufptr + size;
|
|
|
|
const char *nl;
|
2005-04-30 20:51:03 +04:00
|
|
|
|
2010-04-13 03:25:25 +04:00
|
|
|
if (item->object.parsed)
|
|
|
|
return 0;
|
|
|
|
item->object.parsed = 1;
|
2005-04-28 18:46:33 +04:00
|
|
|
|
2017-05-07 01:10:02 +03:00
|
|
|
if (size < GIT_SHA1_HEXSZ + 24)
|
2005-05-06 21:48:34 +04:00
|
|
|
return -1;
|
2017-05-07 01:10:02 +03:00
|
|
|
if (memcmp("object ", bufptr, 7) || parse_oid_hex(bufptr + 7, &oid, &bufptr) || *bufptr++ != '\n')
|
2005-05-06 21:48:34 +04:00
|
|
|
return -1;
|
2005-04-28 18:46:33 +04:00
|
|
|
|
2013-12-01 00:55:40 +04:00
|
|
|
if (!starts_with(bufptr, "type "))
|
2005-05-06 21:48:34 +04:00
|
|
|
return -1;
|
2010-04-13 03:25:27 +04:00
|
|
|
bufptr += 5;
|
|
|
|
nl = memchr(bufptr, '\n', tail - bufptr);
|
|
|
|
if (!nl || sizeof(type) <= (nl - bufptr))
|
2005-05-06 21:48:34 +04:00
|
|
|
return -1;
|
2015-09-25 00:08:26 +03:00
|
|
|
memcpy(type, bufptr, nl - bufptr);
|
2010-04-13 03:25:27 +04:00
|
|
|
type[nl - bufptr] = '\0';
|
|
|
|
bufptr = nl + 1;
|
2005-04-28 18:46:33 +04:00
|
|
|
|
2007-02-26 22:56:00 +03:00
|
|
|
if (!strcmp(type, blob_type)) {
|
2018-06-29 04:21:55 +03:00
|
|
|
item->tagged = (struct object *)lookup_blob(the_repository, &oid);
|
2007-02-26 22:56:00 +03:00
|
|
|
} else if (!strcmp(type, tree_type)) {
|
2018-06-29 04:21:56 +03:00
|
|
|
item->tagged = (struct object *)lookup_tree(the_repository, &oid);
|
2007-02-26 22:56:00 +03:00
|
|
|
} else if (!strcmp(type, commit_type)) {
|
2018-06-29 04:21:59 +03:00
|
|
|
item->tagged = (struct object *)lookup_commit(the_repository, &oid);
|
2007-02-26 22:56:00 +03:00
|
|
|
} else if (!strcmp(type, tag_type)) {
|
2018-06-29 04:22:03 +03:00
|
|
|
item->tagged = (struct object *)lookup_tag(the_repository, &oid);
|
2007-02-26 22:56:00 +03:00
|
|
|
} else {
|
|
|
|
error("Unknown type %s", type);
|
|
|
|
item->tagged = NULL;
|
|
|
|
}
|
|
|
|
|
2013-12-01 00:55:40 +04:00
|
|
|
if (bufptr + 4 < tail && starts_with(bufptr, "tag "))
|
2011-02-14 16:02:51 +03:00
|
|
|
; /* good */
|
|
|
|
else
|
2010-04-13 03:25:27 +04:00
|
|
|
return -1;
|
|
|
|
bufptr += 4;
|
|
|
|
nl = memchr(bufptr, '\n', tail - bufptr);
|
|
|
|
if (!nl)
|
|
|
|
return -1;
|
|
|
|
item->tag = xmemdupz(bufptr, nl - bufptr);
|
|
|
|
bufptr = nl + 1;
|
|
|
|
|
2013-12-01 00:55:40 +04:00
|
|
|
if (bufptr + 7 < tail && starts_with(bufptr, "tagger "))
|
2010-04-13 03:25:28 +04:00
|
|
|
item->date = parse_tag_date(bufptr, tail);
|
|
|
|
else
|
|
|
|
item->date = 0;
|
|
|
|
|
2005-04-28 18:46:33 +04:00
|
|
|
return 0;
|
2005-05-06 21:48:34 +04:00
|
|
|
}
|
2005-05-04 21:44:15 +04:00
|
|
|
|
2005-05-06 21:48:34 +04:00
|
|
|
int parse_tag(struct tag *item)
|
|
|
|
{
|
2007-02-26 22:55:59 +03:00
|
|
|
enum object_type type;
|
2005-05-06 21:48:34 +04:00
|
|
|
void *data;
|
|
|
|
unsigned long size;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (item->object.parsed)
|
|
|
|
return 0;
|
sha1_file: convert read_sha1_file to struct object_id
Convert read_sha1_file to take a pointer to struct object_id and rename
it read_object_file. Do the same for read_sha1_file_extended.
Convert one use in grep.c to use the new function without any other code
change, since the pointer being passed is a void pointer that is already
initialized with a pointer to struct object_id. Update the declaration
and definitions of the modified functions, and apply the following
semantic patch to convert the remaining callers:
@@
expression E1, E2, E3;
@@
- read_sha1_file(E1.hash, E2, E3)
+ read_object_file(&E1, E2, E3)
@@
expression E1, E2, E3;
@@
- read_sha1_file(E1->hash, E2, E3)
+ read_object_file(E1, E2, E3)
@@
expression E1, E2, E3, E4;
@@
- read_sha1_file_extended(E1.hash, E2, E3, E4)
+ read_object_file_extended(&E1, E2, E3, E4)
@@
expression E1, E2, E3, E4;
@@
- read_sha1_file_extended(E1->hash, E2, E3, E4)
+ read_object_file_extended(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-03-12 05:27:53 +03:00
|
|
|
data = read_object_file(&item->object.oid, &type, &size);
|
2005-05-06 21:48:34 +04:00
|
|
|
if (!data)
|
|
|
|
return error("Could not read %s",
|
2015-11-10 05:22:28 +03:00
|
|
|
oid_to_hex(&item->object.oid));
|
2007-02-26 22:55:59 +03:00
|
|
|
if (type != OBJ_TAG) {
|
2005-05-06 21:48:34 +04:00
|
|
|
free(data);
|
|
|
|
return error("Object %s not a tag",
|
2015-11-10 05:22:28 +03:00
|
|
|
oid_to_hex(&item->object.oid));
|
2005-05-06 21:48:34 +04:00
|
|
|
}
|
2018-06-29 04:22:04 +03:00
|
|
|
ret = parse_tag_buffer(the_repository, item, data, size);
|
2005-05-04 21:44:15 +04:00
|
|
|
free(data);
|
2005-05-06 21:48:34 +04:00
|
|
|
return ret;
|
2005-04-28 18:46:33 +04:00
|
|
|
}
|