/proc/self/cwd/c/refname.c
Line | Count | Source (jump to first uncovered line) |
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.h" |
11 | | #include "basics.h" |
12 | | #include "refname.h" |
13 | | #include "slice.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 | 236 | { |
22 | 236 | struct find_arg *f_arg = (struct find_arg *)arg; |
23 | 236 | return strcmp(f_arg->names[k], f_arg->want) >= 0; |
24 | 236 | } |
25 | | |
26 | | int modification_has_ref(struct modification *mod, const char *name) |
27 | 116 | { |
28 | 116 | struct reftable_ref_record ref = { 0 }; |
29 | 116 | int err = 0; |
30 | 116 | |
31 | 116 | if (mod->add_len > 0) { |
32 | 116 | struct find_arg arg = { |
33 | 116 | .names = mod->add, |
34 | 116 | .want = name, |
35 | 116 | }; |
36 | 116 | int idx = binsearch(mod->add_len, find_name, &arg); |
37 | 116 | if (idx < mod->add_len && !strcmp(mod->add[idx], name)) { |
38 | 0 | return 0; |
39 | 0 | } |
40 | 116 | } |
41 | 116 | |
42 | 116 | if (mod->del_len > 0) { |
43 | 4 | struct find_arg arg = { |
44 | 4 | .names = mod->del, |
45 | 4 | .want = name, |
46 | 4 | }; |
47 | 4 | int idx = binsearch(mod->del_len, find_name, &arg); |
48 | 4 | if (idx < mod->del_len && !strcmp(mod->del[idx], name)) { |
49 | 1 | return 1; |
50 | 1 | } |
51 | 115 | } |
52 | 115 | |
53 | 115 | err = reftable_table_read_ref(mod->tab, name, &ref); |
54 | 115 | reftable_ref_record_clear(&ref); |
55 | 115 | return err; |
56 | 115 | } |
57 | | |
58 | | static void modification_clear(struct modification *mod) |
59 | 134 | { |
60 | 134 | /* don't delete the strings themselves; they're owned by ref records. |
61 | 134 | */ |
62 | 134 | FREE_AND_NULL(mod->add); |
63 | 134 | FREE_AND_NULL(mod->del); |
64 | 134 | mod->add_len = 0; |
65 | 134 | mod->del_len = 0; |
66 | 134 | } |
67 | | |
68 | | int modification_has_ref_with_prefix(struct modification *mod, |
69 | | const char *prefix) |
70 | 115 | { |
71 | 115 | struct reftable_iterator it = { NULL }; |
72 | 115 | struct reftable_ref_record ref = { NULL }; |
73 | 115 | int err = 0; |
74 | 115 | |
75 | 115 | if (mod->add_len > 0) { |
76 | 115 | struct find_arg arg = { |
77 | 115 | .names = mod->add, |
78 | 115 | .want = prefix, |
79 | 115 | }; |
80 | 115 | int idx = binsearch(mod->add_len, find_name, &arg); |
81 | 115 | if (idx < mod->add_len && |
82 | 115 | !strncmp(prefix, mod->add[idx], strlen(prefix))) { |
83 | 0 | goto exit; |
84 | 0 | } |
85 | 115 | } |
86 | 115 | err = reftable_table_seek_ref(mod->tab, &it, prefix); |
87 | 115 | if (err) { |
88 | 0 | goto exit; |
89 | 0 | } |
90 | 115 | |
91 | 116 | while (true) { |
92 | 116 | err = reftable_iterator_next_ref(it, &ref); |
93 | 116 | if (err) { |
94 | 113 | goto exit; |
95 | 113 | } |
96 | 3 | |
97 | 3 | if (mod->del_len > 0) { |
98 | 1 | struct find_arg arg = { |
99 | 1 | .names = mod->del, |
100 | 1 | .want = ref.ref_name, |
101 | 1 | }; |
102 | 1 | int idx = binsearch(mod->del_len, find_name, &arg); |
103 | 1 | if (idx < mod->del_len && |
104 | 1 | !strcmp(ref.ref_name, mod->del[idx])) { |
105 | 1 | continue; |
106 | 1 | } |
107 | 2 | } |
108 | 2 | |
109 | 2 | if (strncmp(ref.ref_name, prefix, strlen(prefix))) { |
110 | 0 | err = 1; |
111 | 0 | goto exit; |
112 | 0 | } |
113 | 2 | err = 0; |
114 | 2 | goto exit; |
115 | 2 | } |
116 | 115 | |
117 | 115 | exit: |
118 | 115 | reftable_ref_record_clear(&ref); |
119 | 115 | reftable_iterator_destroy(&it); |
120 | 115 | return err; |
121 | 115 | } |
122 | | |
123 | | int validate_ref_name(const char *name) |
124 | 119 | { |
125 | 130 | while (true) { |
126 | 130 | char *next = strchr(name, '/'); |
127 | 130 | if (!*name) { |
128 | 1 | return REFTABLE_REFNAME_ERROR; |
129 | 1 | } |
130 | 129 | if (!next) { |
131 | 115 | return 0; |
132 | 115 | } |
133 | 14 | if (next - name == 0 || (next - name == 1 && *name == '.') || |
134 | 14 | (next - name == 2 && name[0] == '.' && name[1] == '.')) |
135 | 3 | return REFTABLE_REFNAME_ERROR; |
136 | 11 | name = next + 1; |
137 | 11 | } |
138 | 119 | return 0; |
139 | 119 | } |
140 | | |
141 | | int validate_ref_record_addition(struct reftable_table tab, |
142 | | struct reftable_ref_record *recs, size_t sz) |
143 | 134 | { |
144 | 134 | struct modification mod = { |
145 | 134 | .tab = tab, |
146 | 134 | .add = reftable_calloc(sizeof(char *) * sz), |
147 | 134 | .del = reftable_calloc(sizeof(char *) * sz), |
148 | 134 | }; |
149 | 134 | int i = 0; |
150 | 134 | int err = 0; |
151 | 245 | for (; i < sz; i++) { |
152 | 111 | if (reftable_ref_record_is_deletion(&recs[i])) { |
153 | 1 | mod.del[mod.del_len++] = recs[i].ref_name; |
154 | 110 | } else { |
155 | 110 | mod.add[mod.add_len++] = recs[i].ref_name; |
156 | 110 | } |
157 | 111 | } |
158 | 134 | |
159 | 134 | err = modification_validate(&mod); |
160 | 134 | modification_clear(&mod); |
161 | 134 | return err; |
162 | 134 | } |
163 | | |
164 | | static void slice_trim_component(struct slice *sl) |
165 | 116 | { |
166 | 1.16k | while (sl->len > 0) { |
167 | 1.05k | bool is_slash = (sl->buf[sl->len - 1] == '/'); |
168 | 1.05k | sl->len--; |
169 | 1.05k | if (is_slash) |
170 | 5 | break; |
171 | 1.05k | } |
172 | 116 | } |
173 | | |
174 | | int modification_validate(struct modification *mod) |
175 | 144 | { |
176 | 144 | struct slice slashed = { 0 }; |
177 | 144 | int err = 0; |
178 | 144 | int i = 0; |
179 | 255 | for (; i < mod->add_len; i++) { |
180 | 119 | err = validate_ref_name(mod->add[i]); |
181 | 119 | if (err) { |
182 | 4 | goto exit; |
183 | 4 | } |
184 | 115 | slice_set_string(&slashed, mod->add[i]); |
185 | 115 | slice_append_string(&slashed, "/"); |
186 | 115 | |
187 | 115 | err = modification_has_ref_with_prefix( |
188 | 115 | mod, slice_as_string(&slashed)); |
189 | 115 | if (err == 0) { |
190 | 2 | err = REFTABLE_NAME_CONFLICT; |
191 | 2 | goto exit; |
192 | 2 | } |
193 | 113 | if (err < 0) { |
194 | 0 | goto exit; |
195 | 0 | } |
196 | 113 | |
197 | 113 | slice_set_string(&slashed, mod->add[i]); |
198 | 227 | while (slashed.len) { |
199 | 116 | slice_trim_component(&slashed); |
200 | 116 | err = modification_has_ref(mod, |
201 | 116 | slice_as_string(&slashed)); |
202 | 116 | if (err == 0) { |
203 | 2 | err = REFTABLE_NAME_CONFLICT; |
204 | 2 | goto exit; |
205 | 2 | } |
206 | 114 | if (err < 0) { |
207 | 0 | goto exit; |
208 | 0 | } |
209 | 114 | } |
210 | 113 | } |
211 | 144 | err = 0; |
212 | 144 | exit: |
213 | 144 | slice_clear(&slashed); |
214 | 144 | return err; |
215 | 136 | } |