9
10
static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
11
12
-static int find_short_object_filename(int len, const char *hex_pfx, unsigned char *sha1)
12
+typedef int (*disambiguate_hint_fn)(const unsigned char *, void *);
13
+
14
+struct disambiguate_state {
15
+ disambiguate_hint_fn fn;
16
+ void *cb_data;
17
+ unsigned char candidate[20];
18
+ unsigned candidate_exists:1;
19
+ unsigned candidate_checked:1;
20
+ unsigned candidate_ok:1;
21
+ unsigned disambiguate_fn_used:1;
22
+ unsigned ambiguous:1;
23
+};
24
+
25
+static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)
26
+{
27
+ if (!ds->candidate_exists) {
28
+ /* this is the first candidate */
29
+ hashcpy(ds->candidate, current);
30
+ ds->candidate_exists = 1;
31
+ return;
32
+ } else if (!hashcmp(ds->candidate, current)) {
33
+ /* the same as what we already have seen */
34
+ return;
35
+ }
36
+
37
+ if (!ds->fn) {
38
+ /* cannot disambiguate between ds->candidate and current */
39
+ ds->ambiguous = 1;
40
+ return;
41
+ }
42
+
43
+ if (!ds->candidate_checked) {
44
+ ds->candidate_ok = ds->fn(ds->candidate, ds->cb_data);
45
+ ds->disambiguate_fn_used = 1;
46
+ ds->candidate_checked = 1;
47
+ }
48
+
49
+ if (!ds->candidate_ok) {
50
+ /* discard the candidate; we know it does not satisify fn */
51
+ hashcpy(ds->candidate, current);
52
+ ds->candidate_checked = 0;
53
+ return;
54
+ }
55
+
56
+ /* if we reach this point, we know ds->candidate satisfies fn */
57
+ if (ds->fn(current, ds->cb_data)) {
58
+ /*
59
+ * if both current and candidate satisfy fn, we cannot
60
+ * disambiguate.
61
+ */
62
+ ds->candidate_ok = 0;
63
+ ds->ambiguous = 1;
64
+ }
65
+
66
+ /* otherwise, current can be discarded and candidate is still good */
67
+}
68
+
69
+static void find_short_object_filename(int len, const char *hex_pfx, struct disambiguate_state *ds)
70
{
71
struct alternate_object_database *alt;
72
char hex[40];
16
- int found = 0;
73
static struct alternate_object_database *fakeent;
74
75
if (!fakeent) {
91
fakeent->next = alt_odb_list;
92
93
sprintf(hex, "%.2s", hex_pfx);
38
- for (alt = fakeent; alt && found < 2; alt = alt->next) {
94
+ for (alt = fakeent; alt && !ds->ambiguous; alt = alt->next) {
95
struct dirent *de;
96
DIR *dir;
97
sprintf(alt->name, "%.2s/", hex_pfx);
98
dir = opendir(alt->base);
99
if (!dir)
100
continue;
45
- while ((de = readdir(dir)) != NULL) {
101
+
102
+ while (!ds->ambiguous && (de = readdir(dir)) != NULL) {
103
+ unsigned char sha1[20];
104
+
105
if (strlen(de->d_name) != 38)
106
continue;
107
if (memcmp(de->d_name, hex_pfx + 2, len - 2))
108
continue;
50
- if (!found) {
51
- memcpy(hex + 2, de->d_name, 38);
52
- found++;
53
- }
54
- else if (memcmp(hex + 2, de->d_name, 38)) {
55
- found = 2;
56
- break;
57
- }
109
+ memcpy(hex + 2, de->d_name, 38);
110
+ if (!get_sha1_hex(hex, sha1))
111
+ update_candidates(ds, sha1);
112
}
113
closedir(dir);
114
}
61
- if (found == 1)
62
- return get_sha1_hex(hex, sha1) == 0;
63
- return found;
115
}
116
117
static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)
129
return 1;
130
}
131
81
-static int unique_in_pack(int len,
132
+static void unique_in_pack(int len,
133
const unsigned char *bin_pfx,
83
- struct packed_git *p,
84
- const unsigned char **found_sha1,
85
- int seen_so_far)
134
+ struct packed_git *p,
135
+ struct disambiguate_state *ds)
136
{
137
uint32_t num, last, i, first = 0;
138
const unsigned char *current = NULL;
163
* with an object name that could match "bin_pfx". See if we have
164
* 0, 1 or more objects that actually match(es).
165
*/
116
- for (i = first; i < num; i++) {
117
- current = nth_packed_object_sha1(p, first);
166
+ for (i = first; i < num && !ds->ambiguous; i++) {
167
+ current = nth_packed_object_sha1(p, i);
168
if (!match_sha(len, bin_pfx, current))
169
break;
120
-
121
- /* current matches */
122
- if (!seen_so_far) {
123
- *found_sha1 = current;
124
- seen_so_far++;
125
- } else if (seen_so_far) {
126
- /* is it the same as the one previously found elsewhere? */
127
- if (hashcmp(*found_sha1, current))
128
- return 2; /* definitely not unique */
129
- }
170
+ update_candidates(ds, current);
171
}
131
- return seen_so_far;
172
}
173
134
-static int find_short_packed_object(int len, const unsigned char *bin_pfx, unsigned char *sha1)
174
+static void find_short_packed_object(int len, const unsigned char *bin_pfx,
175
+ struct disambiguate_state *ds)
176
{
177
struct packed_git *p;
137
- const unsigned char *found_sha1 = NULL;
138
- int found = 0;
178
179
prepare_packed_git();
141
- for (p = packed_git; p && found < 2; p = p->next)
142
- found = unique_in_pack(len, bin_pfx, p, &found_sha1, found);
143
-
144
- if (found == 1)
145
- hashcpy(sha1, found_sha1);
146
- return found;
180
+ for (p = packed_git; p && !ds->ambiguous; p = p->next)
181
+ unique_in_pack(len, bin_pfx, p, ds);
182
}
183
184
#define SHORT_NAME_NOT_FOUND (-1)
185
#define SHORT_NAME_AMBIGUOUS (-2)
186
152
-static int find_unique_short_object(int len, char *hex_pfx,
153
- unsigned char *bin_pfx, unsigned char *sha1)
187
+static int finish_object_disambiguation(struct disambiguate_state *ds,
188
+ unsigned char *sha1)
189
{
155
- int has_unpacked, has_packed;
156
- unsigned char unpacked_sha1[20], packed_sha1[20];
190
+ if (ds->ambiguous)
191
+ return SHORT_NAME_AMBIGUOUS;
192
158
- prepare_alt_odb();
159
- has_unpacked = find_short_object_filename(len, hex_pfx, unpacked_sha1);
160
- has_packed = find_short_packed_object(len, bin_pfx, packed_sha1);
161
- if (!has_unpacked && !has_packed)
193
+ if (!ds->candidate_exists)
194
return SHORT_NAME_NOT_FOUND;
163
- if (1 < has_unpacked || 1 < has_packed)
164
- return SHORT_NAME_AMBIGUOUS;
165
- if (has_unpacked != has_packed) {
166
- hashcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1));
167
- return 0;
168
- }
169
- /* Both have unique ones -- do they match? */
170
- if (hashcmp(packed_sha1, unpacked_sha1))
171
- return SHORT_NAME_AMBIGUOUS;
172
- hashcpy(sha1, packed_sha1);
195
+
196
+ if (!ds->candidate_checked)
197
+ /*
198
+ * If this is the only candidate, there is no point
199
+ * calling the disambiguation hint callback.
200
+ *
201
+ * On the other hand, if the current candidate
202
+ * replaced an earlier candidate that did _not_ pass
203
+ * the disambiguation hint callback, then we do have
204
+ * more than one objects that match the short name
205
+ * given, so we should make sure this one matches;
206
+ * otherwise, if we discovered this one and the one
207
+ * that we previously discarded in the reverse order,
208
+ * we would end up showing different results in the
209
+ * same repository!
210
+ */
211
+ ds->candidate_ok = (!ds->disambiguate_fn_used ||
212
+ ds->fn(ds->candidate, ds->cb_data));
213
+
214
+ if (!ds->candidate_ok)
215
+ return SHORT_NAME_NOT_FOUND;
216
+
217
+ hashcpy(sha1, ds->candidate);
218
return 0;
219
}
220
224
int i, status;
225
char hex_pfx[40];
226
unsigned char bin_pfx[20];
227
+ struct disambiguate_state ds;
228
229
if (len < MINIMUM_ABBREV || len > 40)
230
return -1;
249
bin_pfx[i >> 1] |= val;
250
}
251
206
- status = find_unique_short_object(i, hex_pfx, bin_pfx, sha1);
252
+ prepare_alt_odb();
253
+
254
+ memset(&ds, 0, sizeof(ds));
255
+ find_short_object_filename(len, hex_pfx, &ds);
256
+ find_short_packed_object(len, bin_pfx, &ds);
257
+ status = finish_object_disambiguation(&ds, sha1);
258
+
259
if (!quietly && (status == SHORT_NAME_AMBIGUOUS))
260
return error("short SHA1 %.*s is ambiguous.", len, hex_pfx);
261
return status;