]>
git.proxmox.com Git - libgit2.git/blob - src/tree-cache.c
2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
8 #include "tree-cache.h"
12 static git_tree_cache
*find_child(
13 const git_tree_cache
*tree
, const char *path
, const char *end
)
15 size_t i
, dirlen
= end
? (size_t)(end
- path
) : strlen(path
);
17 for (i
= 0; i
< tree
->children_count
; ++i
) {
18 git_tree_cache
*child
= tree
->children
[i
];
20 if (child
->namelen
== dirlen
&& !memcmp(path
, child
->name
, dirlen
))
27 void git_tree_cache_invalidate_path(git_tree_cache
*tree
, const char *path
)
29 const char *ptr
= path
, *end
;
34 tree
->entry_count
= -1;
37 end
= strchr(ptr
, '/');
39 if (end
== NULL
) /* End of path */
42 tree
= find_child(tree
, ptr
, end
);
43 if (tree
== NULL
) /* We don't have that tree */
46 tree
->entry_count
= -1;
51 const git_tree_cache
*git_tree_cache_get(const git_tree_cache
*tree
, const char *path
)
53 const char *ptr
= path
, *end
;
60 end
= strchr(ptr
, '/');
62 tree
= find_child(tree
, ptr
, end
);
63 if (tree
== NULL
) /* Can't find it */
66 if (end
== NULL
|| *end
+ 1 == '\0')
73 static int read_tree_internal(git_tree_cache
**out
,
74 const char **buffer_in
, const char *buffer_end
,
77 git_tree_cache
*tree
= NULL
;
78 const char *name_start
, *buffer
;
81 buffer
= name_start
= *buffer_in
;
83 if ((buffer
= memchr(buffer
, '\0', buffer_end
- buffer
)) == NULL
)
86 if (++buffer
>= buffer_end
)
89 if (git_tree_cache_new(&tree
, name_start
, pool
) < 0)
92 /* Blank-terminated ASCII decimal number of entries in this tree */
93 if (git__strtol32(&count
, buffer
, &buffer
, 10) < 0)
96 tree
->entry_count
= count
;
98 if (*buffer
!= ' ' || ++buffer
>= buffer_end
)
101 /* Number of children of the tree, newline-terminated */
102 if (git__strtol32(&count
, buffer
, &buffer
, 10) < 0 || count
< 0)
105 tree
->children_count
= count
;
107 if (*buffer
!= '\n' || ++buffer
> buffer_end
)
110 /* The SHA1 is only there if it's not invalidated */
111 if (tree
->entry_count
>= 0) {
112 /* 160-bit SHA-1 for this tree and it's children */
113 if (buffer
+ GIT_OID_RAWSZ
> buffer_end
)
116 git_oid_fromraw(&tree
->oid
, (const unsigned char *)buffer
);
117 buffer
+= GIT_OID_RAWSZ
;
120 /* Parse children: */
121 if (tree
->children_count
> 0) {
124 tree
->children
= git_pool_malloc(pool
, tree
->children_count
* sizeof(git_tree_cache
*));
125 GITERR_CHECK_ALLOC(tree
->children
);
127 memset(tree
->children
, 0x0, tree
->children_count
* sizeof(git_tree_cache
*));
129 for (i
= 0; i
< tree
->children_count
; ++i
) {
130 if (read_tree_internal(&tree
->children
[i
], &buffer
, buffer_end
, pool
) < 0)
140 giterr_set(GITERR_INDEX
, "corrupted TREE extension in index");
144 int git_tree_cache_read(git_tree_cache
**tree
, const char *buffer
, size_t buffer_size
, git_pool
*pool
)
146 const char *buffer_end
= buffer
+ buffer_size
;
148 if (read_tree_internal(tree
, &buffer
, buffer_end
, pool
) < 0)
151 if (buffer
< buffer_end
) {
152 giterr_set(GITERR_INDEX
, "corrupted TREE extension in index (unexpected trailing data)");
159 static int read_tree_recursive(git_tree_cache
*cache
, const git_tree
*tree
, git_pool
*pool
)
161 git_repository
*repo
;
162 size_t i
, j
, nentries
, ntrees
;
165 repo
= git_tree_owner(tree
);
167 git_oid_cpy(&cache
->oid
, git_tree_id(tree
));
168 nentries
= git_tree_entrycount(tree
);
171 * We make sure we know how many trees we need to allocate for
172 * so we don't have to realloc and change the pointers for the
176 for (i
= 0; i
< nentries
; i
++) {
177 const git_tree_entry
*entry
;
179 entry
= git_tree_entry_byindex(tree
, i
);
180 if (git_tree_entry_filemode(entry
) == GIT_FILEMODE_TREE
)
184 cache
->children_count
= ntrees
;
185 cache
->children
= git_pool_mallocz(pool
, ntrees
* sizeof(git_tree_cache
*));
186 GITERR_CHECK_ALLOC(cache
->children
);
189 for (i
= 0; i
< nentries
; i
++) {
190 const git_tree_entry
*entry
;
193 entry
= git_tree_entry_byindex(tree
, i
);
194 if (git_tree_entry_filemode(entry
) != GIT_FILEMODE_TREE
) {
195 cache
->entry_count
++;
199 if ((error
= git_tree_cache_new(&cache
->children
[j
], git_tree_entry_name(entry
), pool
)) < 0)
202 if ((error
= git_tree_lookup(&subtree
, repo
, git_tree_entry_id(entry
))) < 0)
205 error
= read_tree_recursive(cache
->children
[j
], subtree
, pool
);
206 git_tree_free(subtree
);
207 cache
->entry_count
+= cache
->children
[j
]->entry_count
;
217 int git_tree_cache_read_tree(git_tree_cache
**out
, const git_tree
*tree
, git_pool
*pool
)
220 git_tree_cache
*cache
;
222 if ((error
= git_tree_cache_new(&cache
, "", pool
)) < 0)
225 if ((error
= read_tree_recursive(cache
, tree
, pool
)) < 0)
232 int git_tree_cache_new(git_tree_cache
**out
, const char *name
, git_pool
*pool
)
235 git_tree_cache
*tree
;
237 name_len
= strlen(name
);
238 tree
= git_pool_malloc(pool
, sizeof(git_tree_cache
) + name_len
+ 1);
239 GITERR_CHECK_ALLOC(tree
);
241 memset(tree
, 0x0, sizeof(git_tree_cache
));
242 /* NUL-terminated tree name */
243 tree
->namelen
= name_len
;
244 memcpy(tree
->name
, name
, name_len
);
245 tree
->name
[name_len
] = '\0';
251 static void write_tree(git_buf
*out
, git_tree_cache
*tree
)
255 git_buf_printf(out
, "%s%c%"PRIdZ
" %"PRIuZ
"\n", tree
->name
, 0, tree
->entry_count
, tree
->children_count
);
257 if (tree
->entry_count
!= -1)
258 git_buf_put(out
, (const char *) &tree
->oid
, GIT_OID_RAWSZ
);
260 for (i
= 0; i
< tree
->children_count
; i
++)
261 write_tree(out
, tree
->children
[i
]);
264 int git_tree_cache_write(git_buf
*out
, git_tree_cache
*tree
)
266 write_tree(out
, tree
);
268 return git_buf_oom(out
) ? -1 : 0;