Merge branch 'jk/send-email-translate-aliases'
[git/gitster.git] / tree.c
blobad86ad1ba99b74ba6556c369005c0363324be952
1 #define USE_THE_REPOSITORY_VARIABLE
3 #include "git-compat-util.h"
4 #include "hex.h"
5 #include "tree.h"
6 #include "object-name.h"
7 #include "object-store-ll.h"
8 #include "commit.h"
9 #include "alloc.h"
10 #include "tree-walk.h"
11 #include "repository.h"
12 #include "environment.h"
14 const char *tree_type = "tree";
16 int read_tree_at(struct repository *r,
17 struct tree *tree, struct strbuf *base,
18 int depth,
19 const struct pathspec *pathspec,
20 read_tree_fn_t fn, void *context)
22 struct tree_desc desc;
23 struct name_entry entry;
24 struct object_id oid;
25 int len, oldlen = base->len;
26 enum interesting retval = entry_not_interesting;
28 if (depth > max_allowed_tree_depth)
29 return error("exceeded maximum allowed tree depth");
31 if (parse_tree(tree))
32 return -1;
34 init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
36 while (tree_entry(&desc, &entry)) {
37 if (retval != all_entries_interesting) {
38 retval = tree_entry_interesting(r->index, &entry,
39 base, pathspec);
40 if (retval == all_entries_not_interesting)
41 break;
42 if (retval == entry_not_interesting)
43 continue;
46 switch (fn(&entry.oid, base,
47 entry.path, entry.mode, context)) {
48 case 0:
49 continue;
50 case READ_TREE_RECURSIVE:
51 break;
52 default:
53 return -1;
56 if (S_ISDIR(entry.mode))
57 oidcpy(&oid, &entry.oid);
58 else if (S_ISGITLINK(entry.mode)) {
59 struct commit *commit;
61 commit = lookup_commit(r, &entry.oid);
62 if (!commit)
63 die("Commit %s in submodule path %s%s not found",
64 oid_to_hex(&entry.oid),
65 base->buf, entry.path);
67 if (repo_parse_commit(r, commit))
68 die("Invalid commit %s in submodule path %s%s",
69 oid_to_hex(&entry.oid),
70 base->buf, entry.path);
72 oidcpy(&oid, get_commit_tree_oid(commit));
74 else
75 continue;
77 len = tree_entry_len(&entry);
78 strbuf_add(base, entry.path, len);
79 strbuf_addch(base, '/');
80 retval = read_tree_at(r, lookup_tree(r, &oid),
81 base, depth + 1, pathspec,
82 fn, context);
83 strbuf_setlen(base, oldlen);
84 if (retval)
85 return -1;
87 return 0;
90 int read_tree(struct repository *r,
91 struct tree *tree,
92 const struct pathspec *pathspec,
93 read_tree_fn_t fn, void *context)
95 struct strbuf sb = STRBUF_INIT;
96 int ret = read_tree_at(r, tree, &sb, 0, pathspec, fn, context);
97 strbuf_release(&sb);
98 return ret;
101 int base_name_compare(const char *name1, size_t len1, int mode1,
102 const char *name2, size_t len2, int mode2)
104 unsigned char c1, c2;
105 size_t len = len1 < len2 ? len1 : len2;
106 int cmp;
108 cmp = memcmp(name1, name2, len);
109 if (cmp)
110 return cmp;
111 c1 = name1[len];
112 c2 = name2[len];
113 if (!c1 && S_ISDIR(mode1))
114 c1 = '/';
115 if (!c2 && S_ISDIR(mode2))
116 c2 = '/';
117 return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
121 * df_name_compare() is identical to base_name_compare(), except it
122 * compares conflicting directory/file entries as equal. Note that
123 * while a directory name compares as equal to a regular file, they
124 * then individually compare _differently_ to a filename that has
125 * a dot after the basename (because '\0' < '.' < '/').
127 * This is used by routines that want to traverse the git namespace
128 * but then handle conflicting entries together when possible.
130 int df_name_compare(const char *name1, size_t len1, int mode1,
131 const char *name2, size_t len2, int mode2)
133 unsigned char c1, c2;
134 size_t len = len1 < len2 ? len1 : len2;
135 int cmp;
137 cmp = memcmp(name1, name2, len);
138 if (cmp)
139 return cmp;
140 /* Directories and files compare equal (same length, same name) */
141 if (len1 == len2)
142 return 0;
143 c1 = name1[len];
144 if (!c1 && S_ISDIR(mode1))
145 c1 = '/';
146 c2 = name2[len];
147 if (!c2 && S_ISDIR(mode2))
148 c2 = '/';
149 if (c1 == '/' && !c2)
150 return 0;
151 if (c2 == '/' && !c1)
152 return 0;
153 return c1 - c2;
156 int name_compare(const char *name1, size_t len1, const char *name2, size_t len2)
158 size_t min_len = (len1 < len2) ? len1 : len2;
159 int cmp = memcmp(name1, name2, min_len);
160 if (cmp)
161 return cmp;
162 if (len1 < len2)
163 return -1;
164 if (len1 > len2)
165 return 1;
166 return 0;
169 struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
171 struct object *obj = lookup_object(r, oid);
172 if (!obj)
173 return create_object(r, oid, alloc_tree_node(r));
174 return object_as_type(obj, OBJ_TREE, 0);
177 int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
179 if (item->object.parsed)
180 return 0;
181 item->object.parsed = 1;
182 item->buffer = buffer;
183 item->size = size;
185 return 0;
188 int parse_tree_gently(struct tree *item, int quiet_on_missing)
190 enum object_type type;
191 void *buffer;
192 unsigned long size;
194 if (item->object.parsed)
195 return 0;
196 buffer = repo_read_object_file(the_repository, &item->object.oid,
197 &type, &size);
198 if (!buffer)
199 return quiet_on_missing ? -1 :
200 error("Could not read %s",
201 oid_to_hex(&item->object.oid));
202 if (type != OBJ_TREE) {
203 free(buffer);
204 return error("Object %s not a tree",
205 oid_to_hex(&item->object.oid));
207 return parse_tree_buffer(item, buffer, size);
210 void free_tree_buffer(struct tree *tree)
212 FREE_AND_NULL(tree->buffer);
213 tree->size = 0;
214 tree->object.parsed = 0;
217 struct tree *parse_tree_indirect(const struct object_id *oid)
219 struct repository *r = the_repository;
220 struct object *obj = parse_object(r, oid);
221 return (struct tree *)repo_peel_to_type(r, NULL, 0, obj, OBJ_TREE);