mirror of
https://github.com/git/git
synced 2024-08-24 18:26:02 +00:00
![Jeff King](/assets/img/avatar_default.png)
strncpy is known to be a confusing function because of its termination semantics. These calls are all correct, but it takes some examination to see why. In particular, every one of them expects to copy up to the length limit, and then makes some arrangement for terminating the result. We can just use memcpy, along with noting explicitly how the result is terminated (if it is not already obvious). That should make it more clear to a reader that we are doing the right thing. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
143 lines
3.2 KiB
C
143 lines
3.2 KiB
C
#include "cache.h"
|
|
#include "tag.h"
|
|
#include "commit.h"
|
|
#include "tree.h"
|
|
#include "blob.h"
|
|
|
|
const char *tag_type = "tag";
|
|
|
|
struct object *deref_tag(struct object *o, const char *warn, int warnlen)
|
|
{
|
|
while (o && o->type == OBJ_TAG)
|
|
if (((struct tag *)o)->tagged)
|
|
o = parse_object(((struct tag *)o)->tagged->sha1);
|
|
else
|
|
o = NULL;
|
|
if (!o && warn) {
|
|
if (!warnlen)
|
|
warnlen = strlen(warn);
|
|
error("missing object referenced by '%.*s'", warnlen, warn);
|
|
}
|
|
return o;
|
|
}
|
|
|
|
struct object *deref_tag_noverify(struct object *o)
|
|
{
|
|
while (o && o->type == OBJ_TAG) {
|
|
o = parse_object(o->sha1);
|
|
if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged)
|
|
o = ((struct tag *)o)->tagged;
|
|
else
|
|
o = NULL;
|
|
}
|
|
return o;
|
|
}
|
|
|
|
struct tag *lookup_tag(const unsigned char *sha1)
|
|
{
|
|
struct object *obj = lookup_object(sha1);
|
|
if (!obj)
|
|
return create_object(sha1, alloc_tag_node());
|
|
return object_as_type(obj, OBJ_TAG, 0);
|
|
}
|
|
|
|
static unsigned long parse_tag_date(const char *buf, const char *tail)
|
|
{
|
|
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;
|
|
/* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
|
|
return strtoul(dateptr, NULL, 10);
|
|
}
|
|
|
|
int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)
|
|
{
|
|
unsigned char sha1[20];
|
|
char type[20];
|
|
const char *bufptr = data;
|
|
const char *tail = bufptr + size;
|
|
const char *nl;
|
|
|
|
if (item->object.parsed)
|
|
return 0;
|
|
item->object.parsed = 1;
|
|
|
|
if (size < 64)
|
|
return -1;
|
|
if (memcmp("object ", bufptr, 7) || get_sha1_hex(bufptr + 7, sha1) || bufptr[47] != '\n')
|
|
return -1;
|
|
bufptr += 48; /* "object " + sha1 + "\n" */
|
|
|
|
if (!starts_with(bufptr, "type "))
|
|
return -1;
|
|
bufptr += 5;
|
|
nl = memchr(bufptr, '\n', tail - bufptr);
|
|
if (!nl || sizeof(type) <= (nl - bufptr))
|
|
return -1;
|
|
memcpy(type, bufptr, nl - bufptr);
|
|
type[nl - bufptr] = '\0';
|
|
bufptr = nl + 1;
|
|
|
|
if (!strcmp(type, blob_type)) {
|
|
item->tagged = &lookup_blob(sha1)->object;
|
|
} else if (!strcmp(type, tree_type)) {
|
|
item->tagged = &lookup_tree(sha1)->object;
|
|
} else if (!strcmp(type, commit_type)) {
|
|
item->tagged = &lookup_commit(sha1)->object;
|
|
} else if (!strcmp(type, tag_type)) {
|
|
item->tagged = &lookup_tag(sha1)->object;
|
|
} else {
|
|
error("Unknown type %s", type);
|
|
item->tagged = NULL;
|
|
}
|
|
|
|
if (bufptr + 4 < tail && starts_with(bufptr, "tag "))
|
|
; /* good */
|
|
else
|
|
return -1;
|
|
bufptr += 4;
|
|
nl = memchr(bufptr, '\n', tail - bufptr);
|
|
if (!nl)
|
|
return -1;
|
|
item->tag = xmemdupz(bufptr, nl - bufptr);
|
|
bufptr = nl + 1;
|
|
|
|
if (bufptr + 7 < tail && starts_with(bufptr, "tagger "))
|
|
item->date = parse_tag_date(bufptr, tail);
|
|
else
|
|
item->date = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int parse_tag(struct tag *item)
|
|
{
|
|
enum object_type type;
|
|
void *data;
|
|
unsigned long size;
|
|
int ret;
|
|
|
|
if (item->object.parsed)
|
|
return 0;
|
|
data = read_sha1_file(item->object.sha1, &type, &size);
|
|
if (!data)
|
|
return error("Could not read %s",
|
|
sha1_to_hex(item->object.sha1));
|
|
if (type != OBJ_TAG) {
|
|
free(data);
|
|
return error("Object %s not a tag",
|
|
sha1_to_hex(item->object.sha1));
|
|
}
|
|
ret = parse_tag_buffer(item, data, size);
|
|
free(data);
|
|
return ret;
|
|
}
|