]>
Commit | Line | Data |
---|---|---|
5e3f94df | 1 | #include "git-compat-util.h" |
41771fa4 | 2 | #include "hex.h" |
175785e5 | 3 | #include "tree.h" |
dabab1d6 | 4 | #include "object-name.h" |
a034e910 | 5 | #include "object-store-ll.h" |
77675e2a | 6 | #include "commit.h" |
14ba97f8 | 7 | #include "alloc.h" |
136f2e54 | 8 | #include "tree-walk.h" |
109cd76d | 9 | #include "repository.h" |
1ee7a5c3 | 10 | #include "environment.h" |
175785e5 DB |
11 | |
12 | const char *tree_type = "tree"; | |
13 | ||
6c9fc42e ÆAB |
14 | int read_tree_at(struct repository *r, |
15 | struct tree *tree, struct strbuf *base, | |
1ee7a5c3 | 16 | int depth, |
6c9fc42e ÆAB |
17 | const struct pathspec *pathspec, |
18 | read_tree_fn_t fn, void *context) | |
94537c78 | 19 | { |
0790a42a | 20 | struct tree_desc desc; |
4c068a98 | 21 | struct name_entry entry; |
f26efc58 | 22 | struct object_id oid; |
d688cf07 NTND |
23 | int len, oldlen = base->len; |
24 | enum interesting retval = entry_not_interesting; | |
0790a42a | 25 | |
1ee7a5c3 JK |
26 | if (depth > max_allowed_tree_depth) |
27 | return error("exceeded maximum allowed tree depth"); | |
28 | ||
521698b1 DB |
29 | if (parse_tree(tree)) |
30 | return -1; | |
0790a42a | 31 | |
6fda5e51 | 32 | init_tree_desc(&desc, tree->buffer, tree->size); |
0790a42a | 33 | |
4c068a98 | 34 | while (tree_entry(&desc, &entry)) { |
d688cf07 | 35 | if (retval != all_entries_interesting) { |
67022e02 | 36 | retval = tree_entry_interesting(r->index, &entry, |
0ad927e9 | 37 | base, pathspec); |
d688cf07 | 38 | if (retval == all_entries_not_interesting) |
ffd31f66 | 39 | break; |
d688cf07 | 40 | if (retval == entry_not_interesting) |
ffd31f66 NTND |
41 | continue; |
42 | } | |
0ca14a57 | 43 | |
ea82b2a0 | 44 | switch (fn(&entry.oid, base, |
47957485 | 45 | entry.path, entry.mode, context)) { |
3c5e8468 LT |
46 | case 0: |
47 | continue; | |
48 | case READ_TREE_RECURSIVE: | |
ba19a808 | 49 | break; |
3c5e8468 LT |
50 | default: |
51 | return -1; | |
52 | } | |
d3bee161 | 53 | |
ffd31f66 | 54 | if (S_ISDIR(entry.mode)) |
ea82b2a0 | 55 | oidcpy(&oid, &entry.oid); |
ffd31f66 NTND |
56 | else if (S_ISGITLINK(entry.mode)) { |
57 | struct commit *commit; | |
d3bee161 | 58 | |
371820d5 | 59 | commit = lookup_commit(r, &entry.oid); |
d3bee161 | 60 | if (!commit) |
ffd31f66 | 61 | die("Commit %s in submodule path %s%s not found", |
ea82b2a0 | 62 | oid_to_hex(&entry.oid), |
ffd31f66 | 63 | base->buf, entry.path); |
d3bee161 | 64 | |
4a93b899 | 65 | if (repo_parse_commit(r, commit)) |
ffd31f66 | 66 | die("Invalid commit %s in submodule path %s%s", |
ea82b2a0 | 67 | oid_to_hex(&entry.oid), |
ffd31f66 NTND |
68 | base->buf, entry.path); |
69 | ||
2e27bd77 | 70 | oidcpy(&oid, get_commit_tree_oid(commit)); |
94537c78 | 71 | } |
ffd31f66 NTND |
72 | else |
73 | continue; | |
74 | ||
0de16337 | 75 | len = tree_entry_len(&entry); |
ffd31f66 NTND |
76 | strbuf_add(base, entry.path, len); |
77 | strbuf_addch(base, '/'); | |
6c9fc42e | 78 | retval = read_tree_at(r, lookup_tree(r, &oid), |
1ee7a5c3 | 79 | base, depth + 1, pathspec, |
6c9fc42e | 80 | fn, context); |
ffd31f66 NTND |
81 | strbuf_setlen(base, oldlen); |
82 | if (retval) | |
83 | return -1; | |
94537c78 LT |
84 | } |
85 | return 0; | |
86 | } | |
87 | ||
47957485 ÆAB |
88 | int read_tree(struct repository *r, |
89 | struct tree *tree, | |
90 | const struct pathspec *pathspec, | |
91 | read_tree_fn_t fn, void *context) | |
ffd31f66 NTND |
92 | { |
93 | struct strbuf sb = STRBUF_INIT; | |
1ee7a5c3 | 94 | int ret = read_tree_at(r, tree, &sb, 0, pathspec, fn, context); |
ffd31f66 | 95 | strbuf_release(&sb); |
ffd31f66 NTND |
96 | return ret; |
97 | } | |
98 | ||
53dca334 EN |
99 | int base_name_compare(const char *name1, size_t len1, int mode1, |
100 | const char *name2, size_t len2, int mode2) | |
101 | { | |
102 | unsigned char c1, c2; | |
103 | size_t len = len1 < len2 ? len1 : len2; | |
104 | int cmp; | |
105 | ||
106 | cmp = memcmp(name1, name2, len); | |
107 | if (cmp) | |
108 | return cmp; | |
109 | c1 = name1[len]; | |
110 | c2 = name2[len]; | |
111 | if (!c1 && S_ISDIR(mode1)) | |
112 | c1 = '/'; | |
113 | if (!c2 && S_ISDIR(mode2)) | |
114 | c2 = '/'; | |
115 | return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0; | |
116 | } | |
117 | ||
118 | /* | |
119 | * df_name_compare() is identical to base_name_compare(), except it | |
120 | * compares conflicting directory/file entries as equal. Note that | |
121 | * while a directory name compares as equal to a regular file, they | |
122 | * then individually compare _differently_ to a filename that has | |
123 | * a dot after the basename (because '\0' < '.' < '/'). | |
124 | * | |
125 | * This is used by routines that want to traverse the git namespace | |
126 | * but then handle conflicting entries together when possible. | |
127 | */ | |
128 | int df_name_compare(const char *name1, size_t len1, int mode1, | |
129 | const char *name2, size_t len2, int mode2) | |
130 | { | |
131 | unsigned char c1, c2; | |
132 | size_t len = len1 < len2 ? len1 : len2; | |
133 | int cmp; | |
134 | ||
135 | cmp = memcmp(name1, name2, len); | |
136 | if (cmp) | |
137 | return cmp; | |
138 | /* Directories and files compare equal (same length, same name) */ | |
139 | if (len1 == len2) | |
140 | return 0; | |
141 | c1 = name1[len]; | |
142 | if (!c1 && S_ISDIR(mode1)) | |
143 | c1 = '/'; | |
144 | c2 = name2[len]; | |
145 | if (!c2 && S_ISDIR(mode2)) | |
146 | c2 = '/'; | |
147 | if (c1 == '/' && !c2) | |
148 | return 0; | |
149 | if (c2 == '/' && !c1) | |
150 | return 0; | |
151 | return c1 - c2; | |
152 | } | |
153 | ||
154 | int name_compare(const char *name1, size_t len1, const char *name2, size_t len2) | |
155 | { | |
156 | size_t min_len = (len1 < len2) ? len1 : len2; | |
157 | int cmp = memcmp(name1, name2, min_len); | |
158 | if (cmp) | |
159 | return cmp; | |
160 | if (len1 < len2) | |
161 | return -1; | |
162 | if (len1 > len2) | |
163 | return 1; | |
164 | return 0; | |
165 | } | |
166 | ||
f58a6cb6 | 167 | struct tree *lookup_tree(struct repository *r, const struct object_id *oid) |
175785e5 | 168 | { |
d0229abd | 169 | struct object *obj = lookup_object(r, oid); |
100c5f3b | 170 | if (!obj) |
a378509e | 171 | return create_object(r, oid, alloc_tree_node(r)); |
6da43d93 | 172 | return object_as_type(obj, OBJ_TREE, 0); |
175785e5 DB |
173 | } |
174 | ||
2d9c58c6 LT |
175 | int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size) |
176 | { | |
175785e5 DB |
177 | if (item->object.parsed) |
178 | return 0; | |
179 | item->object.parsed = 1; | |
136f2e54 LT |
180 | item->buffer = buffer; |
181 | item->size = size; | |
182 | ||
2d9c58c6 LT |
183 | return 0; |
184 | } | |
185 | ||
9cc2b07a | 186 | int parse_tree_gently(struct tree *item, int quiet_on_missing) |
bd2c39f5 | 187 | { |
21666f1a | 188 | enum object_type type; |
bd2c39f5 NP |
189 | void *buffer; |
190 | unsigned long size; | |
bd2c39f5 NP |
191 | |
192 | if (item->object.parsed) | |
193 | return 0; | |
bc726bd0 ÆAB |
194 | buffer = repo_read_object_file(the_repository, &item->object.oid, |
195 | &type, &size); | |
bd2c39f5 | 196 | if (!buffer) |
9cc2b07a JK |
197 | return quiet_on_missing ? -1 : |
198 | error("Could not read %s", | |
f2fd0760 | 199 | oid_to_hex(&item->object.oid)); |
21666f1a | 200 | if (type != OBJ_TREE) { |
bd2c39f5 NP |
201 | free(buffer); |
202 | return error("Object %s not a tree", | |
f2fd0760 | 203 | oid_to_hex(&item->object.oid)); |
bd2c39f5 | 204 | } |
136f2e54 | 205 | return parse_tree_buffer(item, buffer, size); |
bd2c39f5 | 206 | } |
77675e2a | 207 | |
6e454b9a JK |
208 | void free_tree_buffer(struct tree *tree) |
209 | { | |
6a83d902 | 210 | FREE_AND_NULL(tree->buffer); |
6e454b9a JK |
211 | tree->size = 0; |
212 | tree->object.parsed = 0; | |
213 | } | |
214 | ||
a9dbc179 | 215 | struct tree *parse_tree_indirect(const struct object_id *oid) |
77675e2a | 216 | { |
1577dc0f RS |
217 | struct repository *r = the_repository; |
218 | struct object *obj = parse_object(r, oid); | |
219 | return (struct tree *)repo_peel_to_type(r, NULL, 0, obj, OBJ_TREE); | |
77675e2a | 220 | } |