]> git.proxmox.com Git - libgit2.git/blob - src/tree.c
Change include structure for the project
[libgit2.git] / src / tree.c
1 /*
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
5 *
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
14 *
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26 #include "common.h"
27 #include "commit.h"
28 #include "revwalk.h"
29 #include "tree.h"
30 #include "git/repository.h"
31 #include "git/object.h"
32
33 int entry_search_cmp(const void *key, const void *array_member)
34 {
35 const char *filename = (const char *)key;
36 const git_tree_entry *entry = *(const git_tree_entry **)(array_member);
37
38 return strcmp(filename, entry->filename);
39 }
40
41 int entry_sort_cmp(const void *a, const void *b)
42 {
43 const git_tree_entry *entry_a = *(const git_tree_entry **)(a);
44 const git_tree_entry *entry_b = *(const git_tree_entry **)(b);
45
46 return strcmp(entry_a->filename, entry_b->filename);
47 }
48
49 static void free_tree_entries(git_tree *tree)
50 {
51 unsigned int i;
52
53 if (tree == NULL)
54 return;
55
56 for (i = 0; i < tree->entries.length; ++i) {
57 git_tree_entry *e;
58 e = git_vector_get(&tree->entries, i);
59
60 free(e->filename);
61 free(e);
62 }
63
64 git_vector_free(&tree->entries);
65 }
66
67
68
69 void git_tree__free(git_tree *tree)
70 {
71 free_tree_entries(tree);
72 free(tree);
73 }
74
75 const git_oid *git_tree_id(git_tree *c)
76 {
77 return git_object_id((git_object *)c);
78 }
79
80 void git_tree_entry_set_attributes(git_tree_entry *entry, int attr)
81 {
82 assert(entry && entry->owner);
83
84 entry->attr = attr;
85 entry->owner->object.modified = 1;
86 }
87
88 void git_tree_entry_set_name(git_tree_entry *entry, const char *name)
89 {
90 assert(entry && entry->owner);
91
92 free(entry->filename);
93 entry->filename = git__strdup(name);
94 git_vector_sort(&entry->owner->entries);
95 entry->owner->object.modified = 1;
96 }
97
98 void git_tree_entry_set_id(git_tree_entry *entry, const git_oid *oid)
99 {
100 assert(entry && entry->owner);
101
102 git_oid_cpy(&entry->oid, oid);
103 entry->owner->object.modified = 1;
104 }
105
106 unsigned int git_tree_entry_attributes(git_tree_entry *entry)
107 {
108 return entry->attr;
109 }
110
111 const char *git_tree_entry_name(git_tree_entry *entry)
112 {
113 assert(entry);
114 return entry->filename;
115 }
116
117 const git_oid *git_tree_entry_id(git_tree_entry *entry)
118 {
119 assert(entry);
120 return &entry->oid;
121 }
122
123 int git_tree_entry_2object(git_object **object_out, git_tree_entry *entry)
124 {
125 assert(entry && object_out);
126 return git_repository_lookup(object_out, entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY);
127 }
128
129 git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
130 {
131 int idx;
132
133 assert(tree && filename);
134
135 idx = git_vector_search(&tree->entries, filename);
136 if (idx == GIT_ENOTFOUND)
137 return NULL;
138
139 return git_vector_get(&tree->entries, idx);
140 }
141
142 git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx)
143 {
144 assert(tree);
145 return git_vector_get(&tree->entries, (unsigned int)idx);
146 }
147
148 size_t git_tree_entrycount(git_tree *tree)
149 {
150 assert(tree);
151 return tree->entries.length;
152 }
153
154 int git_tree_add_entry(git_tree *tree, const git_oid *id, const char *filename, int attributes)
155 {
156 git_tree_entry *entry;
157
158 assert(tree && id && filename);
159
160 if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL)
161 return GIT_ENOMEM;
162
163 memset(entry, 0x0, sizeof(git_tree_entry));
164
165 entry->filename = git__strdup(filename);
166 git_oid_cpy(&entry->oid, id);
167 entry->attr = attributes;
168 entry->owner = tree;
169
170 if (git_vector_insert(&tree->entries, entry) < 0)
171 return GIT_ENOMEM;
172
173 git_vector_sort(&tree->entries);
174
175 tree->object.modified = 1;
176 return GIT_SUCCESS;
177 }
178
179 int git_tree_remove_entry_byindex(git_tree *tree, int idx)
180 {
181 git_tree_entry *remove_ptr;
182
183 assert(tree);
184
185 remove_ptr = git_vector_get(&tree->entries, (unsigned int)idx);
186 if (remove_ptr == NULL)
187 return GIT_ENOTFOUND;
188
189 free(remove_ptr->filename);
190 free(remove_ptr);
191
192 tree->object.modified = 1;
193
194 return git_vector_remove(&tree->entries, (unsigned int)idx);
195 }
196
197 int git_tree_remove_entry_byname(git_tree *tree, const char *filename)
198 {
199 int idx;
200
201 assert(tree && filename);
202
203 idx = git_vector_search(&tree->entries, filename);
204 if (idx == GIT_ENOTFOUND)
205 return GIT_ENOTFOUND;
206
207 return git_tree_remove_entry_byindex(tree, idx);
208 }
209
210 int git_tree__writeback(git_tree *tree, git_odb_source *src)
211 {
212 size_t i;
213 char filemode[8];
214
215 assert(tree && src);
216
217 if (tree->entries.length == 0)
218 return GIT_EMISSINGOBJDATA;
219
220 git_vector_sort(&tree->entries);
221
222 for (i = 0; i < tree->entries.length; ++i) {
223 git_tree_entry *entry;
224
225 entry = git_vector_get(&tree->entries, i);
226
227 sprintf(filemode, "%06o ", entry->attr);
228
229 git__source_write(src, filemode, strlen(filemode));
230 git__source_write(src, entry->filename, strlen(entry->filename) + 1);
231 git__source_write(src, entry->oid.id, GIT_OID_RAWSZ);
232 }
233
234 return GIT_SUCCESS;
235 }
236
237
238 static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
239 {
240 static const size_t avg_entry_size = 40;
241 unsigned int expected_size;
242 int error = GIT_SUCCESS;
243
244 expected_size = (tree->object.source.raw.len / avg_entry_size) + 1;
245
246 free_tree_entries(tree);
247 if (git_vector_init(&tree->entries, expected_size, entry_sort_cmp, entry_search_cmp) < GIT_SUCCESS)
248 return GIT_ENOMEM;
249
250 while (buffer < buffer_end) {
251 git_tree_entry *entry;
252
253 entry = git__malloc(sizeof(git_tree_entry));
254 if (entry == NULL) {
255 error = GIT_ENOMEM;
256 break;
257 }
258
259 if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)
260 return GIT_ENOMEM;
261
262 entry->owner = tree;
263 entry->attr = strtol(buffer, &buffer, 8);
264
265 if (*buffer++ != ' ') {
266 error = GIT_EOBJCORRUPTED;
267 break;
268 }
269
270 if (memchr(buffer, 0, buffer_end - buffer) == NULL) {
271 error = GIT_EOBJCORRUPTED;
272 break;
273 }
274
275 entry->filename = git__strdup(buffer);
276
277 while (buffer < buffer_end && *buffer != 0)
278 buffer++;
279
280 buffer++;
281
282 git_oid_mkraw(&entry->oid, (const unsigned char *)buffer);
283 buffer += GIT_OID_RAWSZ;
284 }
285
286 return error;
287 }
288
289 int git_tree__parse(git_tree *tree)
290 {
291 char *buffer, *buffer_end;
292
293 assert(tree && tree->object.source.open);
294 assert(!tree->object.in_memory);
295
296 buffer = tree->object.source.raw.data;
297 buffer_end = buffer + tree->object.source.raw.len;
298
299 return tree_parse_buffer(tree, buffer, buffer_end);
300 }
301