2 Copyright 2020 Google LLC
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file or at
6 https://developers.google.com/open-source/licenses/bsd
10 #include "reftable-error.h"
13 #include "reftable-iterator.h"
15 struct refname_needle_lesseq_args
{
20 static int refname_needle_lesseq(size_t k
, void *_args
)
22 struct refname_needle_lesseq_args
*args
= _args
;
23 return strcmp(args
->needle
, args
->haystack
[k
]) <= 0;
26 static int modification_has_ref(struct modification
*mod
, const char *name
)
28 struct reftable_ref_record ref
= { NULL
};
31 if (mod
->add_len
> 0) {
32 struct refname_needle_lesseq_args args
= {
36 size_t idx
= binsearch(mod
->add_len
, refname_needle_lesseq
, &args
);
37 if (idx
< mod
->add_len
&& !strcmp(mod
->add
[idx
], name
))
41 if (mod
->del_len
> 0) {
42 struct refname_needle_lesseq_args args
= {
46 size_t idx
= binsearch(mod
->del_len
, refname_needle_lesseq
, &args
);
47 if (idx
< mod
->del_len
&& !strcmp(mod
->del
[idx
], name
))
51 err
= reftable_table_read_ref(&mod
->tab
, name
, &ref
);
52 reftable_ref_record_release(&ref
);
56 static void modification_release(struct modification
*mod
)
58 /* don't delete the strings themselves; they're owned by ref records.
60 FREE_AND_NULL(mod
->add
);
61 FREE_AND_NULL(mod
->del
);
66 static int modification_has_ref_with_prefix(struct modification
*mod
,
69 struct reftable_iterator it
= { NULL
};
70 struct reftable_ref_record ref
= { NULL
};
73 if (mod
->add_len
> 0) {
74 struct refname_needle_lesseq_args args
= {
78 size_t idx
= binsearch(mod
->add_len
, refname_needle_lesseq
, &args
);
79 if (idx
< mod
->add_len
&&
80 !strncmp(prefix
, mod
->add
[idx
], strlen(prefix
)))
83 err
= reftable_table_seek_ref(&mod
->tab
, &it
, prefix
);
88 err
= reftable_iterator_next_ref(&it
, &ref
);
92 if (mod
->del_len
> 0) {
93 struct refname_needle_lesseq_args args
= {
95 .needle
= ref
.refname
,
97 size_t idx
= binsearch(mod
->del_len
, refname_needle_lesseq
, &args
);
98 if (idx
< mod
->del_len
&&
99 !strcmp(ref
.refname
, mod
->del
[idx
]))
103 if (strncmp(ref
.refname
, prefix
, strlen(prefix
))) {
112 reftable_ref_record_release(&ref
);
113 reftable_iterator_destroy(&it
);
117 static int validate_refname(const char *name
)
120 char *next
= strchr(name
, '/');
122 return REFTABLE_REFNAME_ERROR
;
127 if (next
- name
== 0 || (next
- name
== 1 && *name
== '.') ||
128 (next
- name
== 2 && name
[0] == '.' && name
[1] == '.'))
129 return REFTABLE_REFNAME_ERROR
;
135 int validate_ref_record_addition(struct reftable_table tab
,
136 struct reftable_ref_record
*recs
, size_t sz
)
138 struct modification mod
= {
140 .add
= reftable_calloc(sz
, sizeof(*mod
.add
)),
141 .del
= reftable_calloc(sz
, sizeof(*mod
.del
)),
145 for (; i
< sz
; i
++) {
146 if (reftable_ref_record_is_deletion(&recs
[i
])) {
147 mod
.del
[mod
.del_len
++] = recs
[i
].refname
;
149 mod
.add
[mod
.add_len
++] = recs
[i
].refname
;
153 err
= modification_validate(&mod
);
154 modification_release(&mod
);
158 static void strbuf_trim_component(struct strbuf
*sl
)
160 while (sl
->len
> 0) {
161 int is_slash
= (sl
->buf
[sl
->len
- 1] == '/');
162 strbuf_setlen(sl
, sl
->len
- 1);
168 int modification_validate(struct modification
*mod
)
170 struct strbuf slashed
= STRBUF_INIT
;
173 for (; i
< mod
->add_len
; i
++) {
174 err
= validate_refname(mod
->add
[i
]);
177 strbuf_reset(&slashed
);
178 strbuf_addstr(&slashed
, mod
->add
[i
]);
179 strbuf_addstr(&slashed
, "/");
181 err
= modification_has_ref_with_prefix(mod
, slashed
.buf
);
183 err
= REFTABLE_NAME_CONFLICT
;
189 strbuf_reset(&slashed
);
190 strbuf_addstr(&slashed
, mod
->add
[i
]);
191 while (slashed
.len
) {
192 strbuf_trim_component(&slashed
);
193 err
= modification_has_ref(mod
, slashed
.buf
);
195 err
= REFTABLE_NAME_CONFLICT
;
204 strbuf_release(&slashed
);