]>
Commit | Line | Data |
---|---|---|
225fe215 VM |
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" | |
3315782c | 30 | #include "git/repository.h" |
225fe215 | 31 | |
2a884588 VM |
32 | static void resize_tree_array(git_tree *tree) |
33 | { | |
34 | git_tree_entry **new_entries; | |
35 | ||
36 | tree->array_size = tree->array_size * 2; | |
37 | ||
38 | new_entries = git__malloc(tree->array_size * sizeof(git_tree_entry *)); | |
39 | memcpy(new_entries, tree->entries, tree->entry_count * sizeof(git_tree_entry *)); | |
40 | ||
41 | free(tree->entries); | |
42 | tree->entries = new_entries; | |
43 | } | |
44 | ||
45 | int entry_cmp(const void *key, const void *array_member) | |
46 | { | |
47 | const char *filename = (const char *)key; | |
48 | const git_tree_entry *entry = *(const git_tree_entry **)(array_member); | |
49 | ||
50 | return strcmp(filename, entry->filename); | |
51 | } | |
52 | ||
53 | int entry_sort_cmp(const void *a, const void *b) | |
54 | { | |
55 | const git_tree_entry *entry_a = *(const git_tree_entry **)(a); | |
56 | const git_tree_entry *entry_b = *(const git_tree_entry **)(b); | |
57 | ||
58 | return strcmp(entry_a->filename, entry_b->filename); | |
59 | } | |
60 | ||
61 | static void entry_resort(git_tree *tree) | |
62 | { | |
63 | qsort(tree->entries, tree->entry_count, sizeof(git_tree_entry *), entry_sort_cmp); | |
64 | } | |
65 | ||
66 | ||
67 | ||
68 | ||
225fe215 VM |
69 | void git_tree__free(git_tree *tree) |
70 | { | |
003c2690 VM |
71 | size_t i; |
72 | ||
73 | for (i = 0; i < tree->entry_count; ++i) | |
2a884588 | 74 | free(tree->entries[i]); |
003c2690 VM |
75 | |
76 | free(tree->entries); | |
225fe215 VM |
77 | free(tree); |
78 | } | |
79 | ||
d45b4a9a | 80 | git_tree *git_tree_new(git_repository *repo) |
225fe215 | 81 | { |
d45b4a9a VM |
82 | return (git_tree *)git_object_new(repo, GIT_OBJ_TREE); |
83 | } | |
84 | ||
85 | const git_oid *git_tree_id(git_tree *c) | |
86 | { | |
87 | return git_object_id((git_object *)c); | |
225fe215 VM |
88 | } |
89 | ||
3315782c | 90 | git_tree *git_tree_lookup(git_repository *repo, const git_oid *id) |
225fe215 | 91 | { |
3315782c | 92 | return (git_tree *)git_repository_lookup(repo, id, GIT_OBJ_TREE); |
d8603ed9 VM |
93 | } |
94 | ||
2a884588 | 95 | void git_tree_entry_set_attributes(git_tree_entry *entry, int attr) |
003c2690 | 96 | { |
2a884588 VM |
97 | assert(entry && entry->owner); |
98 | ||
99 | entry->attr = attr; | |
100 | entry->owner->object.modified = 1; | |
003c2690 VM |
101 | } |
102 | ||
2a884588 | 103 | void git_tree_entry_set_name(git_tree_entry *entry, const char *name) |
003c2690 | 104 | { |
2a884588 VM |
105 | assert(entry && entry->owner); |
106 | ||
107 | strncpy(entry->filename, name, GIT_TREE_MAX_FILENAME); | |
108 | entry_resort(entry->owner); | |
109 | entry->owner->object.modified = 1; | |
003c2690 VM |
110 | } |
111 | ||
2a884588 | 112 | void git_tree_entry_set_id(git_tree_entry *entry, const git_oid *oid) |
003c2690 | 113 | { |
2a884588 VM |
114 | assert(entry && entry->owner); |
115 | ||
116 | git_oid_cpy(&entry->oid, oid); | |
117 | entry->owner->object.modified = 1; | |
003c2690 VM |
118 | } |
119 | ||
2a884588 | 120 | unsigned int git_tree_entry_attributes(git_tree_entry *entry) |
003c2690 | 121 | { |
2a884588 | 122 | return entry->attr; |
003c2690 VM |
123 | } |
124 | ||
2a884588 | 125 | const char *git_tree_entry_name(git_tree_entry *entry) |
003c2690 | 126 | { |
c4b5bedc | 127 | assert(entry); |
2a884588 VM |
128 | return entry->filename; |
129 | } | |
003c2690 | 130 | |
2a884588 VM |
131 | const git_oid *git_tree_entry_id(git_tree_entry *entry) |
132 | { | |
c4b5bedc | 133 | assert(entry); |
2a884588 | 134 | return &entry->oid; |
003c2690 VM |
135 | } |
136 | ||
2a884588 | 137 | git_object *git_tree_entry_2object(git_tree_entry *entry) |
003c2690 | 138 | { |
c4b5bedc | 139 | assert(entry); |
2a884588 | 140 | return git_repository_lookup(entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY); |
003c2690 VM |
141 | } |
142 | ||
2a884588 VM |
143 | git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) |
144 | { | |
c4b5bedc VM |
145 | git_tree_entry **found; |
146 | ||
147 | assert(tree && filename); | |
148 | ||
149 | found = bsearch(filename, tree->entries, tree->entry_count, sizeof(git_tree_entry *), entry_cmp); | |
150 | return found ? *found : NULL; | |
2a884588 VM |
151 | } |
152 | ||
153 | git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx) | |
003c2690 | 154 | { |
c4b5bedc VM |
155 | assert(tree); |
156 | ||
003c2690 | 157 | if (tree->entries == NULL) |
f2408cc2 | 158 | return NULL; |
003c2690 | 159 | |
2a884588 | 160 | return (idx >= 0 && idx < (int)tree->entry_count) ? tree->entries[idx] : NULL; |
003c2690 VM |
161 | } |
162 | ||
163 | size_t git_tree_entrycount(git_tree *tree) | |
164 | { | |
c4b5bedc | 165 | assert(tree); |
003c2690 VM |
166 | return tree->entry_count; |
167 | } | |
168 | ||
2a884588 VM |
169 | void git_tree_add_entry(git_tree *tree, const git_oid *id, const char *filename, int attributes) |
170 | { | |
171 | git_tree_entry *entry; | |
172 | ||
c4b5bedc VM |
173 | assert(tree && id && filename); |
174 | ||
2a884588 VM |
175 | if (tree->entry_count >= tree->array_size) |
176 | resize_tree_array(tree); | |
177 | ||
178 | if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL) | |
179 | return; | |
180 | ||
181 | memset(entry, 0x0, sizeof(git_tree_entry)); | |
182 | ||
183 | strncpy(entry->filename, filename, GIT_TREE_MAX_FILENAME); | |
184 | git_oid_cpy(&entry->oid, id); | |
185 | entry->attr = attributes; | |
186 | entry->owner = tree; | |
187 | ||
188 | tree->entries[tree->entry_count++] = entry; | |
189 | entry_resort(tree); | |
190 | ||
191 | tree->object.modified = 1; | |
192 | } | |
193 | ||
194 | int git_tree_remove_entry_byindex(git_tree *tree, int idx) | |
195 | { | |
196 | git_tree_entry *remove_ptr; | |
197 | ||
c4b5bedc VM |
198 | assert(tree); |
199 | ||
2a884588 VM |
200 | if (idx < 0 || idx >= (int)tree->entry_count) |
201 | return GIT_ENOTFOUND; | |
202 | ||
203 | remove_ptr = tree->entries[idx]; | |
204 | tree->entries[idx] = tree->entries[--tree->entry_count]; | |
205 | ||
206 | free(remove_ptr); | |
207 | entry_resort(tree); | |
208 | ||
209 | tree->object.modified = 1; | |
210 | return GIT_SUCCESS; | |
211 | } | |
212 | ||
213 | int git_tree_remove_entry_byname(git_tree *tree, const char *filename) | |
214 | { | |
215 | git_tree_entry **entry_ptr; | |
216 | int idx; | |
217 | ||
c4b5bedc VM |
218 | assert(tree && filename); |
219 | ||
2a884588 VM |
220 | entry_ptr = bsearch(filename, tree->entries, tree->entry_count, sizeof(git_tree_entry *), entry_cmp); |
221 | if (entry_ptr == NULL) | |
222 | return GIT_ENOTFOUND; | |
223 | ||
224 | idx = (int)(entry_ptr - tree->entries); | |
225 | return git_tree_remove_entry_byindex(tree, idx); | |
226 | } | |
227 | ||
228 | int git_tree__writeback(git_tree *tree, git_odb_source *src) | |
229 | { | |
230 | size_t i; | |
231 | ||
c4b5bedc VM |
232 | assert(tree && src); |
233 | ||
2a884588 VM |
234 | if (tree->entries == NULL) |
235 | return GIT_ERROR; | |
236 | ||
237 | entry_resort(tree); | |
238 | ||
239 | for (i = 0; i < tree->entry_count; ++i) { | |
240 | git_tree_entry *entry; | |
241 | entry = tree->entries[i]; | |
242 | ||
243 | git__source_printf(src, "%06o %s\0", entry->attr, entry->filename); | |
244 | git__source_write(src, entry->oid.id, GIT_OID_RAWSZ); | |
245 | } | |
246 | ||
247 | return GIT_SUCCESS; | |
248 | } | |
249 | ||
250 | ||
d8603ed9 VM |
251 | int git_tree__parse(git_tree *tree) |
252 | { | |
003c2690 | 253 | static const size_t avg_entry_size = 40; |
d8603ed9 VM |
254 | |
255 | int error = 0; | |
d8603ed9 | 256 | char *buffer, *buffer_end; |
003c2690 | 257 | |
2a884588 VM |
258 | assert(!tree->object.in_memory); |
259 | ||
260 | if (tree->entries != NULL) { | |
261 | size_t i; | |
262 | ||
263 | for (i = 0; i < tree->entry_count; ++i) | |
264 | free(tree->entries[i]); | |
265 | ||
266 | free(tree->entries); | |
267 | } | |
d8603ed9 | 268 | |
f49a2e49 | 269 | error = git_object__source_open((git_object *)tree); |
d8603ed9 VM |
270 | if (error < 0) |
271 | return error; | |
272 | ||
f49a2e49 VM |
273 | buffer = tree->object.source.raw.data; |
274 | buffer_end = buffer + tree->object.source.raw.len; | |
d8603ed9 | 275 | |
003c2690 | 276 | tree->entry_count = 0; |
2a884588 VM |
277 | tree->array_size = (tree->object.source.raw.len / avg_entry_size) + 1; |
278 | tree->entries = git__malloc(tree->array_size * sizeof(git_tree_entry *)); | |
d8603ed9 | 279 | |
003c2690 VM |
280 | while (buffer < buffer_end) { |
281 | git_tree_entry *entry; | |
d8603ed9 | 282 | |
2a884588 VM |
283 | if (tree->entry_count >= tree->array_size) |
284 | resize_tree_array(tree); | |
d8603ed9 | 285 | |
2a884588 VM |
286 | entry = git__malloc(sizeof(git_tree_entry)); |
287 | if (entry == NULL) { | |
288 | error = GIT_ENOMEM; | |
289 | break; | |
003c2690 | 290 | } |
d8603ed9 | 291 | |
2a884588 | 292 | tree->entries[tree->entry_count++] = entry; |
003c2690 | 293 | |
2a884588 | 294 | entry->owner = tree; |
003c2690 | 295 | entry->attr = strtol(buffer, &buffer, 8); |
d8603ed9 VM |
296 | |
297 | if (*buffer++ != ' ') { | |
298 | error = GIT_EOBJCORRUPTED; | |
299 | break; | |
300 | } | |
301 | ||
2a884588 | 302 | strncpy(entry->filename, buffer, GIT_TREE_MAX_FILENAME); |
d8603ed9 | 303 | |
2a884588 VM |
304 | while (buffer < buffer_end && *buffer != 0) |
305 | buffer++; | |
003c2690 | 306 | |
2a884588 | 307 | buffer++; |
d8603ed9 VM |
308 | |
309 | git_oid_mkraw(&entry->oid, (const unsigned char *)buffer); | |
310 | buffer += GIT_OID_RAWSZ; | |
d8603ed9 VM |
311 | } |
312 | ||
f49a2e49 | 313 | git_object__source_close((git_object *)tree); |
d8603ed9 VM |
314 | return error; |
315 | } |