60
return buf;
61
}
62
63
-static int entry_compare(struct name_entry *a, struct name_entry *b)
64
-{
65
- return df_name_compare(
66
- a->path, tree_entry_len(a->path, a->sha1), a->mode,
67
- b->path, tree_entry_len(b->path, b->sha1), b->mode);
68
-}
69
-
63
static void entry_clear(struct name_entry *a)
64
{
65
memset(a, 0, sizeof(*a));
131
return path;
132
}
133
134
+struct tree_desc_skip {
135
+ struct tree_desc_skip *prev;
136
+ const void *ptr;
137
+};
138
+
139
+struct tree_desc_x {
140
+ struct tree_desc d;
141
+ struct tree_desc_skip *skip;
142
+};
143
+
144
+static int name_compare(const char *a, int a_len,
145
+ const char *b, int b_len)
146
+{
147
+ int len = (a_len < b_len) ? a_len : b_len;
148
+ int cmp = memcmp(a, b, len);
149
+ if (cmp)
150
+ return cmp;
151
+ return (a_len - b_len);
152
+}
153
+
154
+static int check_entry_match(const char *a, int a_len, const char *b, int b_len)
155
+{
156
+ /*
157
+ * The caller wants to pick *a* from a tree or nothing.
158
+ * We are looking at *b* in a tree.
159
+ *
160
+ * (0) If a and b are the same name, we are trivially happy.
161
+ *
162
+ * There are three possibilities where *a* could be hiding
163
+ * behind *b*.
164
+ *
165
+ * (1) *a* == "t", *b* == "ab" i.e. *b* sorts earlier than *a* no
166
+ * matter what.
167
+ * (2) *a* == "t", *b* == "t-2" and "t" is a subtree in the tree;
168
+ * (3) *a* == "t-2", *b* == "t" and "t-2" is a blob in the tree.
169
+ *
170
+ * Otherwise we know *a* won't appear in the tree without
171
+ * scanning further.
172
+ */
173
+
174
+ int cmp = name_compare(a, a_len, b, b_len);
175
+
176
+ /* Most common case first -- reading sync'd trees */
177
+ if (!cmp)
178
+ return cmp;
179
+
180
+ if (0 < cmp) {
181
+ /* a comes after b; it does not matter if it is case (3)
182
+ if (b_len < a_len && !memcmp(a, b, b_len) && a[b_len] < '/')
183
+ return 1;
184
+ */
185
+ return 1; /* keep looking */
186
+ }
187
+
188
+ /* b comes after a; are we looking at case (2)? */
189
+ if (a_len < b_len && !memcmp(a, b, a_len) && b[a_len] < '/')
190
+ return 1; /* keep looking */
191
+
192
+ return -1; /* a cannot appear in the tree */
193
+}
194
+
195
+/*
196
+ * From the extended tree_desc, extract the first name entry, while
197
+ * paying attention to the candidate "first" name. Most importantly,
198
+ * when looking for an entry, if there are entries that sorts earlier
199
+ * in the tree object representation than that name, skip them and
200
+ * process the named entry first. We will remember that we haven't
201
+ * processed the first entry yet, and in the later call skip the
202
+ * entry we processed early when update_extended_entry() is called.
203
+ *
204
+ * E.g. if the underlying tree object has these entries:
205
+ *
206
+ * blob "t-1"
207
+ * blob "t-2"
208
+ * tree "t"
209
+ * blob "t=1"
210
+ *
211
+ * and the "first" asks for "t", remember that we still need to
212
+ * process "t-1" and "t-2" but extract "t". After processing the
213
+ * entry "t" from this call, the caller will let us know by calling
214
+ * update_extended_entry() that we can remember "t" has been processed
215
+ * already.
216
+ */
217
+
218
+static void extended_entry_extract(struct tree_desc_x *t,
219
+ struct name_entry *a,
220
+ const char *first,
221
+ int first_len)
222
+{
223
+ const char *path;
224
+ int len;
225
+ struct tree_desc probe;
226
+ struct tree_desc_skip *skip;
227
+
228
+ /*
229
+ * Extract the first entry from the tree_desc, but skip the
230
+ * ones that we already returned in earlier rounds.
231
+ */
232
+ while (1) {
233
+ if (!t->d.size) {
234
+ entry_clear(a);
235
+ break; /* not found */
236
+ }
237
+ entry_extract(&t->d, a);
238
+ for (skip = t->skip; skip; skip = skip->prev)
239
+ if (a->path == skip->ptr)
240
+ break; /* found */
241
+ if (!skip)
242
+ break;
243
+ /* We have processed this entry already. */
244
+ update_tree_entry(&t->d);
245
+ }
246
+
247
+ if (!first || !a->path)
248
+ return;
249
+
250
+ /*
251
+ * The caller wants "first" from this tree, or nothing.
252
+ */
253
+ path = a->path;
254
+ len = tree_entry_len(a->path, a->sha1);
255
+ switch (check_entry_match(first, first_len, path, len)) {
256
+ case -1:
257
+ entry_clear(a);
258
+ case 0:
259
+ return;
260
+ default:
261
+ break;
262
+ }
263
+
264
+ /*
265
+ * We need to look-ahead -- we suspect that a subtree whose
266
+ * name is "first" may be hiding behind the current entry "path".
267
+ */
268
+ probe = t->d;
269
+ while (probe.size) {
270
+ entry_extract(&probe, a);
271
+ path = a->path;
272
+ len = tree_entry_len(a->path, a->sha1);
273
+ switch (check_entry_match(first, first_len, path, len)) {
274
+ case -1:
275
+ entry_clear(a);
276
+ case 0:
277
+ return;
278
+ default:
279
+ update_tree_entry(&probe);
280
+ break;
281
+ }
282
+ /* keep looking */
283
+ }
284
+ entry_clear(a);
285
+}
286
+
287
+static void update_extended_entry(struct tree_desc_x *t, struct name_entry *a)
288
+{
289
+ if (t->d.entry.path == a->path) {
290
+ update_tree_entry(&t->d);
291
+ } else {
292
+ /* we have returned this entry early */
293
+ struct tree_desc_skip *skip = xmalloc(sizeof(*skip));
294
+ skip->ptr = a->path;
295
+ skip->prev = t->skip;
296
+ t->skip = skip;
297
+ }
298
+}
299
+
300
+static void free_extended_entry(struct tree_desc_x *t)
301
+{
302
+ struct tree_desc_skip *p, *s;
303
+
304
+ for (s = t->skip; s; s = p) {
305
+ p = s->prev;
306
+ free(s);
307
+ }
308
+}
309
+
310
int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
311
{
312
int ret = 0;
313
struct name_entry *entry = xmalloc(n*sizeof(*entry));
314
+ int i;
315
+ struct tree_desc_x *tx = xcalloc(n, sizeof(*tx));
316
+
317
+ for (i = 0; i < n; i++)
318
+ tx[i].d = t[i];
319
320
for (;;) {
147
- unsigned long mask = 0;
148
- unsigned long dirmask = 0;
149
- int i, last;
321
+ unsigned long mask, dirmask;
322
+ const char *first = NULL;
323
+ int first_len = 0;
324
+ struct name_entry *e;
325
+ int len;
326
151
- last = -1;
327
for (i = 0; i < n; i++) {
153
- if (!t[i].size)
328
+ e = entry + i;
329
+ extended_entry_extract(tx + i, e, NULL, 0);
330
+ }
331
+
332
+ /*
333
+ * A tree may have "t-2" at the current location even
334
+ * though it may have "t" that is a subtree behind it,
335
+ * and another tree may return "t". We want to grab
336
+ * all "t" from all trees to match in such a case.
337
+ */
338
+ for (i = 0; i < n; i++) {
339
+ e = entry + i;
340
+ if (!e->path)
341
continue;
155
- entry_extract(t+i, entry+i);
156
- if (last >= 0) {
157
- int cmp = entry_compare(entry+i, entry+last);
158
-
159
- /*
160
- * Is the new name bigger than the old one?
161
- * Ignore it
162
- */
163
- if (cmp > 0)
342
+ len = tree_entry_len(e->path, e->sha1);
343
+ if (!first) {
344
+ first = e->path;
345
+ first_len = len;
346
+ continue;
347
+ }
348
+ if (name_compare(e->path, len, first, first_len) < 0) {
349
+ first = e->path;
350
+ first_len = len;
351
+ }
352
+ }
353
+
354
+ if (first) {
355
+ for (i = 0; i < n; i++) {
356
+ e = entry + i;
357
+ extended_entry_extract(tx + i, e, first, first_len);
358
+ /* Cull the ones that are not the earliest */
359
+ if (!e->path)
360
continue;
165
- /*
166
- * Is the new name smaller than the old one?
167
- * Ignore all old ones
168
- */
169
- if (cmp < 0)
170
- mask = 0;
361
+ len = tree_entry_len(e->path, e->sha1);
362
+ if (name_compare(e->path, len, first, first_len))
363
+ entry_clear(e);
364
}
365
+ }
366
+
367
+ /* Now we have in entry[i] the earliest name from the trees */
368
+ mask = 0;
369
+ dirmask = 0;
370
+ for (i = 0; i < n; i++) {
371
+ if (!entry[i].path)
372
+ continue;
373
mask |= 1ul << i;
374
if (S_ISDIR(entry[i].mode))
375
dirmask |= 1ul << i;
175
- last = i;
376
}
377
if (!mask)
378
break;
179
- dirmask &= mask;
180
-
181
- /*
182
- * Clear all the unused name-entries.
183
- */
184
- for (i = 0; i < n; i++) {
185
- if (mask & (1ul << i))
186
- continue;
187
- entry_clear(entry + i);
188
- }
379
ret = info->fn(n, mask, dirmask, entry, info);
380
if (ret < 0)
381
break;
192
- if (ret)
193
- mask &= ret;
382
+ mask &= ret;
383
ret = 0;
195
- for (i = 0; i < n; i++) {
384
+ for (i = 0; i < n; i++)
385
if (mask & (1ul << i))
197
- update_tree_entry(t + i);
198
- }
386
+ update_extended_entry(tx + i, entry + i);
387
}
388
free(entry);
389
+ for (i = 0; i < n; i++)
390
+ free_extended_entry(tx + i);
391
+ free(tx);
392
return ret;
393
}
394