]>
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 | ||
013f276e JH |
122 | #define SHORT_NAME_NOT_FOUND (-1) |
123 | #define SHORT_NAME_AMBIGUOUS (-2) | |
124 | ||
99a19b43 JH |
125 | static int find_unique_short_object(int len, char *canonical, |
126 | unsigned char *res, unsigned char *sha1) | |
127 | { | |
128 | int has_unpacked, has_packed; | |
129 | unsigned char unpacked_sha1[20], packed_sha1[20]; | |
130 | ||
131 | has_unpacked = find_short_object_filename(len, canonical, unpacked_sha1); | |
132 | has_packed = find_short_packed_object(len, res, packed_sha1); | |
133 | if (!has_unpacked && !has_packed) | |
013f276e | 134 | return SHORT_NAME_NOT_FOUND; |
99a19b43 | 135 | if (1 < has_unpacked || 1 < has_packed) |
013f276e | 136 | return SHORT_NAME_AMBIGUOUS; |
99a19b43 JH |
137 | if (has_unpacked != has_packed) { |
138 | memcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1), 20); | |
139 | return 0; | |
140 | } | |
141 | /* Both have unique ones -- do they match? */ | |
142 | if (memcmp(packed_sha1, unpacked_sha1, 20)) | |
013f276e | 143 | return -2; |
99a19b43 | 144 | memcpy(sha1, packed_sha1, 20); |
9938af6a JH |
145 | return 0; |
146 | } | |
147 | ||
013f276e JH |
148 | static int get_short_sha1(const char *name, int len, unsigned char *sha1, |
149 | int quietly) | |
9938af6a | 150 | { |
013f276e | 151 | int i, status; |
9938af6a JH |
152 | char canonical[40]; |
153 | unsigned char res[20]; | |
154 | ||
af61c6e0 LT |
155 | if (len < 4) |
156 | return -1; | |
9938af6a JH |
157 | memset(res, 0, 20); |
158 | memset(canonical, 'x', 40); | |
af61c6e0 | 159 | for (i = 0; i < len ;i++) { |
9938af6a JH |
160 | unsigned char c = name[i]; |
161 | unsigned char val; | |
9938af6a JH |
162 | if (c >= '0' && c <= '9') |
163 | val = c - '0'; | |
164 | else if (c >= 'a' && c <= 'f') | |
165 | val = c - 'a' + 10; | |
166 | else if (c >= 'A' && c <='F') { | |
167 | val = c - 'A' + 10; | |
168 | c -= 'A' - 'a'; | |
169 | } | |
170 | else | |
171 | return -1; | |
172 | canonical[i] = c; | |
173 | if (!(i & 1)) | |
174 | val <<= 4; | |
175 | res[i >> 1] |= val; | |
176 | } | |
99a19b43 | 177 | |
013f276e JH |
178 | status = find_unique_short_object(i, canonical, res, sha1); |
179 | if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) | |
180 | return error("short SHA1 %.*s is ambiguous.", len, canonical); | |
181 | return status; | |
182 | } | |
183 | ||
184 | const char *find_unique_abbrev(const unsigned char *sha1, int len) | |
185 | { | |
186 | int status; | |
187 | static char hex[41]; | |
188 | memcpy(hex, sha1_to_hex(sha1), 40); | |
189 | while (len < 40) { | |
190 | unsigned char sha1_ret[20]; | |
191 | status = get_short_sha1(hex, len, sha1_ret, 1); | |
192 | if (!status) { | |
193 | hex[len] = 0; | |
194 | return hex; | |
195 | } | |
196 | if (status != SHORT_NAME_AMBIGUOUS) | |
197 | return NULL; | |
198 | len++; | |
199 | } | |
200 | return NULL; | |
9938af6a JH |
201 | } |
202 | ||
9938af6a JH |
203 | static int get_sha1_basic(const char *str, int len, unsigned char *sha1) |
204 | { | |
205 | static const char *prefix[] = { | |
206 | "", | |
207 | "refs", | |
208 | "refs/tags", | |
209 | "refs/heads", | |
9938af6a JH |
210 | NULL |
211 | }; | |
212 | const char **p; | |
213 | ||
3c3852e3 | 214 | if (len == 40 && !get_sha1_hex(str, sha1)) |
9938af6a JH |
215 | return 0; |
216 | ||
217 | for (p = prefix; *p; p++) { | |
218 | char *pathname = git_path("%s/%.*s", *p, len, str); | |
ca8db142 | 219 | if (!read_ref(pathname, sha1)) |
9938af6a JH |
220 | return 0; |
221 | } | |
222 | ||
223 | return -1; | |
224 | } | |
225 | ||
226 | static int get_sha1_1(const char *name, int len, unsigned char *sha1); | |
227 | ||
228 | static int get_parent(const char *name, int len, | |
229 | unsigned char *result, int idx) | |
230 | { | |
231 | unsigned char sha1[20]; | |
232 | int ret = get_sha1_1(name, len, sha1); | |
233 | struct commit *commit; | |
234 | struct commit_list *p; | |
235 | ||
236 | if (ret) | |
237 | return ret; | |
238 | commit = lookup_commit_reference(sha1); | |
239 | if (!commit) | |
240 | return -1; | |
241 | if (parse_commit(commit)) | |
242 | return -1; | |
243 | if (!idx) { | |
244 | memcpy(result, commit->object.sha1, 20); | |
245 | return 0; | |
246 | } | |
247 | p = commit->parents; | |
248 | while (p) { | |
249 | if (!--idx) { | |
250 | memcpy(result, p->item->object.sha1, 20); | |
251 | return 0; | |
252 | } | |
253 | p = p->next; | |
254 | } | |
255 | return -1; | |
256 | } | |
257 | ||
4f7599ac JH |
258 | static int get_nth_ancestor(const char *name, int len, |
259 | unsigned char *result, int generation) | |
260 | { | |
261 | unsigned char sha1[20]; | |
262 | int ret = get_sha1_1(name, len, sha1); | |
263 | if (ret) | |
264 | return ret; | |
265 | ||
266 | while (generation--) { | |
267 | struct commit *commit = lookup_commit_reference(sha1); | |
268 | ||
269 | if (!commit || parse_commit(commit) || !commit->parents) | |
270 | return -1; | |
271 | memcpy(sha1, commit->parents->item->object.sha1, 20); | |
272 | } | |
273 | memcpy(result, sha1, 20); | |
274 | return 0; | |
275 | } | |
276 | ||
9938af6a JH |
277 | static int get_sha1_1(const char *name, int len, unsigned char *sha1) |
278 | { | |
279 | int parent, ret; | |
4f7599ac | 280 | const char *cp; |
9938af6a JH |
281 | |
282 | /* foo^[0-9] or foo^ (== foo^1); we do not do more than 9 parents. */ | |
283 | if (len > 2 && name[len-2] == '^' && | |
284 | name[len-1] >= '0' && name[len-1] <= '9') { | |
285 | parent = name[len-1] - '0'; | |
286 | len -= 2; | |
287 | } | |
ef0bd2e6 | 288 | else if (len > 1 && name[len-1] == '^') { |
9938af6a | 289 | parent = 1; |
ef0bd2e6 JS |
290 | len--; |
291 | } else | |
9938af6a JH |
292 | parent = -1; |
293 | ||
02a4a32c LT |
294 | if (parent >= 0) |
295 | return get_parent(name, len, sha1, parent); | |
296 | ||
4f7599ac JH |
297 | /* "name~3" is "name^^^", |
298 | * "name~12" is "name^^^^^^^^^^^^", and | |
299 | * "name~" and "name~0" are name -- not "name^0"! | |
300 | */ | |
301 | parent = 0; | |
302 | for (cp = name + len - 1; name <= cp; cp--) { | |
303 | int ch = *cp; | |
304 | if ('0' <= ch && ch <= '9') | |
305 | continue; | |
306 | if (ch != '~') | |
307 | parent = -1; | |
308 | break; | |
309 | } | |
310 | if (!parent && *cp == '~') { | |
311 | int len1 = cp - name; | |
312 | cp++; | |
313 | while (cp < name + len) | |
314 | parent = parent * 10 + *cp++ - '0'; | |
315 | return get_nth_ancestor(name, len1, sha1, parent); | |
316 | } | |
317 | ||
9938af6a JH |
318 | ret = get_sha1_basic(name, len, sha1); |
319 | if (!ret) | |
320 | return 0; | |
013f276e | 321 | return get_short_sha1(name, len, sha1, 0); |
9938af6a JH |
322 | } |
323 | ||
324 | /* | |
325 | * This is like "get_sha1_basic()", except it allows "sha1 expressions", | |
326 | * notably "xyz^" for "parent of xyz" | |
327 | */ | |
328 | int get_sha1(const char *name, unsigned char *sha1) | |
329 | { | |
99a19b43 | 330 | prepare_alt_odb(); |
9938af6a JH |
331 | return get_sha1_1(name, strlen(name), sha1); |
332 | } |