]> git.ipfire.org Git - thirdparty/git.git/blob - reftable/refname.c
Merge branch 'rs/opt-parse-long-fixups'
[thirdparty/git.git] / reftable / refname.c
1 /*
2 Copyright 2020 Google LLC
3
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
7 */
8
9 #include "system.h"
10 #include "reftable-error.h"
11 #include "basics.h"
12 #include "refname.h"
13 #include "reftable-iterator.h"
14
15 struct find_arg {
16 char **names;
17 const char *want;
18 };
19
20 static int find_name(size_t k, void *arg)
21 {
22 struct find_arg *f_arg = arg;
23 return strcmp(f_arg->names[k], f_arg->want) >= 0;
24 }
25
26 static int modification_has_ref(struct modification *mod, const char *name)
27 {
28 struct reftable_ref_record ref = { NULL };
29 int err = 0;
30
31 if (mod->add_len > 0) {
32 struct find_arg arg = {
33 .names = mod->add,
34 .want = name,
35 };
36 int idx = binsearch(mod->add_len, find_name, &arg);
37 if (idx < mod->add_len && !strcmp(mod->add[idx], name)) {
38 return 0;
39 }
40 }
41
42 if (mod->del_len > 0) {
43 struct find_arg arg = {
44 .names = mod->del,
45 .want = name,
46 };
47 int idx = binsearch(mod->del_len, find_name, &arg);
48 if (idx < mod->del_len && !strcmp(mod->del[idx], name)) {
49 return 1;
50 }
51 }
52
53 err = reftable_table_read_ref(&mod->tab, name, &ref);
54 reftable_ref_record_release(&ref);
55 return err;
56 }
57
58 static void modification_release(struct modification *mod)
59 {
60 /* don't delete the strings themselves; they're owned by ref records.
61 */
62 FREE_AND_NULL(mod->add);
63 FREE_AND_NULL(mod->del);
64 mod->add_len = 0;
65 mod->del_len = 0;
66 }
67
68 static int modification_has_ref_with_prefix(struct modification *mod,
69 const char *prefix)
70 {
71 struct reftable_iterator it = { NULL };
72 struct reftable_ref_record ref = { NULL };
73 int err = 0;
74
75 if (mod->add_len > 0) {
76 struct find_arg arg = {
77 .names = mod->add,
78 .want = prefix,
79 };
80 int idx = binsearch(mod->add_len, find_name, &arg);
81 if (idx < mod->add_len &&
82 !strncmp(prefix, mod->add[idx], strlen(prefix)))
83 goto done;
84 }
85 err = reftable_table_seek_ref(&mod->tab, &it, prefix);
86 if (err)
87 goto done;
88
89 while (1) {
90 err = reftable_iterator_next_ref(&it, &ref);
91 if (err)
92 goto done;
93
94 if (mod->del_len > 0) {
95 struct find_arg arg = {
96 .names = mod->del,
97 .want = ref.refname,
98 };
99 int idx = binsearch(mod->del_len, find_name, &arg);
100 if (idx < mod->del_len &&
101 !strcmp(ref.refname, mod->del[idx])) {
102 continue;
103 }
104 }
105
106 if (strncmp(ref.refname, prefix, strlen(prefix))) {
107 err = 1;
108 goto done;
109 }
110 err = 0;
111 goto done;
112 }
113
114 done:
115 reftable_ref_record_release(&ref);
116 reftable_iterator_destroy(&it);
117 return err;
118 }
119
120 static int validate_refname(const char *name)
121 {
122 while (1) {
123 char *next = strchr(name, '/');
124 if (!*name) {
125 return REFTABLE_REFNAME_ERROR;
126 }
127 if (!next) {
128 return 0;
129 }
130 if (next - name == 0 || (next - name == 1 && *name == '.') ||
131 (next - name == 2 && name[0] == '.' && name[1] == '.'))
132 return REFTABLE_REFNAME_ERROR;
133 name = next + 1;
134 }
135 return 0;
136 }
137
138 int validate_ref_record_addition(struct reftable_table tab,
139 struct reftable_ref_record *recs, size_t sz)
140 {
141 struct modification mod = {
142 .tab = tab,
143 .add = reftable_calloc(sz, sizeof(*mod.add)),
144 .del = reftable_calloc(sz, sizeof(*mod.del)),
145 };
146 int i = 0;
147 int err = 0;
148 for (; i < sz; i++) {
149 if (reftable_ref_record_is_deletion(&recs[i])) {
150 mod.del[mod.del_len++] = recs[i].refname;
151 } else {
152 mod.add[mod.add_len++] = recs[i].refname;
153 }
154 }
155
156 err = modification_validate(&mod);
157 modification_release(&mod);
158 return err;
159 }
160
161 static void strbuf_trim_component(struct strbuf *sl)
162 {
163 while (sl->len > 0) {
164 int is_slash = (sl->buf[sl->len - 1] == '/');
165 strbuf_setlen(sl, sl->len - 1);
166 if (is_slash)
167 break;
168 }
169 }
170
171 int modification_validate(struct modification *mod)
172 {
173 struct strbuf slashed = STRBUF_INIT;
174 int err = 0;
175 int i = 0;
176 for (; i < mod->add_len; i++) {
177 err = validate_refname(mod->add[i]);
178 if (err)
179 goto done;
180 strbuf_reset(&slashed);
181 strbuf_addstr(&slashed, mod->add[i]);
182 strbuf_addstr(&slashed, "/");
183
184 err = modification_has_ref_with_prefix(mod, slashed.buf);
185 if (err == 0) {
186 err = REFTABLE_NAME_CONFLICT;
187 goto done;
188 }
189 if (err < 0)
190 goto done;
191
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);
197 if (err == 0) {
198 err = REFTABLE_NAME_CONFLICT;
199 goto done;
200 }
201 if (err < 0)
202 goto done;
203 }
204 }
205 err = 0;
206 done:
207 strbuf_release(&slashed);
208 return err;
209 }