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"
20 static int find_name(size_t k
, void *arg
)
22 struct find_arg
*f_arg
= arg
;
23 return strcmp(f_arg
->names
[k
], f_arg
->want
) >= 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 find_arg arg
= {
36 int idx
= binsearch(mod
->add_len
, find_name
, &arg
);
37 if (idx
< mod
->add_len
&& !strcmp(mod
->add
[idx
], name
)) {
42 if (mod
->del_len
> 0) {
43 struct find_arg arg
= {
47 int idx
= binsearch(mod
->del_len
, find_name
, &arg
);
48 if (idx
< mod
->del_len
&& !strcmp(mod
->del
[idx
], name
)) {
53 err
= reftable_table_read_ref(&mod
->tab
, name
, &ref
);
54 reftable_ref_record_release(&ref
);
58 static void modification_release(struct modification
*mod
)
60 /* don't delete the strings themselves; they're owned by ref records.
62 FREE_AND_NULL(mod
->add
);
63 FREE_AND_NULL(mod
->del
);
68 static int modification_has_ref_with_prefix(struct modification
*mod
,
71 struct reftable_iterator it
= { NULL
};
72 struct reftable_ref_record ref
= { NULL
};
75 if (mod
->add_len
> 0) {
76 struct find_arg arg
= {
80 int idx
= binsearch(mod
->add_len
, find_name
, &arg
);
81 if (idx
< mod
->add_len
&&
82 !strncmp(prefix
, mod
->add
[idx
], strlen(prefix
)))
85 err
= reftable_table_seek_ref(&mod
->tab
, &it
, prefix
);
90 err
= reftable_iterator_next_ref(&it
, &ref
);
94 if (mod
->del_len
> 0) {
95 struct find_arg arg
= {
99 int idx
= binsearch(mod
->del_len
, find_name
, &arg
);
100 if (idx
< mod
->del_len
&&
101 !strcmp(ref
.refname
, mod
->del
[idx
])) {
106 if (strncmp(ref
.refname
, prefix
, strlen(prefix
))) {
115 reftable_ref_record_release(&ref
);
116 reftable_iterator_destroy(&it
);
120 static int validate_refname(const char *name
)
123 char *next
= strchr(name
, '/');
125 return REFTABLE_REFNAME_ERROR
;
130 if (next
- name
== 0 || (next
- name
== 1 && *name
== '.') ||
131 (next
- name
== 2 && name
[0] == '.' && name
[1] == '.'))
132 return REFTABLE_REFNAME_ERROR
;
138 int validate_ref_record_addition(struct reftable_table tab
,
139 struct reftable_ref_record
*recs
, size_t sz
)
141 struct modification mod
= {
143 .add
= reftable_calloc(sizeof(char *) * sz
),
144 .del
= reftable_calloc(sizeof(char *) * sz
),
148 for (; i
< sz
; i
++) {
149 if (reftable_ref_record_is_deletion(&recs
[i
])) {
150 mod
.del
[mod
.del_len
++] = recs
[i
].refname
;
152 mod
.add
[mod
.add_len
++] = recs
[i
].refname
;
156 err
= modification_validate(&mod
);
157 modification_release(&mod
);
161 static void strbuf_trim_component(struct strbuf
*sl
)
163 while (sl
->len
> 0) {
164 int is_slash
= (sl
->buf
[sl
->len
- 1] == '/');
165 strbuf_setlen(sl
, sl
->len
- 1);
171 int modification_validate(struct modification
*mod
)
173 struct strbuf slashed
= STRBUF_INIT
;
176 for (; i
< mod
->add_len
; i
++) {
177 err
= validate_refname(mod
->add
[i
]);
180 strbuf_reset(&slashed
);
181 strbuf_addstr(&slashed
, mod
->add
[i
]);
182 strbuf_addstr(&slashed
, "/");
184 err
= modification_has_ref_with_prefix(mod
, slashed
.buf
);
186 err
= REFTABLE_NAME_CONFLICT
;
192 strbuf_reset(&slashed
);
193 strbuf_addstr(&slashed
, mod
->add
[i
]);
194 while (slashed
.len
) {
195 strbuf_trim_component(&slashed
);
196 err
= modification_has_ref(mod
, slashed
.buf
);
198 err
= REFTABLE_NAME_CONFLICT
;
207 strbuf_release(&slashed
);