Commit cdd9fd47 by Carlos Martín Nieto Committed by Vicent Marti

Allow read_tree_internal to return an error code

There are two reasons why read_tree_internal might return a NULL
tree. The first one is a corrupt index, but the second one is an
invalidated TREE extension. Up to now, its only way to communicate
with its caller was through the return value being NULL or not.

Allow read_tree_internal to report its exit status independently from
the tree pointer.

Signed-off-by: Carlos Martín Nieto <cmn@elego.de>
parent f7e59c4d
......@@ -99,7 +99,7 @@ static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffe
static int read_header(struct index_header *dest, const void *buffer);
static int read_tree(git_index *index, const char *buffer, size_t buffer_size);
static git_index_tree *read_tree_internal(const char **, const char *, git_index_tree *);
static int read_tree_internal(git_index_tree **, const char **, const char *, git_index_tree *);
static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
static int is_index_extended(git_index *index);
......@@ -485,52 +485,72 @@ const git_index_entry_unmerged *git_index_get_unmerged(git_index *index, const c
}
static git_index_tree *read_tree_internal(
static int read_tree_internal(git_index_tree **out,
const char **buffer_in, const char *buffer_end, git_index_tree *parent)
{
git_index_tree *tree;
const char *name_start, *buffer;
long count;
int error = GIT_SUCCESS;
if ((tree = git__malloc(sizeof(git_index_tree))) == NULL)
return NULL;
return GIT_ENOMEM;
memset(tree, 0x0, sizeof(git_index_tree));
tree->parent = parent;
buffer = name_start = *buffer_in;
if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL)
goto error_cleanup;
if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL) {
error = GIT_EOBJCORRUPTED;
goto exit;
}
/* NUL-terminated tree name */
tree->name = git__strdup(name_start);
if (++buffer >= buffer_end)
goto error_cleanup;
if (tree->name == NULL) {
error = GIT_ENOMEM;
goto exit;
}
if (++buffer >= buffer_end) {
error = GIT_EOBJCORRUPTED;
goto exit;
}
/* Blank-terminated ASCII decimal number of entries in this tree */
if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS ||
count < 0)
goto error_cleanup;
count < 0) {
error = GIT_EOBJCORRUPTED;
goto exit;
}
tree->entries = (size_t)count;
if (*buffer != ' ' || ++buffer >= buffer_end)
goto error_cleanup;
if (*buffer != ' ' || ++buffer >= buffer_end) {
error = GIT_EOBJCORRUPTED;
goto exit;
}
/* Number of children of the tree, newline-terminated */
if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS ||
count < 0)
goto error_cleanup;
count < 0) {
error = GIT_EOBJCORRUPTED;
goto exit;
}
tree->children_count = (size_t)count;
if (*buffer != '\n' || ++buffer >= buffer_end)
goto error_cleanup;
if (*buffer != '\n' || ++buffer >= buffer_end) {
error = GIT_EOBJCORRUPTED;
goto exit;
}
/* 160-bit SHA-1 for this tree and it's children */
if (buffer + GIT_OID_RAWSZ > buffer_end)
goto error_cleanup;
if (buffer + GIT_OID_RAWSZ > buffer_end) {
error = GIT_EOBJCORRUPTED;
goto exit;
}
git_oid_mkraw(&tree->oid, (const unsigned char *)buffer);
buffer += GIT_OID_RAWSZ;
......@@ -538,33 +558,38 @@ static git_index_tree *read_tree_internal(
/* Parse children: */
if (tree->children_count > 0) {
unsigned int i;
int err;
tree->children = git__malloc(tree->children_count * sizeof(git_index_tree *));
if (tree->children == NULL)
goto error_cleanup;
goto exit;
for (i = 0; i < tree->children_count; ++i) {
tree->children[i] = read_tree_internal(&buffer, buffer_end, tree);
err = read_tree_internal(&tree->children[i], &buffer, buffer_end, tree);
if (tree->children[i] == NULL)
goto error_cleanup;
if (err < GIT_SUCCESS)
goto exit;
}
}
exit:
*buffer_in = buffer;
return tree;
error_cleanup:
if (error < GIT_SUCCESS) {
free_tree(tree);
return NULL;
} else {
*out = tree;
}
return error;
}
static int read_tree(git_index *index, const char *buffer, size_t buffer_size)
{
const char *buffer_end = buffer + buffer_size;
int error;
error = read_tree_internal(&index->tree, &buffer, buffer_end, NULL);
index->tree = read_tree_internal(&buffer, buffer_end, NULL);
return (index->tree != NULL && buffer == buffer_end) ? GIT_SUCCESS : GIT_EOBJCORRUPTED;
return (error == GIT_SUCCESS && buffer == buffer_end) ? GIT_SUCCESS : GIT_EOBJCORRUPTED;
}
static int read_unmerged(git_index *index, const char *buffer, size_t size)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment