1
#include "../git-compat-util.h"
4
#include "../repository.h"
5
#include "refs-internal.h"
7
#include "../iterator.h"
9
void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry)
11
ALLOC_GROW(dir->entries, dir->nr + 1, dir->alloc);
12
dir->entries[dir->nr++] = entry;
15
(dir->nr == dir->sorted + 1 &&
16
strcmp(dir->entries[dir->nr - 2]->name,
17
dir->entries[dir->nr - 1]->name) < 0))
18
dir->sorted = dir->nr;
21
struct ref_dir *get_ref_dir(struct ref_entry *entry)
24
assert(entry->flag & REF_DIR);
25
dir = &entry->u.subdir;
26
if (entry->flag & REF_INCOMPLETE) {
27
if (!dir->cache->fill_ref_dir)
28
BUG("incomplete ref_store without fill_ref_dir function");
30
dir->cache->fill_ref_dir(dir->cache->ref_store, dir, entry->name);
31
entry->flag &= ~REF_INCOMPLETE;
36
struct ref_entry *create_ref_entry(const char *refname,
38
const struct object_id *oid, int flag)
40
struct ref_entry *ref;
42
FLEX_ALLOC_STR(ref, name, refname);
43
oidcpy(&ref->u.value.oid, oid);
45
ref->u.value.referent = xstrdup_or_null(referent);
50
struct ref_cache *create_ref_cache(struct ref_store *refs,
51
fill_ref_dir_fn *fill_ref_dir)
53
struct ref_cache *ret = xcalloc(1, sizeof(*ret));
55
ret->ref_store = refs;
56
ret->fill_ref_dir = fill_ref_dir;
57
ret->root = create_dir_entry(ret, "", 0);
61
static void clear_ref_dir(struct ref_dir *dir);
63
static void free_ref_entry(struct ref_entry *entry)
65
if (entry->flag & REF_DIR) {
70
clear_ref_dir(&entry->u.subdir);
72
free(entry->u.value.referent);
76
void free_ref_cache(struct ref_cache *cache)
80
free_ref_entry(cache->root);
87
static void clear_ref_dir(struct ref_dir *dir)
90
for (i = 0; i < dir->nr; i++)
91
free_ref_entry(dir->entries[i]);
92
FREE_AND_NULL(dir->entries);
93
dir->sorted = dir->nr = dir->alloc = 0;
96
struct ref_entry *create_dir_entry(struct ref_cache *cache,
97
const char *dirname, size_t len)
99
struct ref_entry *direntry;
101
FLEX_ALLOC_MEM(direntry, name, dirname, len);
102
direntry->u.subdir.cache = cache;
103
direntry->flag = REF_DIR | REF_INCOMPLETE;
107
static int ref_entry_cmp(const void *a, const void *b)
109
struct ref_entry *one = *(struct ref_entry **)a;
110
struct ref_entry *two = *(struct ref_entry **)b;
111
return strcmp(one->name, two->name);
114
static void sort_ref_dir(struct ref_dir *dir);
121
static int ref_entry_cmp_sslice(const void *key_, const void *ent_)
123
const struct string_slice *key = key_;
124
const struct ref_entry *ent = *(const struct ref_entry * const *)ent_;
125
int cmp = strncmp(key->str, ent->name, key->len);
128
return '\0' - (unsigned char)ent->name[key->len];
131
int search_ref_dir(struct ref_dir *dir, const char *refname, size_t len)
133
struct ref_entry **r;
134
struct string_slice key;
136
if (refname == NULL || !dir->nr)
142
r = bsearch(&key, dir->entries, dir->nr, sizeof(*dir->entries),
143
ref_entry_cmp_sslice);
148
return r - dir->entries;
157
static struct ref_dir *search_for_subdir(struct ref_dir *dir,
158
const char *subdirname, size_t len)
160
int entry_index = search_ref_dir(dir, subdirname, len);
161
struct ref_entry *entry;
163
if (entry_index == -1)
166
entry = dir->entries[entry_index];
167
return get_ref_dir(entry);
178
static struct ref_dir *find_containing_dir(struct ref_dir *dir,
182
for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
183
size_t dirnamelen = slash - refname + 1;
184
struct ref_dir *subdir;
185
subdir = search_for_subdir(dir, refname, dirnamelen);
196
struct ref_entry *find_ref_entry(struct ref_dir *dir, const char *refname)
199
struct ref_entry *entry;
200
dir = find_containing_dir(dir, refname);
203
entry_index = search_ref_dir(dir, refname, strlen(refname));
204
if (entry_index == -1)
206
entry = dir->entries[entry_index];
207
return (entry->flag & REF_DIR) ? NULL : entry;
215
static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2)
217
if (strcmp(ref1->name, ref2->name))
222
if ((ref1->flag & REF_DIR) || (ref2->flag & REF_DIR))
224
die("Reference directory conflict: %s", ref1->name);
226
if (!oideq(&ref1->u.value.oid, &ref2->u.value.oid))
227
die("Duplicated ref, and SHA1s don't match: %s", ref1->name);
229
warning("Duplicated ref: %s", ref1->name);
237
static void sort_ref_dir(struct ref_dir *dir)
240
struct ref_entry *last = NULL;
246
if (dir->sorted == dir->nr)
249
QSORT(dir->entries, dir->nr, ref_entry_cmp);
252
for (i = 0, j = 0; j < dir->nr; j++) {
253
struct ref_entry *entry = dir->entries[j];
254
if (last && is_dup_ref(last, entry))
255
free_ref_entry(entry);
257
last = dir->entries[i++] = entry;
259
dir->sorted = dir->nr = i;
277
static enum prefix_state overlaps_prefix(const char *dirname,
280
while (*prefix && *dirname == *prefix) {
285
return PREFIX_CONTAINS_DIR;
287
return PREFIX_WITHIN_DIR;
289
return PREFIX_EXCLUDES_DIR;
297
static void prime_ref_dir(struct ref_dir *dir, const char *prefix)
306
for (i = 0; i < dir->nr; i++) {
307
struct ref_entry *entry = dir->entries[i];
308
if (!(entry->flag & REF_DIR)) {
310
} else if (!prefix) {
312
prime_ref_dir(get_ref_dir(entry), NULL);
314
switch (overlaps_prefix(entry->name, prefix)) {
315
case PREFIX_CONTAINS_DIR:
321
prime_ref_dir(get_ref_dir(entry), NULL);
323
case PREFIX_WITHIN_DIR:
324
prime_ref_dir(get_ref_dir(entry), prefix);
326
case PREFIX_EXCLUDES_DIR:
338
struct cache_ref_iterator_level {
345
enum prefix_state prefix_state;
360
struct cache_ref_iterator {
361
struct ref_iterator base;
388
struct cache_ref_iterator_level *levels;
390
struct repository *repo;
393
static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
395
struct cache_ref_iterator *iter =
396
(struct cache_ref_iterator *)ref_iterator;
399
struct cache_ref_iterator_level *level =
400
&iter->levels[iter->levels_nr - 1];
401
struct ref_dir *dir = level->dir;
402
struct ref_entry *entry;
403
enum prefix_state entry_prefix_state;
405
if (level->index == -1)
408
if (++level->index == level->dir->nr) {
410
if (--iter->levels_nr == 0)
411
return ref_iterator_abort(ref_iterator);
416
entry = dir->entries[level->index];
418
if (level->prefix_state == PREFIX_WITHIN_DIR) {
419
entry_prefix_state = overlaps_prefix(entry->name, iter->prefix);
420
if (entry_prefix_state == PREFIX_EXCLUDES_DIR ||
421
(entry_prefix_state == PREFIX_WITHIN_DIR && !(entry->flag & REF_DIR)))
424
entry_prefix_state = level->prefix_state;
427
if (entry->flag & REF_DIR) {
429
ALLOC_GROW(iter->levels, iter->levels_nr + 1,
432
level = &iter->levels[iter->levels_nr++];
433
level->dir = get_ref_dir(entry);
434
level->prefix_state = entry_prefix_state;
437
iter->base.refname = entry->name;
438
iter->base.referent = entry->u.value.referent;
439
iter->base.oid = &entry->u.value.oid;
440
iter->base.flags = entry->flag;
446
static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
447
struct object_id *peeled)
449
struct cache_ref_iterator *iter =
450
(struct cache_ref_iterator *)ref_iterator;
451
return peel_object(iter->repo, ref_iterator->oid, peeled) ? -1 : 0;
454
static int cache_ref_iterator_abort(struct ref_iterator *ref_iterator)
456
struct cache_ref_iterator *iter =
457
(struct cache_ref_iterator *)ref_iterator;
459
free((char *)iter->prefix);
461
base_ref_iterator_free(ref_iterator);
465
static struct ref_iterator_vtable cache_ref_iterator_vtable = {
466
.advance = cache_ref_iterator_advance,
467
.peel = cache_ref_iterator_peel,
468
.abort = cache_ref_iterator_abort
471
struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache,
473
struct repository *repo,
477
struct cache_ref_iterator *iter;
478
struct ref_iterator *ref_iterator;
479
struct cache_ref_iterator_level *level;
481
dir = get_ref_dir(cache->root);
482
if (prefix && *prefix)
483
dir = find_containing_dir(dir, prefix);
486
return empty_ref_iterator_begin();
489
prime_ref_dir(dir, prefix);
491
CALLOC_ARRAY(iter, 1);
492
ref_iterator = &iter->base;
493
base_ref_iterator_init(ref_iterator, &cache_ref_iterator_vtable);
494
ALLOC_GROW(iter->levels, 10, iter->levels_alloc);
497
level = &iter->levels[0];
501
if (prefix && *prefix) {
502
iter->prefix = xstrdup(prefix);
503
level->prefix_state = PREFIX_WITHIN_DIR;
505
level->prefix_state = PREFIX_CONTAINS_DIR;