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 | { | |
6 | static char dirname[PATH_MAX]; | |
7 | char hex[40]; | |
8 | DIR *dir; | |
9 | int found; | |
10 | ||
11 | snprintf(dirname, sizeof(dirname), "%s/%.2s", get_object_directory(), name); | |
12 | dir = opendir(dirname); | |
13 | sprintf(hex, "%.2s", name); | |
14 | found = 0; | |
15 | if (dir) { | |
16 | struct dirent *de; | |
17 | while ((de = readdir(dir)) != NULL) { | |
18 | if (strlen(de->d_name) != 38) | |
19 | continue; | |
20 | if (memcmp(de->d_name, name + 2, len-2)) | |
21 | continue; | |
22 | memcpy(hex + 2, de->d_name, 38); | |
23 | if (++found > 1) | |
24 | break; | |
25 | } | |
26 | closedir(dir); | |
27 | } | |
28 | if (found == 1) | |
29 | return get_sha1_hex(hex, sha1) == 0; | |
30 | return 0; | |
31 | } | |
32 | ||
33 | static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b) | |
34 | { | |
35 | do { | |
36 | if (*a != *b) | |
37 | return 0; | |
38 | a++; | |
39 | b++; | |
40 | len -= 2; | |
41 | } while (len > 1); | |
42 | if (len) | |
43 | if ((*a ^ *b) & 0xf0) | |
44 | return 0; | |
45 | return 1; | |
46 | } | |
47 | ||
48 | static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1) | |
49 | { | |
50 | struct packed_git *p; | |
51 | ||
52 | prepare_packed_git(); | |
53 | for (p = packed_git; p; p = p->next) { | |
54 | unsigned num = num_packed_objects(p); | |
55 | unsigned first = 0, last = num; | |
56 | while (first < last) { | |
57 | unsigned mid = (first + last) / 2; | |
58 | unsigned char now[20]; | |
59 | int cmp; | |
60 | ||
61 | nth_packed_object_sha1(p, mid, now); | |
62 | cmp = memcmp(match, now, 20); | |
63 | if (!cmp) { | |
64 | first = mid; | |
65 | break; | |
66 | } | |
67 | if (cmp > 0) { | |
68 | first = mid+1; | |
69 | continue; | |
70 | } | |
71 | last = mid; | |
72 | } | |
73 | if (first < num) { | |
74 | unsigned char now[20], next[20]; | |
75 | nth_packed_object_sha1(p, first, now); | |
76 | if (match_sha(len, match, now)) { | |
77 | if (nth_packed_object_sha1(p, first+1, next) || !match_sha(len, match, next)) { | |
78 | memcpy(sha1, now, 20); | |
79 | return 1; | |
80 | } | |
81 | } | |
82 | } | |
83 | } | |
84 | return 0; | |
85 | } | |
86 | ||
af61c6e0 | 87 | static int get_short_sha1(const char *name, int len, unsigned char *sha1) |
9938af6a JH |
88 | { |
89 | int i; | |
90 | char canonical[40]; | |
91 | unsigned char res[20]; | |
92 | ||
af61c6e0 LT |
93 | if (len < 4) |
94 | return -1; | |
9938af6a JH |
95 | memset(res, 0, 20); |
96 | memset(canonical, 'x', 40); | |
af61c6e0 | 97 | for (i = 0; i < len ;i++) { |
9938af6a JH |
98 | unsigned char c = name[i]; |
99 | unsigned char val; | |
9938af6a JH |
100 | if (c >= '0' && c <= '9') |
101 | val = c - '0'; | |
102 | else if (c >= 'a' && c <= 'f') | |
103 | val = c - 'a' + 10; | |
104 | else if (c >= 'A' && c <='F') { | |
105 | val = c - 'A' + 10; | |
106 | c -= 'A' - 'a'; | |
107 | } | |
108 | else | |
109 | return -1; | |
110 | canonical[i] = c; | |
111 | if (!(i & 1)) | |
112 | val <<= 4; | |
113 | res[i >> 1] |= val; | |
114 | } | |
9938af6a JH |
115 | if (find_short_object_filename(i, canonical, sha1)) |
116 | return 0; | |
117 | if (find_short_packed_object(i, res, sha1)) | |
118 | return 0; | |
119 | return -1; | |
120 | } | |
121 | ||
9938af6a JH |
122 | static int get_sha1_basic(const char *str, int len, unsigned char *sha1) |
123 | { | |
124 | static const char *prefix[] = { | |
125 | "", | |
126 | "refs", | |
127 | "refs/tags", | |
128 | "refs/heads", | |
9938af6a JH |
129 | NULL |
130 | }; | |
131 | const char **p; | |
132 | ||
3c3852e3 | 133 | if (len == 40 && !get_sha1_hex(str, sha1)) |
9938af6a JH |
134 | return 0; |
135 | ||
136 | for (p = prefix; *p; p++) { | |
137 | char *pathname = git_path("%s/%.*s", *p, len, str); | |
ca8db142 | 138 | if (!read_ref(pathname, sha1)) |
9938af6a JH |
139 | return 0; |
140 | } | |
141 | ||
142 | return -1; | |
143 | } | |
144 | ||
145 | static int get_sha1_1(const char *name, int len, unsigned char *sha1); | |
146 | ||
147 | static int get_parent(const char *name, int len, | |
148 | unsigned char *result, int idx) | |
149 | { | |
150 | unsigned char sha1[20]; | |
151 | int ret = get_sha1_1(name, len, sha1); | |
152 | struct commit *commit; | |
153 | struct commit_list *p; | |
154 | ||
155 | if (ret) | |
156 | return ret; | |
157 | commit = lookup_commit_reference(sha1); | |
158 | if (!commit) | |
159 | return -1; | |
160 | if (parse_commit(commit)) | |
161 | return -1; | |
162 | if (!idx) { | |
163 | memcpy(result, commit->object.sha1, 20); | |
164 | return 0; | |
165 | } | |
166 | p = commit->parents; | |
167 | while (p) { | |
168 | if (!--idx) { | |
169 | memcpy(result, p->item->object.sha1, 20); | |
170 | return 0; | |
171 | } | |
172 | p = p->next; | |
173 | } | |
174 | return -1; | |
175 | } | |
176 | ||
4f7599ac JH |
177 | static int get_nth_ancestor(const char *name, int len, |
178 | unsigned char *result, int generation) | |
179 | { | |
180 | unsigned char sha1[20]; | |
181 | int ret = get_sha1_1(name, len, sha1); | |
182 | if (ret) | |
183 | return ret; | |
184 | ||
185 | while (generation--) { | |
186 | struct commit *commit = lookup_commit_reference(sha1); | |
187 | ||
188 | if (!commit || parse_commit(commit) || !commit->parents) | |
189 | return -1; | |
190 | memcpy(sha1, commit->parents->item->object.sha1, 20); | |
191 | } | |
192 | memcpy(result, sha1, 20); | |
193 | return 0; | |
194 | } | |
195 | ||
9938af6a JH |
196 | static int get_sha1_1(const char *name, int len, unsigned char *sha1) |
197 | { | |
198 | int parent, ret; | |
4f7599ac | 199 | const char *cp; |
9938af6a JH |
200 | |
201 | /* foo^[0-9] or foo^ (== foo^1); we do not do more than 9 parents. */ | |
202 | if (len > 2 && name[len-2] == '^' && | |
203 | name[len-1] >= '0' && name[len-1] <= '9') { | |
204 | parent = name[len-1] - '0'; | |
205 | len -= 2; | |
206 | } | |
ef0bd2e6 | 207 | else if (len > 1 && name[len-1] == '^') { |
9938af6a | 208 | parent = 1; |
ef0bd2e6 JS |
209 | len--; |
210 | } else | |
9938af6a JH |
211 | parent = -1; |
212 | ||
02a4a32c LT |
213 | if (parent >= 0) |
214 | return get_parent(name, len, sha1, parent); | |
215 | ||
4f7599ac JH |
216 | /* "name~3" is "name^^^", |
217 | * "name~12" is "name^^^^^^^^^^^^", and | |
218 | * "name~" and "name~0" are name -- not "name^0"! | |
219 | */ | |
220 | parent = 0; | |
221 | for (cp = name + len - 1; name <= cp; cp--) { | |
222 | int ch = *cp; | |
223 | if ('0' <= ch && ch <= '9') | |
224 | continue; | |
225 | if (ch != '~') | |
226 | parent = -1; | |
227 | break; | |
228 | } | |
229 | if (!parent && *cp == '~') { | |
230 | int len1 = cp - name; | |
231 | cp++; | |
232 | while (cp < name + len) | |
233 | parent = parent * 10 + *cp++ - '0'; | |
234 | return get_nth_ancestor(name, len1, sha1, parent); | |
235 | } | |
236 | ||
9938af6a JH |
237 | ret = get_sha1_basic(name, len, sha1); |
238 | if (!ret) | |
239 | return 0; | |
af61c6e0 | 240 | return get_short_sha1(name, len, sha1); |
9938af6a JH |
241 | } |
242 | ||
243 | /* | |
244 | * This is like "get_sha1_basic()", except it allows "sha1 expressions", | |
245 | * notably "xyz^" for "parent of xyz" | |
246 | */ | |
247 | int get_sha1(const char *name, unsigned char *sha1) | |
248 | { | |
249 | return get_sha1_1(name, strlen(name), sha1); | |
250 | } |