]>
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"
13 static git_tree_cache
*find_child(
14 const git_tree_cache
*tree
, const char *path
, const char *end
)
16 size_t i
, dirlen
= end
? (size_t)(end
- path
) : strlen(path
);
18 for (i
= 0; i
< tree
->children_count
; ++i
) {
19 git_tree_cache
*child
= tree
->children
[i
];
21 if (child
->namelen
== dirlen
&& !memcmp(path
, child
->name
, dirlen
))
28 void git_tree_cache_invalidate_path(git_tree_cache
*tree
, const char *path
)
30 const char *ptr
= path
, *end
;
35 tree
->entry_count
= -1;
38 end
= strchr(ptr
, '/');
40 if (end
== NULL
) /* End of path */
43 tree
= find_child(tree
, ptr
, end
);
44 if (tree
== NULL
) /* We don't have that tree */
47 tree
->entry_count
= -1;
52 const git_tree_cache
*git_tree_cache_get(const git_tree_cache
*tree
, const char *path
)
54 const char *ptr
= path
, *end
;
61 end
= strchr(ptr
, '/');
63 tree
= find_child(tree
, ptr
, end
);
64 if (tree
== NULL
) /* Can't find it */
67 if (end
== NULL
|| *end
+ 1 == '\0')
74 static int read_tree_internal(git_tree_cache
**out
,
75 const char **buffer_in
, const char *buffer_end
,
78 git_tree_cache
*tree
= NULL
;
79 const char *name_start
, *buffer
;
82 buffer
= name_start
= *buffer_in
;
84 if ((buffer
= memchr(buffer
, '\0', buffer_end
- buffer
)) == NULL
)
87 if (++buffer
>= buffer_end
)
90 if (git_tree_cache_new(&tree
, name_start
, pool
) < 0)
93 /* Blank-terminated ASCII decimal number of entries in this tree */
94 if (git__strntol32(&count
, buffer
, buffer_end
- buffer
, &buffer
, 10) < 0)
97 tree
->entry_count
= count
;
99 if (*buffer
!= ' ' || ++buffer
>= buffer_end
)
102 /* Number of children of the tree, newline-terminated */
103 if (git__strntol32(&count
, buffer
, buffer_end
- buffer
, &buffer
, 10) < 0 || count
< 0)
106 tree
->children_count
= count
;
108 if (*buffer
!= '\n' || ++buffer
> buffer_end
)
111 /* The SHA1 is only there if it's not invalidated */
112 if (tree
->entry_count
>= 0) {
113 /* 160-bit SHA-1 for this tree and it's children */
114 if (buffer
+ GIT_OID_RAWSZ
> buffer_end
)
117 git_oid_fromraw(&tree
->oid
, (const unsigned char *)buffer
);
118 buffer
+= GIT_OID_RAWSZ
;
121 /* Parse children: */
122 if (tree
->children_count
> 0) {
125 tree
->children
= git_pool_malloc(pool
, tree
->children_count
* sizeof(git_tree_cache
*));
126 GIT_ERROR_CHECK_ALLOC(tree
->children
);
128 memset(tree
->children
, 0x0, tree
->children_count
* sizeof(git_tree_cache
*));
130 for (i
= 0; i
< tree
->children_count
; ++i
) {
131 if (read_tree_internal(&tree
->children
[i
], &buffer
, buffer_end
, pool
) < 0)
141 git_error_set(GIT_ERROR_INDEX
, "corrupted TREE extension in index");
145 int git_tree_cache_read(git_tree_cache
**tree
, const char *buffer
, size_t buffer_size
, git_pool
*pool
)
147 const char *buffer_end
= buffer
+ buffer_size
;
149 if (read_tree_internal(tree
, &buffer
, buffer_end
, pool
) < 0)
152 if (buffer
< buffer_end
) {
153 git_error_set(GIT_ERROR_INDEX
, "corrupted TREE extension in index (unexpected trailing data)");
160 static int read_tree_recursive(git_tree_cache
*cache
, const git_tree
*tree
, git_pool
*pool
)
162 git_repository
*repo
;
163 size_t i
, j
, nentries
, ntrees
;
166 repo
= git_tree_owner(tree
);
168 git_oid_cpy(&cache
->oid
, git_tree_id(tree
));
169 nentries
= git_tree_entrycount(tree
);
172 * We make sure we know how many trees we need to allocate for
173 * so we don't have to realloc and change the pointers for the
177 for (i
= 0; i
< nentries
; i
++) {
178 const git_tree_entry
*entry
;
180 entry
= git_tree_entry_byindex(tree
, i
);
181 if (git_tree_entry_filemode(entry
) == GIT_FILEMODE_TREE
)
185 cache
->children_count
= ntrees
;
186 cache
->children
= git_pool_mallocz(pool
, ntrees
* sizeof(git_tree_cache
*));
187 GIT_ERROR_CHECK_ALLOC(cache
->children
);
190 for (i
= 0; i
< nentries
; i
++) {
191 const git_tree_entry
*entry
;
194 entry
= git_tree_entry_byindex(tree
, i
);
195 if (git_tree_entry_filemode(entry
) != GIT_FILEMODE_TREE
) {
196 cache
->entry_count
++;
200 if ((error
= git_tree_cache_new(&cache
->children
[j
], git_tree_entry_name(entry
), pool
)) < 0)
203 if ((error
= git_tree_lookup(&subtree
, repo
, git_tree_entry_id(entry
))) < 0)
206 error
= read_tree_recursive(cache
->children
[j
], subtree
, pool
);
207 git_tree_free(subtree
);
208 cache
->entry_count
+= cache
->children
[j
]->entry_count
;
218 int git_tree_cache_read_tree(git_tree_cache
**out
, const git_tree
*tree
, git_pool
*pool
)
221 git_tree_cache
*cache
;
223 if ((error
= git_tree_cache_new(&cache
, "", pool
)) < 0)
226 if ((error
= read_tree_recursive(cache
, tree
, pool
)) < 0)
233 int git_tree_cache_new(git_tree_cache
**out
, const char *name
, git_pool
*pool
)
236 git_tree_cache
*tree
;
238 name_len
= strlen(name
);
239 tree
= git_pool_malloc(pool
, sizeof(git_tree_cache
) + name_len
+ 1);
240 GIT_ERROR_CHECK_ALLOC(tree
);
242 memset(tree
, 0x0, sizeof(git_tree_cache
));
243 /* NUL-terminated tree name */
244 tree
->namelen
= name_len
;
245 memcpy(tree
->name
, name
, name_len
);
246 tree
->name
[name_len
] = '\0';
252 static void write_tree(git_buf
*out
, git_tree_cache
*tree
)
256 git_buf_printf(out
, "%s%c%"PRIdZ
" %"PRIuZ
"\n", tree
->name
, 0, tree
->entry_count
, tree
->children_count
);
258 if (tree
->entry_count
!= -1)
259 git_buf_put(out
, (const char *) &tree
->oid
, GIT_OID_RAWSZ
);
261 for (i
= 0; i
< tree
->children_count
; i
++)
262 write_tree(out
, tree
->children
[i
]);
265 int git_tree_cache_write(git_buf
*out
, git_tree_cache
*tree
)
267 write_tree(out
, tree
);
269 return git_buf_oom(out
) ? -1 : 0;