Coverage Report

Created: 2020-05-07 18:36

/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
}