]>
Commit | Line | Data |
---|---|---|
9938af6a JH |
1 | #include "cache.h" |
2 | #include "commit.h" | |
3 | ||
4 | static int find_short_object_filename(int len, const char *name, unsigned char *sha1) | |
5 | { | |
99a19b43 | 6 | struct alternate_object_database *alt; |
9938af6a | 7 | char hex[40]; |
99a19b43 JH |
8 | int found = 0; |
9 | static struct alternate_object_database *fakeent; | |
10 | ||
11 | if (!fakeent) { | |
12 | const char *objdir = get_object_directory(); | |
13 | int objdir_len = strlen(objdir); | |
14 | int entlen = objdir_len + 43; | |
15 | fakeent = xmalloc(sizeof(*fakeent) + entlen); | |
16 | memcpy(fakeent->base, objdir, objdir_len); | |
17 | fakeent->name = fakeent->base + objdir_len + 1; | |
18 | fakeent->name[-1] = '/'; | |
19 | } | |
20 | fakeent->next = alt_odb_list; | |
9938af6a | 21 | |
9938af6a | 22 | sprintf(hex, "%.2s", name); |
99a19b43 | 23 | for (alt = fakeent; alt && found < 2; alt = alt->next) { |
9938af6a | 24 | struct dirent *de; |
99a19b43 JH |
25 | DIR *dir; |
26 | sprintf(alt->name, "%.2s/", name); | |
27 | dir = opendir(alt->base); | |
28 | if (!dir) | |
29 | continue; | |
9938af6a JH |
30 | while ((de = readdir(dir)) != NULL) { |
31 | if (strlen(de->d_name) != 38) | |
32 | continue; | |
99a19b43 | 33 | if (memcmp(de->d_name, name + 2, len - 2)) |
9938af6a | 34 | continue; |
99a19b43 JH |
35 | if (!found) { |
36 | memcpy(hex + 2, de->d_name, 38); | |
37 | found++; | |
38 | } | |
39 | else if (memcmp(hex + 2, de->d_name, 38)) { | |
40 | found = 2; | |
9938af6a | 41 | break; |
99a19b43 | 42 | } |
9938af6a JH |
43 | } |
44 | closedir(dir); | |
45 | } | |
46 | if (found == 1) | |
47 | return get_sha1_hex(hex, sha1) == 0; | |
99a19b43 | 48 | return found; |
9938af6a JH |
49 | } |
50 | ||
51 | static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b) | |
52 | { | |
53 | do { | |
54 | if (*a != *b) | |
55 | return 0; | |
56 | a++; | |
57 | b++; | |
58 | len -= 2; | |
59 | } while (len > 1); | |
60 | if (len) | |
61 | if ((*a ^ *b) & 0xf0) | |
62 | return 0; | |
63 | return 1; | |
64 | } | |
65 | ||
66 | static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1) | |
67 | { | |
68 | struct packed_git *p; | |
99a19b43 JH |
69 | unsigned char found_sha1[20]; |
70 | int found = 0; | |
9938af6a JH |
71 | |
72 | prepare_packed_git(); | |
99a19b43 | 73 | for (p = packed_git; p && found < 2; p = p->next) { |
9938af6a JH |
74 | unsigned num = num_packed_objects(p); |
75 | unsigned first = 0, last = num; | |
76 | while (first < last) { | |
77 | unsigned mid = (first + last) / 2; | |
78 | unsigned char now[20]; | |
79 | int cmp; | |
80 | ||
81 | nth_packed_object_sha1(p, mid, now); | |
82 | cmp = memcmp(match, now, 20); | |
83 | if (!cmp) { | |
84 | first = mid; | |
85 | break; | |
86 | } | |
87 | if (cmp > 0) { | |
88 | first = mid+1; | |
89 | continue; | |
90 | } | |
91 | last = mid; | |
92 | } | |
93 | if (first < num) { | |
0bc45890 | 94 | unsigned char now[20], next[20]; |
9938af6a JH |
95 | nth_packed_object_sha1(p, first, now); |
96 | if (match_sha(len, match, now)) { | |
0bc45890 JH |
97 | if (nth_packed_object_sha1(p, first+1, next) || |
98 | !match_sha(len, match, next)) { | |
99 | /* unique within this pack */ | |
100 | if (!found) { | |
101 | memcpy(found_sha1, now, 20); | |
102 | found++; | |
103 | } | |
104 | else if (memcmp(found_sha1, now, 20)) { | |
105 | found = 2; | |
106 | break; | |
107 | } | |
99a19b43 | 108 | } |
0bc45890 JH |
109 | else { |
110 | /* not even unique within this pack */ | |
99a19b43 JH |
111 | found = 2; |
112 | break; | |
9938af6a JH |
113 | } |
114 | } | |
115 | } | |
116 | } | |
99a19b43 JH |
117 | if (found == 1) |
118 | memcpy(sha1, found_sha1, 20); | |
119 | return found; | |
120 | } | |
121 | ||
122 | static int find_unique_short_object(int len, char *canonical, | |
123 | unsigned char *res, unsigned char *sha1) | |
124 | { | |
125 | int has_unpacked, has_packed; | |
126 | unsigned char unpacked_sha1[20], packed_sha1[20]; | |
127 | ||
128 | has_unpacked = find_short_object_filename(len, canonical, unpacked_sha1); | |
129 | has_packed = find_short_packed_object(len, res, packed_sha1); | |
130 | if (!has_unpacked && !has_packed) | |
131 | return -1; | |
132 | if (1 < has_unpacked || 1 < has_packed) | |
0bc45890 | 133 | return error("short SHA1 %.*s is ambiguous.", len, canonical); |
99a19b43 JH |
134 | if (has_unpacked != has_packed) { |
135 | memcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1), 20); | |
136 | return 0; | |
137 | } | |
138 | /* Both have unique ones -- do they match? */ | |
139 | if (memcmp(packed_sha1, unpacked_sha1, 20)) | |
5a82b4fb | 140 | return error("short SHA1 %.*s is ambiguous.", len, canonical); |
99a19b43 | 141 | memcpy(sha1, packed_sha1, 20); |
9938af6a JH |
142 | return 0; |
143 | } | |
144 | ||
af61c6e0 | 145 | static int get_short_sha1(const char *name, int len, unsigned char *sha1) |
9938af6a JH |
146 | { |
147 | int i; | |
148 | char canonical[40]; | |
149 | unsigned char res[20]; | |
150 | ||
af61c6e0 LT |
151 | if (len < 4) |
152 | return -1; | |
9938af6a JH |
153 | memset(res, 0, 20); |
154 | memset(canonical, 'x', 40); | |
af61c6e0 | 155 | for (i = 0; i < len ;i++) { |
9938af6a JH |
156 | unsigned char c = name[i]; |
157 | unsigned char val; | |
9938af6a JH |
158 | if (c >= '0' && c <= '9') |
159 | val = c - '0'; | |
160 | else if (c >= 'a' && c <= 'f') | |
161 | val = c - 'a' + 10; | |
162 | else if (c >= 'A' && c <='F') { | |
163 | val = c - 'A' + 10; | |
164 | c -= 'A' - 'a'; | |
165 | } | |
166 | else | |
167 | return -1; | |
168 | canonical[i] = c; | |
169 | if (!(i & 1)) | |
170 | val <<= 4; | |
171 | res[i >> 1] |= val; | |
172 | } | |
99a19b43 JH |
173 | |
174 | return find_unique_short_object(i, canonical, res, sha1); | |
9938af6a JH |
175 | } |
176 | ||
9938af6a JH |
177 | static int get_sha1_basic(const char *str, int len, unsigned char *sha1) |
178 | { | |
179 | static const char *prefix[] = { | |
180 | "", | |
181 | "refs", | |
182 | "refs/tags", | |
183 | "refs/heads", | |
9938af6a JH |
184 | NULL |
185 | }; | |
186 | const char **p; | |
187 | ||
3c3852e3 | 188 | if (len == 40 && !get_sha1_hex(str, sha1)) |
9938af6a JH |
189 | return 0; |
190 | ||
191 | for (p = prefix; *p; p++) { | |
192 | char *pathname = git_path("%s/%.*s", *p, len, str); | |
ca8db142 | 193 | if (!read_ref(pathname, sha1)) |
9938af6a JH |
194 | return 0; |
195 | } | |
196 | ||
197 | return -1; | |
198 | } | |
199 | ||
200 | static int get_sha1_1(const char *name, int len, unsigned char *sha1); | |
201 | ||
202 | static int get_parent(const char *name, int len, | |
203 | unsigned char *result, int idx) | |
204 | { | |
205 | unsigned char sha1[20]; | |
206 | int ret = get_sha1_1(name, len, sha1); | |
207 | struct commit *commit; | |
208 | struct commit_list *p; | |
209 | ||
210 | if (ret) | |
211 | return ret; | |
212 | commit = lookup_commit_reference(sha1); | |
213 | if (!commit) | |
214 | return -1; | |
215 | if (parse_commit(commit)) | |
216 | return -1; | |
217 | if (!idx) { | |
218 | memcpy(result, commit->object.sha1, 20); | |
219 | return 0; | |
220 | } | |
221 | p = commit->parents; | |
222 | while (p) { | |
223 | if (!--idx) { | |
224 | memcpy(result, p->item->object.sha1, 20); | |
225 | return 0; | |
226 | } | |
227 | p = p->next; | |
228 | } | |
229 | return -1; | |
230 | } | |
231 | ||
4f7599ac JH |
232 | static int get_nth_ancestor(const char *name, int len, |
233 | unsigned char *result, int generation) | |
234 | { | |
235 | unsigned char sha1[20]; | |
236 | int ret = get_sha1_1(name, len, sha1); | |
237 | if (ret) | |
238 | return ret; | |
239 | ||
240 | while (generation--) { | |
241 | struct commit *commit = lookup_commit_reference(sha1); | |
242 | ||
243 | if (!commit || parse_commit(commit) || !commit->parents) | |
244 | return -1; | |
245 | memcpy(sha1, commit->parents->item->object.sha1, 20); | |
246 | } | |
247 | memcpy(result, sha1, 20); | |
248 | return 0; | |
249 | } | |
250 | ||
9938af6a JH |
251 | static int get_sha1_1(const char *name, int len, unsigned char *sha1) |
252 | { | |
253 | int parent, ret; | |
4f7599ac | 254 | const char *cp; |
9938af6a JH |
255 | |
256 | /* foo^[0-9] or foo^ (== foo^1); we do not do more than 9 parents. */ | |
257 | if (len > 2 && name[len-2] == '^' && | |
258 | name[len-1] >= '0' && name[len-1] <= '9') { | |
259 | parent = name[len-1] - '0'; | |
260 | len -= 2; | |
261 | } | |
ef0bd2e6 | 262 | else if (len > 1 && name[len-1] == '^') { |
9938af6a | 263 | parent = 1; |
ef0bd2e6 JS |
264 | len--; |
265 | } else | |
9938af6a JH |
266 | parent = -1; |
267 | ||
02a4a32c LT |
268 | if (parent >= 0) |
269 | return get_parent(name, len, sha1, parent); | |
270 | ||
4f7599ac JH |
271 | /* "name~3" is "name^^^", |
272 | * "name~12" is "name^^^^^^^^^^^^", and | |
273 | * "name~" and "name~0" are name -- not "name^0"! | |
274 | */ | |
275 | parent = 0; | |
276 | for (cp = name + len - 1; name <= cp; cp--) { | |
277 | int ch = *cp; | |
278 | if ('0' <= ch && ch <= '9') | |
279 | continue; | |
280 | if (ch != '~') | |
281 | parent = -1; | |
282 | break; | |
283 | } | |
284 | if (!parent && *cp == '~') { | |
285 | int len1 = cp - name; | |
286 | cp++; | |
287 | while (cp < name + len) | |
288 | parent = parent * 10 + *cp++ - '0'; | |
289 | return get_nth_ancestor(name, len1, sha1, parent); | |
290 | } | |
291 | ||
9938af6a JH |
292 | ret = get_sha1_basic(name, len, sha1); |
293 | if (!ret) | |
294 | return 0; | |
af61c6e0 | 295 | return get_short_sha1(name, len, sha1); |
9938af6a JH |
296 | } |
297 | ||
298 | /* | |
299 | * This is like "get_sha1_basic()", except it allows "sha1 expressions", | |
300 | * notably "xyz^" for "parent of xyz" | |
301 | */ | |
302 | int get_sha1(const char *name, unsigned char *sha1) | |
303 | { | |
99a19b43 | 304 | prepare_alt_odb(); |
9938af6a JH |
305 | return get_sha1_1(name, strlen(name), sha1); |
306 | } |