]> git.proxmox.com Git - libgit2.git/blame - src/tree.c
Make reinitializing a repository return GIT_ENOTIMPLEMENTED instead of GIT_SUCCESS
[libgit2.git] / src / tree.c
CommitLineData
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"
225fe215 28#include "tree.h"
44908fe7
VM
29#include "git2/repository.h"
30#include "git2/object.h"
225fe215 31
c8f5ff8f 32#define DEFAULT_TREE_SIZE 16
9de27ad0
SJ
33#define MAX_FILEMODE 0777777
34#define MAX_FILEMODE_BYTES 6
c8f5ff8f 35
c4034e63 36int entry_search_cmp(const void *key, const void *array_member)
2a884588
VM
37{
38 const char *filename = (const char *)key;
39 const git_tree_entry *entry = *(const git_tree_entry **)(array_member);
40
41 return strcmp(filename, entry->filename);
42}
43
72a3fe42 44#if 0
9de27ad0
SJ
45static int valid_attributes(const int attributes) {
46 return attributes >= 0 && attributes <= MAX_FILEMODE;
47}
72a3fe42 48#endif
9de27ad0 49
2a884588
VM
50int entry_sort_cmp(const void *a, const void *b)
51{
52 const git_tree_entry *entry_a = *(const git_tree_entry **)(a);
53 const git_tree_entry *entry_b = *(const git_tree_entry **)(b);
54
ccef1c9d 55 return gitfo_cmp_path(entry_a->filename, strlen(entry_a->filename),
35786cb7
JW
56 entry_a->attr & 040000,
57 entry_b->filename, strlen(entry_b->filename),
58 entry_b->attr & 040000);
2a884588
VM
59}
60
72a3fe42 61void git_tree__free(git_tree *tree)
225fe215 62{
c4034e63 63 unsigned int i;
003c2690 64
c4034e63
VM
65 for (i = 0; i < tree->entries.length; ++i) {
66 git_tree_entry *e;
67 e = git_vector_get(&tree->entries, i);
68
69 free(e->filename);
70 free(e);
58519018 71 }
003c2690 72
c8f5ff8f 73 git_vector_free(&tree->entries);
225fe215
VM
74 free(tree);
75}
76
d45b4a9a
VM
77const git_oid *git_tree_id(git_tree *c)
78{
79 return git_object_id((git_object *)c);
225fe215
VM
80}
81
2a884588 82unsigned int git_tree_entry_attributes(git_tree_entry *entry)
003c2690 83{
2a884588 84 return entry->attr;
003c2690
VM
85}
86
2a884588 87const char *git_tree_entry_name(git_tree_entry *entry)
003c2690 88{
c4b5bedc 89 assert(entry);
2a884588
VM
90 return entry->filename;
91}
003c2690 92
2a884588
VM
93const git_oid *git_tree_entry_id(git_tree_entry *entry)
94{
c4b5bedc 95 assert(entry);
2a884588 96 return &entry->oid;
003c2690
VM
97}
98
72a3fe42 99int git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry)
003c2690 100{
1795f879 101 assert(entry && object_out);
72a3fe42 102 return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY);
122c3405
VM
103}
104
2a884588
VM
105git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
106{
c4034e63 107 int idx;
c4b5bedc
VM
108
109 assert(tree && filename);
110
86d7e1ca 111 idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);
c4034e63
VM
112 if (idx == GIT_ENOTFOUND)
113 return NULL;
114
115 return git_vector_get(&tree->entries, idx);
2a884588
VM
116}
117
118git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx)
003c2690 119{
c4b5bedc 120 assert(tree);
c4034e63 121 return git_vector_get(&tree->entries, (unsigned int)idx);
003c2690
VM
122}
123
124size_t git_tree_entrycount(git_tree *tree)
125{
c4b5bedc 126 assert(tree);
c4034e63 127 return tree->entries.length;
003c2690
VM
128}
129
720d5472 130static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buffer_end)
d8603ed9 131{
6f02c3ba 132 int error = GIT_SUCCESS;
2a884588 133
72a3fe42
VM
134 if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS)
135 return GIT_ENOMEM;
e4def81a 136
003c2690
VM
137 while (buffer < buffer_end) {
138 git_tree_entry *entry;
d8603ed9 139
29e1789b 140 entry = git__calloc(1, sizeof(git_tree_entry));
2a884588
VM
141 if (entry == NULL) {
142 error = GIT_ENOMEM;
143 break;
003c2690 144 }
d8603ed9 145
6f02c3ba 146 if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)
c4034e63 147 return GIT_ENOMEM;
003c2690 148
720d5472 149 entry->attr = strtol(buffer, (char **)&buffer, 8);
d8603ed9
VM
150
151 if (*buffer++ != ' ') {
152 error = GIT_EOBJCORRUPTED;
153 break;
154 }
155
58519018
VM
156 if (memchr(buffer, 0, buffer_end - buffer) == NULL) {
157 error = GIT_EOBJCORRUPTED;
158 break;
159 }
160
161 entry->filename = git__strdup(buffer);
d8603ed9 162
2a884588
VM
163 while (buffer < buffer_end && *buffer != 0)
164 buffer++;
003c2690 165
2a884588 166 buffer++;
d8603ed9
VM
167
168 git_oid_mkraw(&entry->oid, (const unsigned char *)buffer);
169 buffer += GIT_OID_RAWSZ;
d8603ed9
VM
170 }
171
172 return error;
173}
58519018 174
72a3fe42 175int git_tree__parse(git_tree *tree, git_odb_object *obj)
58519018 176{
72a3fe42
VM
177 assert(tree);
178 return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len);
58519018
VM
179}
180
29e1789b 181static int write_entry(char *buffer, int mode, const char *path, size_t path_len, const git_oid *oid)
47d8ec56 182{
29e1789b
VM
183 int written;
184 written = sprintf(buffer, "%o %.*s%c", mode, (int)path_len, path, 0);
185 memcpy(buffer + written, &oid->id, GIT_OID_RAWSZ);
186 return written + GIT_OID_RAWSZ;
187}
188
189static int write_index(git_oid *oid, git_index *index, const char *base, int baselen, int entry_no, int maxentries)
190{
191 size_t size, offset;
47d8ec56 192 char *buffer;
29e1789b
VM
193 int nr, error;
194
47d8ec56 195 /* Guess at some random initial size */
29e1789b 196 size = maxentries * 40;
47d8ec56
SL
197 buffer = git__malloc(size);
198 if (buffer == NULL)
199 return GIT_ENOMEM;
200
201 offset = 0;
47d8ec56 202
29e1789b 203 for (nr = entry_no; nr < maxentries; ++nr) {
47d8ec56 204 git_index_entry *entry = git_index_get(index, nr);
29e1789b 205
47d8ec56
SL
206 const char *pathname = entry->path, *filename, *dirname;
207 int pathlen = strlen(pathname), entrylen;
29e1789b
VM
208
209 unsigned int write_mode;
210 git_oid subtree_oid;
211 git_oid *write_oid;
47d8ec56
SL
212
213 /* Did we hit the end of the directory? Return how many we wrote */
29e1789b 214 if (baselen >= pathlen || memcmp(base, pathname, baselen) != 0)
47d8ec56
SL
215 break;
216
47d8ec56
SL
217 /* Do we have _further_ subdirectories? */
218 filename = pathname + baselen;
219 dirname = strchr(filename, '/');
29e1789b
VM
220
221 write_oid = &entry->oid;
222 write_mode = entry->mode;
223
47d8ec56
SL
224 if (dirname) {
225 int subdir_written;
29e1789b
VM
226
227#if 0
228 if (entry->mode != S_IFDIR) {
229 free(buffer);
230 return GIT_EOBJCORRUPTED;
231 }
232#endif
233 subdir_written = write_index(&subtree_oid, index, pathname, dirname - pathname + 1, nr, maxentries);
234
235 if (subdir_written < GIT_SUCCESS) {
236 free(buffer);
237 return subdir_written;
238 }
47d8ec56 239
29e1789b 240 nr = subdir_written - 1;
47d8ec56
SL
241
242 /* Now we need to write out the directory entry into this tree.. */
47d8ec56 243 pathlen = dirname - pathname;
29e1789b
VM
244 write_oid = &subtree_oid;
245 write_mode = S_IFDIR;
47d8ec56 246 }
29e1789b 247
47d8ec56 248 entrylen = pathlen - baselen;
29e1789b
VM
249 if (offset + entrylen + 32 > size) {
250 size = alloc_nr(offset + entrylen + 32);
47d8ec56
SL
251 buffer = git__realloc(buffer, size);
252
253 if (buffer == NULL)
254 return GIT_ENOMEM;
255 }
29e1789b
VM
256
257 offset += write_entry(buffer + offset, write_mode, filename, entrylen, write_oid);
258 }
47d8ec56 259
29e1789b
VM
260 error = git_odb_write(oid, index->repository->db, buffer, offset, GIT_OBJ_TREE);
261 free(buffer);
262
263 return (error == GIT_SUCCESS) ? nr : error;
264}
265
266int git_tree_create_fromindex(git_oid *oid, git_index *index)
267{
268 int error;
269
270 if (index->repository == NULL)
271 return GIT_EBAREINDEX;
47d8ec56 272
29e1789b
VM
273 error = write_index(oid, index, "", 0, 0, git_index_entrycount(index));
274 return (error < GIT_SUCCESS) ? error : GIT_SUCCESS;
47d8ec56 275}