]> git.ipfire.org Git - thirdparty/git.git/blame - cache-tree.c
Add test-dump-cache-tree
[thirdparty/git.git] / cache-tree.c
CommitLineData
74986462
JH
1#include "cache.h"
2#include "tree.h"
3#include "cache-tree.h"
4
5#define DEBUG 0
6
7struct cache_tree *cache_tree(void)
8{
9 struct cache_tree *it = xcalloc(1, sizeof(struct cache_tree));
10 it->entry_count = -1;
11 return it;
12}
13
14void cache_tree_free(struct cache_tree *it)
15{
16 int i;
17
18 if (!it)
19 return;
20 for (i = 0; i < it->subtree_nr; i++)
21 cache_tree_free(it->down[i]->cache_tree);
22 free(it->down);
23 free(it);
24}
25
26static struct cache_tree_sub *find_subtree(struct cache_tree *it,
27 const char *path,
28 int pathlen,
29 int create)
30{
31 int i;
32 struct cache_tree_sub *down;
33 for (i = 0; i < it->subtree_nr; i++) {
34 down = it->down[i];
35 if (down->namelen == pathlen &&
36 !memcmp(down->name, path, pathlen))
37 return down;
38 }
39 if (!create)
40 return NULL;
41 if (it->subtree_alloc <= it->subtree_nr) {
42 it->subtree_alloc = alloc_nr(it->subtree_alloc);
43 it->down = xrealloc(it->down, it->subtree_alloc *
44 sizeof(*it->down));
45 }
46 down = xmalloc(sizeof(*down) + pathlen + 1);
47 down->cache_tree = NULL; /* cache_tree(); */
48 down->namelen = pathlen;
49 memcpy(down->name, path, pathlen);
50 down->name[pathlen] = 0; /* not strictly needed */
51 it->down[it->subtree_nr++] = down;
52 return down;
53}
54
55void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
56{
57 /* a/b/c
58 * ==> invalidate self
59 * ==> find "a", have it invalidate "b/c"
60 * a
61 * ==> invalidate self
62 * ==> if "a" exists as a subtree, remove it.
63 */
64 const char *slash;
65 int namelen;
66 struct cache_tree_sub *down;
67
68 if (!it)
69 return;
70 slash = strchr(path, '/');
71 it->entry_count = -1;
72 if (!slash) {
73 int i;
74 namelen = strlen(path);
75 for (i = 0; i < it->subtree_nr; i++) {
76 if (it->down[i]->namelen == namelen &&
77 !memcmp(it->down[i]->name, path, namelen))
78 break;
79 }
80 if (i < it->subtree_nr) {
81 cache_tree_free(it->down[i]->cache_tree);
82 free(it->down[i]);
83 /* 0 1 2 3 4 5
84 * ^ ^subtree_nr = 6
85 * i
86 * move 4 and 5 up one place (2 entries)
87 * 2 = 6 - 3 - 1 = subtree_nr - i - 1
88 */
89 memmove(it->down+i, it->down+i+1,
90 sizeof(struct cache_tree_sub *) *
91 (it->subtree_nr - i - 1));
92 it->subtree_nr--;
93 }
94 return;
95 }
96 namelen = slash - path;
97 down = find_subtree(it, path, namelen, 0);
98 if (down)
99 cache_tree_invalidate_path(down->cache_tree, slash + 1);
100}
101
102static int verify_cache(struct cache_entry **cache,
103 int entries)
104{
105 int i, funny;
106
107 /* Verify that the tree is merged */
108 funny = 0;
109 for (i = 0; i < entries; i++) {
110 struct cache_entry *ce = cache[i];
111 if (ce_stage(ce)) {
112 if (10 < ++funny) {
113 fprintf(stderr, "...\n");
114 break;
115 }
116 fprintf(stderr, "%s: unmerged (%s)\n",
117 ce->name, sha1_to_hex(ce->sha1));
118 }
119 }
120 if (funny)
121 return -1;
122
123 /* Also verify that the cache does not have path and path/file
124 * at the same time. At this point we know the cache has only
125 * stage 0 entries.
126 */
127 funny = 0;
128 for (i = 0; i < entries - 1; i++) {
129 /* path/file always comes after path because of the way
130 * the cache is sorted. Also path can appear only once,
131 * which means conflicting one would immediately follow.
132 */
133 const char *this_name = cache[i]->name;
134 const char *next_name = cache[i+1]->name;
135 int this_len = strlen(this_name);
136 if (this_len < strlen(next_name) &&
137 strncmp(this_name, next_name, this_len) == 0 &&
138 next_name[this_len] == '/') {
139 if (10 < ++funny) {
140 fprintf(stderr, "...\n");
141 break;
142 }
143 fprintf(stderr, "You have both %s and %s\n",
144 this_name, next_name);
145 }
146 }
147 if (funny)
148 return -1;
149 return 0;
150}
151
152static void discard_unused_subtrees(struct cache_tree *it)
153{
154 struct cache_tree_sub **down = it->down;
155 int nr = it->subtree_nr;
156 int dst, src;
157 for (dst = src = 0; src < nr; src++) {
158 struct cache_tree_sub *s = down[src];
159 if (s->used)
160 down[dst++] = s;
161 else {
162 cache_tree_free(s->cache_tree);
163 free(s);
164 it->subtree_nr--;
165 }
166 }
167}
168
169static int update_one(struct cache_tree *it,
170 struct cache_entry **cache,
171 int entries,
172 const char *base,
173 int baselen,
174 int missing_ok)
175{
176 unsigned long size, offset;
177 char *buffer;
178 int i;
179
180 if (0 <= it->entry_count)
181 return it->entry_count;
182
183 /*
184 * We first scan for subtrees and update them; we start by
185 * marking existing subtrees -- the ones that are unmarked
186 * should not be in the result.
187 */
188 for (i = 0; i < it->subtree_nr; i++)
189 it->down[i]->used = 0;
190
191 /*
192 * Find the subtrees and update them.
193 */
194 for (i = 0; i < entries; i++) {
195 struct cache_entry *ce = cache[i];
196 struct cache_tree_sub *sub;
197 const char *path, *slash;
198 int pathlen, sublen, subcnt;
199
200 path = ce->name;
201 pathlen = ce_namelen(ce);
202 if (pathlen <= baselen || memcmp(base, path, baselen))
203 break; /* at the end of this level */
204
205 slash = strchr(path + baselen, '/');
206 if (!slash)
207 continue;
208 /*
209 * a/bbb/c (base = a/, slash = /c)
210 * ==>
211 * path+baselen = bbb/c, sublen = 3
212 */
213 sublen = slash - (path + baselen);
214 sub = find_subtree(it, path + baselen, sublen, 1);
215 if (!sub->cache_tree)
216 sub->cache_tree = cache_tree();
217 subcnt = update_one(sub->cache_tree,
218 cache + i, entries - i,
219 path,
220 baselen + sublen + 1,
221 missing_ok);
222 i += subcnt - 1;
223 sub->used = 1;
224 }
225
226 discard_unused_subtrees(it);
227
228 /*
229 * Then write out the tree object for this level.
230 */
231 size = 8192;
232 buffer = xmalloc(size);
233 offset = 0;
234
235 for (i = 0; i < entries; i++) {
236 struct cache_entry *ce = cache[i];
237 struct cache_tree_sub *sub;
238 const char *path, *slash;
239 int pathlen, entlen;
240 const unsigned char *sha1;
241 unsigned mode;
242
243 path = ce->name;
244 pathlen = ce_namelen(ce);
245 if (pathlen <= baselen || memcmp(base, path, baselen))
246 break; /* at the end of this level */
247
248 slash = strchr(path + baselen, '/');
249 if (slash) {
250 entlen = slash - (path + baselen);
251 sub = find_subtree(it, path + baselen, entlen, 0);
252 if (!sub)
253 die("cache-tree.c: '%.*s' in '%s' not found",
254 entlen, path + baselen, path);
255 i += sub->cache_tree->entry_count - 1;
256 sha1 = sub->cache_tree->sha1;
257 mode = S_IFDIR;
258 }
259 else {
260 sha1 = ce->sha1;
261 mode = ntohl(ce->ce_mode);
262 entlen = pathlen - baselen;
263 }
264 if (!missing_ok && !has_sha1_file(sha1))
265 return error("invalid object %s", sha1_to_hex(sha1));
266
267 if (!ce->ce_mode)
268 continue; /* entry being removed */
269
270 if (size < offset + entlen + 100) {
271 size = alloc_nr(offset + entlen + 100);
272 buffer = xrealloc(buffer, size);
273 }
274 offset += sprintf(buffer + offset,
275 "%o %.*s", mode, entlen, path + baselen);
276 buffer[offset++] = 0;
277 memcpy(buffer + offset, sha1, 20);
278 offset += 20;
279
280#if DEBUG
281 fprintf(stderr, "cache-tree %o %.*s\n",
282 mode, entlen, path + baselen);
283#endif
284 }
285
286 write_sha1_file(buffer, offset, tree_type, it->sha1);
287 free(buffer);
288 it->entry_count = i;
289#if DEBUG
290 fprintf(stderr, "cache-tree (%d ent, %d subtree) %s\n",
291 it->entry_count, it->subtree_nr,
292 sha1_to_hex(it->sha1));
293#endif
294 return i;
295}
296
297int cache_tree_update(struct cache_tree *it,
298 struct cache_entry **cache,
299 int entries,
300 int missing_ok)
301{
302 int i;
303 i = verify_cache(cache, entries);
304 if (i)
305 return i;
306 i = update_one(it, cache, entries, "", 0, missing_ok);
307 if (i < 0)
308 return i;
309 return 0;
310}
311
312static void *write_one(struct cache_tree *it,
313 char *path,
314 int pathlen,
315 char *buffer,
316 unsigned long *size,
317 unsigned long *offset)
318{
319 int i;
320
321 /* One "cache-tree" entry consists of the following:
322 * path (NUL terminated)
323 * entry_count, subtree_nr ("%d %d\n")
324 * tree-sha1 (missing if invalid)
325 * subtree_nr "cache-tree" entries for subtrees.
326 */
327 if (*size < *offset + pathlen + 100) {
328 *size = alloc_nr(*offset + pathlen + 100);
329 buffer = xrealloc(buffer, *size);
330 }
331 *offset += sprintf(buffer + *offset, "%.*s%c%d %d\n",
332 pathlen, path, 0,
333 it->entry_count, it->subtree_nr);
334
335#if DEBUG
336 if (0 <= it->entry_count)
337 fprintf(stderr, "cache-tree <%.*s> (%d ent, %d subtree) %s\n",
338 pathlen, path, it->entry_count, it->subtree_nr,
339 sha1_to_hex(it->sha1));
340 else
341 fprintf(stderr, "cache-tree <%.*s> (%d subtree) invalid\n",
342 pathlen, path, it->subtree_nr);
343#endif
344
345 if (0 <= it->entry_count) {
346 memcpy(buffer + *offset, it->sha1, 20);
347 *offset += 20;
348 }
349 for (i = 0; i < it->subtree_nr; i++) {
350 struct cache_tree_sub *down = it->down[i];
351 buffer = write_one(down->cache_tree, down->name, down->namelen,
352 buffer, size, offset);
353 }
354 return buffer;
355}
356
357static void *cache_tree_write(const unsigned char *cache_sha1,
358 struct cache_tree *root,
359 unsigned long *offset_p)
360{
361 char path[PATH_MAX];
362 unsigned long size = 8192;
363 char *buffer = xmalloc(size);
364
365 /* the cache checksum of the corresponding index file. */
366 memcpy(buffer, cache_sha1, 20);
367 *offset_p = 20;
368 path[0] = 0;
369 return write_one(root, path, 0, buffer, &size, offset_p);
370}
371
372static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
373{
374 const char *buf = *buffer;
375 unsigned long size = *size_p;
376 struct cache_tree *it;
377 int i, subtree_nr;
378
379 it = NULL;
380 /* skip name, but make sure name exists */
381 while (size && *buf) {
382 size--;
383 buf++;
384 }
385 if (!size)
386 goto free_return;
387 buf++; size--;
388 it = cache_tree();
389 if (sscanf(buf, "%d %d\n", &it->entry_count, &subtree_nr) != 2)
390 goto free_return;
391 while (size && *buf && *buf != '\n') {
392 size--;
393 buf++;
394 }
395 if (!size)
396 goto free_return;
397 buf++; size--;
398 if (0 <= it->entry_count) {
399 if (size < 20)
400 goto free_return;
401 memcpy(it->sha1, buf, 20);
402 buf += 20;
403 size -= 20;
404 }
405
406#if DEBUG
407 if (0 <= it->entry_count)
408 fprintf(stderr, "cache-tree <%s> (%d ent, %d subtree) %s\n",
409 *buffer, it->entry_count, subtree_nr,
410 sha1_to_hex(it->sha1));
411 else
412 fprintf(stderr, "cache-tree <%s> (%d subtrees) invalid\n",
413 *buffer, subtree_nr);
414#endif
415
416 /*
417 * Just a heuristic -- we do not add directories that often but
418 * we do not want to have to extend it immediately when we do,
419 * hence +2.
420 */
421 it->subtree_alloc = subtree_nr + 2;
422 it->down = xcalloc(it->subtree_alloc, sizeof(struct cache_tree_sub *));
423 for (i = 0; i < subtree_nr; i++) {
424 /* read each subtree */
425 struct cache_tree *sub;
426 const char *name = buf;
427 int namelen;
428 sub = read_one(&buf, &size);
429 if (!sub)
430 goto free_return;
431 namelen = strlen(name);
432 it->down[i] = find_subtree(it, name, namelen, 1);
433 it->down[i]->cache_tree = sub;
434 }
435 if (subtree_nr != it->subtree_nr)
436 die("cache-tree: internal error");
437 *buffer = buf;
438 *size_p = size;
439 return it;
440
441 free_return:
442 cache_tree_free(it);
443 return NULL;
444}
445
446static struct cache_tree *cache_tree_read(unsigned char *sha1,
447 const char *buffer,
448 unsigned long size)
449{
450 /* check the cache-tree matches the index */
451 if (memcmp(buffer, sha1, 20))
452 return NULL; /* checksum mismatch */
453 if (buffer[20])
454 return NULL; /* not the whole tree */
455 buffer += 20;
456 size -= 20;
457 return read_one(&buffer, &size);
458}
459
460struct cache_tree *read_cache_tree(unsigned char *sha1)
461{
462 int fd;
463 struct stat st;
464 char path[PATH_MAX];
465 unsigned long size = 0;
466 void *map;
467 struct cache_tree *it;
468
469 sprintf(path, "%s.aux", get_index_file());
470 fd = open(path, O_RDONLY);
471 if (fd < 0)
472 return cache_tree();
473
474 if (fstat(fd, &st))
475 return cache_tree();
476 size = st.st_size;
477 map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
478 close(fd);
479 if (map == MAP_FAILED)
480 return cache_tree();
481 it = cache_tree_read(sha1, map, size);
482 munmap(map, size);
483 if (!it)
484 return cache_tree();
485 return it;
486}
487
488int write_cache_tree(const unsigned char *sha1, struct cache_tree *root)
489{
490 char path[PATH_MAX];
491 unsigned long size = 0;
492 void *buf, *buffer;
493 int fd, ret = -1;
494
495 sprintf(path, "%s.aux", get_index_file());
496 if (!root) {
497 unlink(path);
498 return -1;
499 }
500 fd = open(path, O_WRONLY|O_CREAT, 0666);
501 if (fd < 0)
502 return -1;
503 buffer = buf = cache_tree_write(sha1, root, &size);
504 while (size) {
505 int written = xwrite(fd, buf, size);
506 if (written <= 0)
507 goto fail;
508 buf += written;
509 size -= written;
510 }
511 ret = 0;
512
513 fail:
514 close(fd);
515 free(buffer);
516 if (ret)
517 unlink(path);
518 return ret;
519}