1#include "cache.h"
2#include "tree.h"
3#include "blob.h"
4#include "commit.h"
5#include "tag.h"
6#include "tree-walk.h"
7#include <stdlib.h>
89
const char *tree_type = "tree";
1011
static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
12{
13int len;
14unsigned int size;
15struct cache_entry *ce;
1617
if (S_ISDIR(mode))
18return READ_TREE_RECURSIVE;
1920
len = strlen(pathname);
21size = cache_entry_size(baselen + len);
22ce = xcalloc(1, size);
2324
ce->ce_mode = create_ce_mode(mode);
25ce->ce_flags = create_ce_flags(baselen + len, stage);
26memcpy(ce->name, base, baselen);
27memcpy(ce->name + baselen, pathname, len+1);
28memcpy(ce->sha1, sha1, 20);
29return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
30}
3132
static int match_tree_entry(const char *base, int baselen, const char *path, unsigned int mode, const char **paths)
33{
34const char *match;
35int pathlen;
3637
if (!paths)
38return 1;
39pathlen = strlen(path);
40while ((match = *paths++) != NULL) {
41int matchlen = strlen(match);
4243
if (baselen >= matchlen) {
44/* If it doesn't match, move along... */
45if (strncmp(base, match, matchlen))
46continue;
47/* The base is a subdirectory of a path which was specified. */
48return 1;
49}
5051
/* Does the base match? */
52if (strncmp(base, match, baselen))
53continue;
5455
match += baselen;
56matchlen -= baselen;
5758
if (pathlen > matchlen)
59continue;
6061
if (matchlen > pathlen) {
62if (match[pathlen] != '/')
63continue;
64if (!S_ISDIR(mode))
65continue;
66}
6768
if (strncmp(path, match, pathlen))
69continue;
7071
return 1;
72}
73return 0;
74}
7576
int read_tree_recursive(struct tree *tree,
77const char *base, int baselen,
78int stage, const char **match,
79read_tree_fn_t fn)
80{
81struct tree_desc desc;
8283
if (parse_tree(tree))
84return -1;
8586
desc.buf = tree->buffer;
87desc.size = tree->size;
8889
while (desc.size) {
90unsigned mode;
91const char *name;
92const unsigned char *sha1;
9394
sha1 = tree_entry_extract(&desc, &name, &mode);
95update_tree_entry(&desc);
9697
if (!match_tree_entry(base, baselen, name, mode, match))
98continue;
99100
switch (fn(sha1, base, baselen, name, mode, stage)) {
101case 0:
102continue;
103case READ_TREE_RECURSIVE:
104break;;
105default:
106return -1;
107}
108if (S_ISDIR(mode)) {
109int retval;
110int pathlen = strlen(name);
111char *newbase;
112113
newbase = xmalloc(baselen + 1 + pathlen);
114memcpy(newbase, base, baselen);
115memcpy(newbase + baselen, name, pathlen);
116newbase[baselen + pathlen] = '/';
117retval = read_tree_recursive(lookup_tree(sha1),
118newbase,
119baselen + pathlen + 1,
120stage, match, fn);
121free(newbase);
122if (retval)
123return -1;
124continue;
125}
126}
127return 0;
128}
129130
int read_tree(struct tree *tree, int stage, const char **match)
131{
132return read_tree_recursive(tree, "", 0, stage, match, read_one_entry);
133}
134135
struct tree *lookup_tree(const unsigned char *sha1)
136{
137struct object *obj = lookup_object(sha1);
138if (!obj) {
139struct tree *ret = xcalloc(1, sizeof(struct tree));
140created_object(sha1, &ret->object);
141ret->object.type = tree_type;
142return ret;
143}
144if (!obj->type)
145obj->type = tree_type;
146if (obj->type != tree_type) {
147error("Object %s is a %s, not a tree",
148sha1_to_hex(sha1), obj->type);
149return NULL;
150}
151return (struct tree *) obj;
152}
153154
static int track_tree_refs(struct tree *item)
155{
156int n_refs = 0, i;
157struct object_refs *refs;
158struct tree_desc desc;
159160
/* Count how many entries there are.. */
161desc.buf = item->buffer;
162desc.size = item->size;
163while (desc.size) {
164n_refs++;
165update_tree_entry(&desc);
166}
167168
/* Allocate object refs and walk it again.. */
169i = 0;
170refs = alloc_object_refs(n_refs);
171desc.buf = item->buffer;
172desc.size = item->size;
173while (desc.size) {
174unsigned mode;
175const char *name;
176const unsigned char *sha1;
177struct object *obj;
178179
sha1 = tree_entry_extract(&desc, &name, &mode);
180update_tree_entry(&desc);
181if (S_ISDIR(mode))
182obj = &lookup_tree(sha1)->object;
183else
184obj = &lookup_blob(sha1)->object;
185refs->ref[i++] = obj;
186}
187set_object_refs(&item->object, refs);
188return 0;
189}
190191
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
192{
193if (item->object.parsed)
194return 0;
195item->object.parsed = 1;
196item->buffer = buffer;
197item->size = size;
198199
if (track_object_refs)
200track_tree_refs(item);
201return 0;
202}
203204
struct tree_entry_list *create_tree_entry_list(struct tree *tree)
205{
206struct tree_desc desc;
207struct tree_entry_list *ret = NULL;
208struct tree_entry_list **list_p = &ret;
209210
desc.buf = tree->buffer;
211desc.size = tree->size;
212213
while (desc.size) {
214unsigned mode;
215const char *path;
216const unsigned char *sha1;
217struct tree_entry_list *entry;
218219
sha1 = tree_entry_extract(&desc, &path, &mode);
220221
entry = xmalloc(sizeof(struct tree_entry_list));
222entry->name = path;
223entry->sha1 = sha1;
224entry->mode = mode;
225entry->directory = S_ISDIR(mode) != 0;
226entry->executable = (mode & S_IXUSR) != 0;
227entry->symlink = S_ISLNK(mode) != 0;
228entry->zeropad = *(const char *)(desc.buf) == '0';
229entry->next = NULL;
230231
update_tree_entry(&desc);
232*list_p = entry;
233list_p = &entry->next;
234}
235return ret;
236}
237238
void free_tree_entry_list(struct tree_entry_list *list)
239{
240while (list) {
241struct tree_entry_list *next = list->next;
242free(list);
243list = next;
244}
245}
246247
int parse_tree(struct tree *item)
248{
249char type[20];
250void *buffer;
251unsigned long size;
252253
if (item->object.parsed)
254return 0;
255buffer = read_sha1_file(item->object.sha1, type, &size);
256if (!buffer)
257return error("Could not read %s",
258sha1_to_hex(item->object.sha1));
259if (strcmp(type, tree_type)) {
260free(buffer);
261return error("Object %s not a tree",
262sha1_to_hex(item->object.sha1));
263}
264return parse_tree_buffer(item, buffer, size);
265}
266267
struct tree *parse_tree_indirect(const unsigned char *sha1)
268{
269struct object *obj = parse_object(sha1);
270do {
271if (!obj)
272return NULL;
273if (obj->type == tree_type)
274return (struct tree *) obj;
275else if (obj->type == commit_type)
276obj = &(((struct commit *) obj)->tree->object);
277else if (obj->type == tag_type)
278obj = ((struct tag *) obj)->tagged;
279else
280return NULL;
281if (!obj->parsed)
282parse_object(obj->sha1);
283} while (1);
284}