]> git.proxmox.com Git - libgit2.git/blame - src/tree-cache.c
Update Copyright header
[libgit2.git] / src / tree-cache.c
CommitLineData
b4171320 1/*
5e0de328 2 * Copyright (C) 2009-2012 the libgit2 contributors
b4171320
CMN
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8#include "tree-cache.h"
9
3ba69ba8 10static git_tree_cache *find_child(const git_tree_cache *tree, const char *path)
69bffab9
CMN
11{
12 size_t i, dirlen;
13 const char *end;
14
15 end = strchr(path, '/');
16 if (end == NULL) {
17 end = strrchr(path, '\0');
18 }
19
20 dirlen = end - path;
21
22 for (i = 0; i < tree->children_count; ++i) {
23 const char *childname = tree->children[i]->name;
24
25 if (strlen(childname) == dirlen && !memcmp(path, childname, dirlen))
26 return tree->children[i];
27 }
28
29 return NULL;
30}
31
32void git_tree_cache_invalidate_path(git_tree_cache *tree, const char *path)
33{
34 const char *ptr = path, *end;
35
36 if (tree == NULL)
37 return;
38
39 tree->entries = -1;
40
41 while (ptr != NULL) {
42 end = strchr(ptr, '/');
43
44 if (end == NULL) /* End of path */
45 break;
46
47 tree = find_child(tree, ptr);
48 if (tree == NULL) /* We don't have that tree */
49 return;
50
51 tree->entries = -1;
52 ptr = end + 1;
53 }
54}
55
3ba69ba8
CMN
56const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char *path)
57{
58 const char *ptr = path, *end;
59
60 if (tree == NULL) {
61 return NULL;
62 }
63
64 while (1) {
65 end = strchr(ptr, '/');
66
67 tree = find_child(tree, ptr);
68 if (tree == NULL) { /* Can't find it */
69 return NULL;
70 }
71
72 if (end == NULL || end + 1 == '\0')
73 return tree;
74
75 ptr = end + 1;
76 }
77}
78
b4171320
CMN
79static int read_tree_internal(git_tree_cache **out,
80 const char **buffer_in, const char *buffer_end, git_tree_cache *parent)
81{
69bffab9 82 git_tree_cache *tree = NULL;
b4171320
CMN
83 const char *name_start, *buffer;
84 int count;
85 int error = GIT_SUCCESS;
b183ffe7 86 size_t name_len;
b4171320
CMN
87
88 buffer = name_start = *buffer_in;
89
90 if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL) {
91 error = GIT_EOBJCORRUPTED;
92 goto cleanup;
93 }
94
b4171320
CMN
95 if (++buffer >= buffer_end) {
96 error = GIT_EOBJCORRUPTED;
97 goto cleanup;
98 }
99
b183ffe7
CMN
100 name_len = strlen(name_start);
101 if ((tree = git__malloc(sizeof(git_tree_cache) + name_len + 1)) == NULL)
102 return GIT_ENOMEM;
103
104 memset(tree, 0x0, sizeof(git_tree_cache));
105 tree->parent = parent;
106
107 /* NUL-terminated tree name */
108 memcpy(tree->name, name_start, name_len);
109 tree->name[name_len] = '\0';
110
b4171320
CMN
111 /* Blank-terminated ASCII decimal number of entries in this tree */
112 if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS || count < -1) {
113 error = GIT_EOBJCORRUPTED;
114 goto cleanup;
115 }
116
b4171320
CMN
117 tree->entries = count;
118
119 if (*buffer != ' ' || ++buffer >= buffer_end) {
120 error = GIT_EOBJCORRUPTED;
121 goto cleanup;
122 }
123
124 /* Number of children of the tree, newline-terminated */
125 if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS ||
126 count < 0) {
127 error = GIT_EOBJCORRUPTED;
128 goto cleanup;
129 }
130
131 tree->children_count = count;
132
133 if (*buffer != '\n' || ++buffer >= buffer_end) {
134 error = GIT_EOBJCORRUPTED;
135 goto cleanup;
136 }
137
acd31b4a
CMN
138 /* The SHA1 is only there if it's not invalidated */
139 if (tree->entries >= 0) {
140 /* 160-bit SHA-1 for this tree and it's children */
141 if (buffer + GIT_OID_RAWSZ > buffer_end) {
142 error = GIT_EOBJCORRUPTED;
143 goto cleanup;
144 }
b4171320 145
acd31b4a
CMN
146 git_oid_fromraw(&tree->oid, (const unsigned char *)buffer);
147 buffer += GIT_OID_RAWSZ;
148 }
b4171320
CMN
149
150 /* Parse children: */
151 if (tree->children_count > 0) {
152 unsigned int i;
153 int err;
154
155 tree->children = git__malloc(tree->children_count * sizeof(git_tree_cache *));
156 if (tree->children == NULL)
157 goto cleanup;
158
159 for (i = 0; i < tree->children_count; ++i) {
160 err = read_tree_internal(&tree->children[i], &buffer, buffer_end, tree);
161
162 if (err < GIT_SUCCESS)
163 goto cleanup;
164 }
165 }
166
167 *buffer_in = buffer;
168 *out = tree;
169 return GIT_SUCCESS;
170
171 cleanup:
172 git_tree_cache_free(tree);
173 return error;
174}
175
176int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size)
177{
178 const char *buffer_end = buffer + buffer_size;
179 int error;
180
181 error = read_tree_internal(tree, &buffer, buffer_end, NULL);
182
183 if (buffer < buffer_end)
184 return GIT_EOBJCORRUPTED;
185
186 return error;
187}
188
189void git_tree_cache_free(git_tree_cache *tree)
190{
191 unsigned int i;
192
193 if (tree == NULL)
194 return;
195
196 for (i = 0; i < tree->children_count; ++i)
197 git_tree_cache_free(tree->children[i]);
198
3286c408
VM
199 git__free(tree->children);
200 git__free(tree);
b4171320 201}