Skip to content

Commit f2408cc

Browse files
author
Vicent Marti
committed
Fix object handling in git_repository
All loaded objects through git_repository_lookup are properly parsed & free'd on failure. Signed-off-by: Vicent Marti <tanoku@gmail.com>
1 parent 0e465f9 commit f2408cc

File tree

6 files changed

+98
-75
lines changed

6 files changed

+98
-75
lines changed

src/commit.c

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,6 @@ void git_commit__free(git_commit *commit)
5353
{
5454
clear_parents(commit);
5555

56-
if (commit->odb_open)
57-
git_obj_close(&commit->odb_object);
58-
5956
free(commit->author);
6057
free(commit->committer);
6158
free(commit->message);
@@ -72,26 +69,14 @@ int git_commit__parse(git_commit *commit, unsigned int parse_flags, int close_db
7269
{
7370
int error = 0;
7471

75-
if (!commit->odb_open) {
76-
error = git_odb_read(&commit->odb_object, commit->object.repo->db, &commit->object.id);
77-
if (error < 0)
78-
return error;
79-
80-
if (commit->odb_object.type != GIT_OBJ_COMMIT) {
81-
git_obj_close(&commit->odb_object);
82-
return GIT_EOBJTYPE;
83-
}
84-
85-
commit->odb_open = 1;
86-
}
72+
if ((error = git_repository__open_dbo((git_repository_object *)commit)) < 0)
73+
return error;
8774

8875
error = git_commit__parse_buffer(commit,
89-
commit->odb_object.data, commit->odb_object.len, parse_flags);
76+
commit->object.dbo.data, commit->object.dbo.len, parse_flags);
9077

91-
if (close_db_object) {
92-
git_obj_close(&commit->odb_object);
93-
commit->odb_open = 0;
94-
}
78+
if (close_db_object)
79+
git_repository__close_dbo((git_repository_object *)commit);
9580

9681
return error;
9782
}

src/commit.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ typedef struct git_commit_parents {
2323

2424
struct git_commit {
2525
git_repository_object object;
26-
git_obj odb_object;
2726

2827
time_t commit_time;
2928
git_commit_parents *parents;

src/repository.c

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,10 @@ void git_repository_free(git_repository *repo)
8484

8585
while ((object = (git_repository_object *)
8686
git_hashtable_iterator_next(&it)) != NULL) {
87+
88+
git_obj_close(&object->dbo);
8789

88-
switch (object->type) {
90+
switch (object->dbo.type) {
8991
case GIT_OBJ_COMMIT:
9092
git_commit__free((git_commit *)object);
9193
break;
@@ -109,8 +111,39 @@ void git_repository_free(git_repository *repo)
109111
free(repo);
110112
}
111113

114+
int git_repository__open_dbo(git_repository_object *object)
115+
{
116+
int error;
117+
118+
if (object->dbo_open)
119+
return GIT_SUCCESS;
120+
121+
error = git_odb_read(&object->dbo, object->repo->db, &object->id);
122+
if (error < 0)
123+
return error;
124+
125+
object->dbo_open = 1;
126+
return GIT_SUCCESS;
127+
}
128+
129+
void git_repository__close_dbo(git_repository_object *object)
130+
{
131+
if (!object->dbo_open) {
132+
git_obj_close(&object->dbo);
133+
object->dbo_open = 0;
134+
}
135+
}
136+
112137
git_repository_object *git_repository_lookup(git_repository *repo, const git_oid *id, git_otype type)
113138
{
139+
static const size_t object_sizes[] = {
140+
0,
141+
sizeof(git_commit),
142+
sizeof(git_tree),
143+
sizeof(git_repository_object), /* TODO: sizeof(git_blob) */
144+
sizeof(git_tag)
145+
};
146+
114147
git_repository_object *object = NULL;
115148
git_obj obj_file;
116149

@@ -120,24 +153,61 @@ git_repository_object *git_repository_lookup(git_repository *repo, const git_oid
120153
if (object != NULL)
121154
return object;
122155

123-
if (git_odb_read(&obj_file, repo->db, id) < 0 ||
124-
(type != GIT_OBJ_ANY && type != obj_file.type))
156+
if (git_odb_read(&obj_file, repo->db, id) < 0)
125157
return NULL;
126158

127-
object = git__malloc(sizeof(git_commit));
159+
if (type != GIT_OBJ_ANY && type != obj_file.type)
160+
return NULL;
161+
162+
type = obj_file.type;
163+
164+
object = git__malloc(object_sizes[type]);
128165

129166
if (object == NULL)
130167
return NULL;
131168

132-
memset(object, 0x0, sizeof(git_commit));
169+
memset(object, 0x0, object_sizes[type]);
133170

134171
/* Initialize parent object */
135172
git_oid_cpy(&object->id, id);
136173
object->repo = repo;
137-
object->type = obj_file.type;
174+
object->dbo_open = 1;
175+
memcpy(&object->dbo, &obj_file, sizeof(git_obj));
138176

139-
git_hashtable_insert(repo->objects, &object->id, object);
140-
git_obj_close(&obj_file);
177+
switch (type) {
141178

179+
case GIT_OBJ_COMMIT:
180+
if (git_commit__parse_basic((git_commit *)object) < 0) {
181+
free(object);
182+
return NULL;
183+
}
184+
185+
break;
186+
187+
case GIT_OBJ_TREE:
188+
if (git_tree__parse((git_tree *)object) < 0) {
189+
free(object);
190+
return NULL;
191+
}
192+
193+
break;
194+
195+
case GIT_OBJ_TAG:
196+
if (git_tag__parse((git_tag *)object) < 0) {
197+
free(object);
198+
return NULL;
199+
}
200+
201+
break;
202+
203+
default:
204+
/* blobs get no parsing */
205+
break;
206+
}
207+
208+
git_obj_close(&object->dbo);
209+
object->dbo_open = 0;
210+
211+
git_hashtable_insert(repo->objects, &object->id, object);
142212
return object;
143213
}

src/repository.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@
1111
struct git_repository_object {
1212
git_oid id;
1313
git_repository *repo;
14-
git_otype type;
14+
git_obj dbo;
15+
int dbo_open;
1516
};
1617

1718
struct git_repository {
1819
git_odb *db;
1920
git_hashtable *objects;
2021
};
2122

22-
int git_repository__insert(git_repository *repo, git_repository_object *obj);
23-
git_repository_object *git_repository__lookup(git_repository *repo, const git_oid *id);
23+
24+
int git_repository__open_dbo(git_repository_object *object);
25+
void git_repository__close_dbo(git_repository_object *object);
2426

2527
#endif

src/tag.c

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -45,47 +45,26 @@ const git_oid *git_tag_id(git_tag *t)
4545

4646
const git_repository_object *git_tag_target(git_tag *t)
4747
{
48-
if (t->target)
49-
return t->target;
50-
51-
git_tag__parse(t);
5248
return t->target;
5349
}
5450

5551
git_otype git_tag_type(git_tag *t)
5652
{
57-
if (t->type)
58-
return t->type;
59-
60-
git_tag__parse(t);
6153
return t->type;
6254
}
6355

64-
6556
const char *git_tag_name(git_tag *t)
6657
{
67-
if (t->tag_name)
68-
return t->tag_name;
69-
70-
git_tag__parse(t);
7158
return t->tag_name;
7259
}
7360

7461
const git_person *git_tag_tagger(git_tag *t)
7562
{
76-
if (t->tagger)
77-
return t->tagger;
78-
79-
git_tag__parse(t);
8063
return t->tagger;
8164
}
8265

8366
const char *git_tag_message(git_tag *t)
8467
{
85-
if (t->message)
86-
return t->message;
87-
88-
git_tag__parse(t);
8968
return t->message;
9069
}
9170

@@ -181,21 +160,14 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
181160
int git_tag__parse(git_tag *tag)
182161
{
183162
int error = 0;
184-
git_obj odb_object;
185163

186-
error = git_odb_read(&odb_object, tag->object.repo->db, &tag->object.id);
164+
error = git_repository__open_dbo((git_repository_object *)tag);
187165
if (error < 0)
188166
return error;
189167

190-
if (odb_object.type != GIT_OBJ_TAG) {
191-
error = GIT_EOBJTYPE;
192-
goto cleanup;
193-
}
194-
195-
error = parse_tag_buffer(tag, odb_object.data, odb_object.data + odb_object.len);
168+
error = parse_tag_buffer(tag, tag->object.dbo.data, tag->object.dbo.data + tag->object.dbo.len);
196169

197-
cleanup:
198-
git_obj_close(&odb_object);
170+
git_repository__close_dbo((git_repository_object *)tag);
199171
return error;
200172
}
201173

src/tree.c

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,15 @@ int entry_cmp(const void *key, const void *array_member)
8080

8181
const git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
8282
{
83-
if (tree->entries == NULL)
84-
git_tree__parse(tree);
85-
8683
return bsearch(filename, tree->entries, tree->entry_count, sizeof(git_tree_entry), entry_cmp);
8784
}
8885

8986
const git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx)
9087
{
9188
if (tree->entries == NULL)
92-
git_tree__parse(tree);
89+
return NULL;
9390

94-
return (tree->entries && idx >= 0 && idx < (int)tree->entry_count) ?
95-
&tree->entries[idx] : NULL;
91+
return (idx >= 0 && idx < (int)tree->entry_count) ? &tree->entries[idx] : NULL;
9692
}
9793

9894
size_t git_tree_entrycount(git_tree *tree)
@@ -105,22 +101,21 @@ int git_tree__parse(git_tree *tree)
105101
static const size_t avg_entry_size = 40;
106102

107103
int error = 0;
108-
git_obj odb_object;
109104
char *buffer, *buffer_end;
110105
size_t entries_size;
111106

112107
if (tree->entries != NULL)
113108
return GIT_SUCCESS;
114109

115-
error = git_odb_read(&odb_object, tree->object.repo->db, &tree->object.id);
110+
error = git_repository__open_dbo((git_repository_object *)tree);
116111
if (error < 0)
117112
return error;
118113

119-
buffer = odb_object.data;
120-
buffer_end = odb_object.data + odb_object.len;
114+
buffer = tree->object.dbo.data;
115+
buffer_end = buffer + tree->object.dbo.len;
121116

122117
tree->entry_count = 0;
123-
entries_size = (odb_object.len / avg_entry_size) + 1;
118+
entries_size = (tree->object.dbo.len / avg_entry_size) + 1;
124119
tree->entries = git__malloc(entries_size * sizeof(git_tree_entry));
125120

126121
while (buffer < buffer_end) {
@@ -160,6 +155,6 @@ int git_tree__parse(git_tree *tree)
160155
buffer += GIT_OID_RAWSZ;
161156
}
162157

163-
git_obj_close(&odb_object);
158+
git_repository__close_dbo((git_repository_object *)tree);
164159
return error;
165160
}

0 commit comments

Comments
 (0)