/proc/self/cwd/c/record.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 | | /* record.c - methods for different types of records. */ |
10 | | |
11 | | #include "record.h" |
12 | | |
13 | | #include "system.h" |
14 | | |
15 | | #include "constants.h" |
16 | | #include "reftable.h" |
17 | | |
18 | | int get_var_int(uint64_t *dest, struct slice in) |
19 | 37.1k | { |
20 | 37.1k | int ptr = 0; |
21 | 37.1k | uint64_t val; |
22 | 37.1k | |
23 | 37.1k | if (in.len == 0) { |
24 | 0 | return -1; |
25 | 0 | } |
26 | 37.1k | val = in.buf[ptr] & 0x7f; |
27 | 37.1k | |
28 | 38.3k | while (in.buf[ptr] & 0x80) { |
29 | 1.25k | ptr++; |
30 | 1.25k | if (ptr > in.len) { |
31 | 0 | return -1; |
32 | 0 | } |
33 | 1.25k | val = (val + 1) << 7 | (uint64_t)(in.buf[ptr] & 0x7f); |
34 | 1.25k | } |
35 | 37.1k | |
36 | 37.1k | *dest = val; |
37 | 37.1k | return ptr + 1; |
38 | 37.1k | } |
39 | | |
40 | | int put_var_int(struct slice dest, uint64_t val) |
41 | 7.37k | { |
42 | 7.37k | byte buf[10] = { 0 }; |
43 | 7.37k | int i = 9; |
44 | 7.37k | buf[i] = (byte)(val & 0x7f); |
45 | 7.37k | i--; |
46 | 8.23k | while (true) { |
47 | 8.23k | val >>= 7; |
48 | 8.23k | if (!val) { |
49 | 7.37k | break; |
50 | 7.37k | } |
51 | 860 | val--; |
52 | 860 | buf[i] = 0x80 | (byte)(val & 0x7f); |
53 | 860 | i--; |
54 | 860 | } |
55 | 7.37k | |
56 | 7.37k | { |
57 | 7.37k | int n = sizeof(buf) - i - 1; |
58 | 7.37k | if (dest.len < n) { |
59 | 0 | return -1; |
60 | 0 | } |
61 | 7.37k | memcpy(dest.buf, &buf[i + 1], n); |
62 | 7.37k | return n; |
63 | 7.37k | } |
64 | 7.37k | } |
65 | | |
66 | | int is_block_type(byte typ) |
67 | 3.25k | { |
68 | 3.25k | switch (typ) { |
69 | 3.25k | case BLOCK_TYPE_REF: |
70 | 3.25k | case BLOCK_TYPE_LOG: |
71 | 3.25k | case BLOCK_TYPE_OBJ: |
72 | 3.25k | case BLOCK_TYPE_INDEX: |
73 | 3.25k | return true; |
74 | 0 | } |
75 | 0 | return false; |
76 | 0 | } |
77 | | |
78 | | static int decode_string(struct slice *dest, struct slice in) |
79 | 6.98k | { |
80 | 6.98k | int start_len = in.len; |
81 | 6.98k | uint64_t tsize = 0; |
82 | 6.98k | int n = get_var_int(&tsize, in); |
83 | 6.98k | if (n <= 0) { |
84 | 0 | return -1; |
85 | 0 | } |
86 | 6.98k | slice_consume(&in, n); |
87 | 6.98k | if (in.len < tsize) { |
88 | 0 | return -1; |
89 | 0 | } |
90 | 6.98k | |
91 | 6.98k | slice_resize(dest, tsize + 1); |
92 | 6.98k | dest->buf[tsize] = 0; |
93 | 6.98k | memcpy(dest->buf, in.buf, tsize); |
94 | 6.98k | slice_consume(&in, tsize); |
95 | 6.98k | |
96 | 6.98k | return start_len - in.len; |
97 | 6.98k | } |
98 | | |
99 | | static int encode_string(char *str, struct slice s) |
100 | 1.65k | { |
101 | 1.65k | struct slice start = s; |
102 | 1.65k | int l = strlen(str); |
103 | 1.65k | int n = put_var_int(s, l); |
104 | 1.65k | if (n < 0) { |
105 | 0 | return -1; |
106 | 0 | } |
107 | 1.65k | slice_consume(&s, n); |
108 | 1.65k | if (s.len < l) { |
109 | 0 | return -1; |
110 | 0 | } |
111 | 1.65k | memcpy(s.buf, str, l); |
112 | 1.65k | slice_consume(&s, l); |
113 | 1.65k | |
114 | 1.65k | return start.len - s.len; |
115 | 1.65k | } |
116 | | |
117 | | int encode_key(bool *restart, struct slice dest, struct slice prev_key, |
118 | | struct slice key, byte extra) |
119 | 1.91k | { |
120 | 1.91k | struct slice start = dest; |
121 | 1.91k | int prefix_len = common_prefix_size(prev_key, key); |
122 | 1.91k | uint64_t suffix_len = key.len - prefix_len; |
123 | 1.91k | int n = put_var_int(dest, (uint64_t)prefix_len); |
124 | 1.91k | if (n < 0) { |
125 | 0 | return -1; |
126 | 0 | } |
127 | 1.91k | slice_consume(&dest, n); |
128 | 1.91k | |
129 | 1.91k | *restart = (prefix_len == 0); |
130 | 1.91k | |
131 | 1.91k | n = put_var_int(dest, suffix_len << 3 | (uint64_t)extra); |
132 | 1.91k | if (n < 0) { |
133 | 0 | return -1; |
134 | 0 | } |
135 | 1.91k | slice_consume(&dest, n); |
136 | 1.91k | |
137 | 1.91k | if (dest.len < suffix_len) { |
138 | 43 | return -1; |
139 | 43 | } |
140 | 1.87k | memcpy(dest.buf, key.buf + prefix_len, suffix_len); |
141 | 1.87k | slice_consume(&dest, suffix_len); |
142 | 1.87k | |
143 | 1.87k | return start.len - dest.len; |
144 | 1.87k | } |
145 | | |
146 | | int decode_key(struct slice *key, byte *extra, struct slice last_key, |
147 | | struct slice in) |
148 | 10.7k | { |
149 | 10.7k | int start_len = in.len; |
150 | 10.7k | uint64_t prefix_len = 0; |
151 | 10.7k | uint64_t suffix_len = 0; |
152 | 10.7k | int n = get_var_int(&prefix_len, in); |
153 | 10.7k | if (n < 0) { |
154 | 0 | return -1; |
155 | 0 | } |
156 | 10.7k | slice_consume(&in, n); |
157 | 10.7k | |
158 | 10.7k | if (prefix_len > last_key.len) { |
159 | 0 | return -1; |
160 | 0 | } |
161 | 10.7k | |
162 | 10.7k | n = get_var_int(&suffix_len, in); |
163 | 10.7k | if (n <= 0) { |
164 | 0 | return -1; |
165 | 0 | } |
166 | 10.7k | slice_consume(&in, n); |
167 | 10.7k | |
168 | 10.7k | *extra = (byte)(suffix_len & 0x7); |
169 | 10.7k | suffix_len >>= 3; |
170 | 10.7k | |
171 | 10.7k | if (in.len < suffix_len) { |
172 | 0 | return -1; |
173 | 0 | } |
174 | 10.7k | |
175 | 10.7k | slice_resize(key, suffix_len + prefix_len); |
176 | 10.7k | memcpy(key->buf, last_key.buf, prefix_len); |
177 | 10.7k | |
178 | 10.7k | memcpy(key->buf + prefix_len, in.buf, suffix_len); |
179 | 10.7k | slice_consume(&in, suffix_len); |
180 | 10.7k | |
181 | 10.7k | return start_len - in.len; |
182 | 10.7k | } |
183 | | |
184 | | static void reftable_ref_record_key(const void *r, struct slice *dest) |
185 | 16.3k | { |
186 | 16.3k | const struct reftable_ref_record *rec = |
187 | 16.3k | (const struct reftable_ref_record *)r; |
188 | 16.3k | slice_set_string(dest, rec->ref_name); |
189 | 16.3k | } |
190 | | |
191 | | static void reftable_ref_record_copy_from(void *rec, const void *src_rec, |
192 | | int hash_size) |
193 | 554 | { |
194 | 554 | struct reftable_ref_record *ref = (struct reftable_ref_record *)rec; |
195 | 554 | struct reftable_ref_record *src = (struct reftable_ref_record *)src_rec; |
196 | 554 | assert(hash_size > 0); |
197 | 554 | |
198 | 554 | /* This is simple and correct, but we could probably reuse the hash |
199 | 554 | fields. */ |
200 | 554 | reftable_ref_record_clear(ref); |
201 | 554 | if (src->ref_name != NULL) { |
202 | 554 | ref->ref_name = xstrdup(src->ref_name); |
203 | 554 | } |
204 | 554 | |
205 | 554 | if (src->target != NULL) { |
206 | 536 | ref->target = xstrdup(src->target); |
207 | 536 | } |
208 | 554 | |
209 | 554 | if (src->target_value != NULL) { |
210 | 2 | ref->target_value = reftable_malloc(hash_size); |
211 | 2 | memcpy(ref->target_value, src->target_value, hash_size); |
212 | 2 | } |
213 | 554 | |
214 | 554 | if (src->value != NULL) { |
215 | 12 | ref->value = reftable_malloc(hash_size); |
216 | 12 | memcpy(ref->value, src->value, hash_size); |
217 | 12 | } |
218 | 554 | ref->update_index = src->update_index; |
219 | 554 | } |
220 | | |
221 | | static char hexdigit(int c) |
222 | 0 | { |
223 | 0 | if (c <= 9) { |
224 | 0 | return '0' + c; |
225 | 0 | } |
226 | 0 | return 'a' + (c - 10); |
227 | 0 | } |
228 | | |
229 | | static void hex_format(char *dest, byte *src, int hash_size) |
230 | 0 | { |
231 | 0 | assert(hash_size > 0); |
232 | 0 | if (src != NULL) { |
233 | 0 | int i = 0; |
234 | 0 | for (i = 0; i < hash_size; i++) { |
235 | 0 | dest[2 * i] = hexdigit(src[i] >> 4); |
236 | 0 | dest[2 * i + 1] = hexdigit(src[i] & 0xf); |
237 | 0 | } |
238 | 0 | dest[2 * hash_size] = 0; |
239 | 0 | } |
240 | 0 | } |
241 | | |
242 | | void reftable_ref_record_print(struct reftable_ref_record *ref, |
243 | | uint32_t hash_id) |
244 | 0 | { |
245 | 0 | char hex[SHA256_SIZE + 1] = { 0 }; |
246 | 0 | printf("ref{%s(%" PRIu64 ") ", ref->ref_name, ref->update_index); |
247 | 0 | if (ref->value != NULL) { |
248 | 0 | hex_format(hex, ref->value, hash_size(hash_id)); |
249 | 0 | printf("%s", hex); |
250 | 0 | } |
251 | 0 | if (ref->target_value != NULL) { |
252 | 0 | hex_format(hex, ref->target_value, hash_size(hash_id)); |
253 | 0 | printf(" (T %s)", hex); |
254 | 0 | } |
255 | 0 | if (ref->target != NULL) { |
256 | 0 | printf("=> %s", ref->target); |
257 | 0 | } |
258 | 0 | printf("}\n"); |
259 | 0 | } |
260 | | |
261 | | static void reftable_ref_record_clear_void(void *rec) |
262 | 3.46k | { |
263 | 3.46k | reftable_ref_record_clear((struct reftable_ref_record *)rec); |
264 | 3.46k | } |
265 | | |
266 | | void reftable_ref_record_clear(struct reftable_ref_record *ref) |
267 | 4.76k | { |
268 | 4.76k | reftable_free(ref->ref_name); |
269 | 4.76k | reftable_free(ref->target); |
270 | 4.76k | reftable_free(ref->target_value); |
271 | 4.76k | reftable_free(ref->value); |
272 | 4.76k | memset(ref, 0, sizeof(struct reftable_ref_record)); |
273 | 4.76k | } |
274 | | |
275 | | static byte reftable_ref_record_val_type(const void *rec) |
276 | 1.00k | { |
277 | 1.00k | const struct reftable_ref_record *r = |
278 | 1.00k | (const struct reftable_ref_record *)rec; |
279 | 1.00k | if (r->value != NULL) { |
280 | 454 | if (r->target_value != NULL) { |
281 | 133 | return 2; |
282 | 321 | } else { |
283 | 321 | return 1; |
284 | 321 | } |
285 | 547 | } else if (r->target != NULL) { |
286 | 539 | return 3; |
287 | 539 | } |
288 | 8 | return 0; |
289 | 8 | } |
290 | | |
291 | | static int reftable_ref_record_encode(const void *rec, struct slice s, |
292 | | int hash_size) |
293 | 970 | { |
294 | 970 | const struct reftable_ref_record *r = |
295 | 970 | (const struct reftable_ref_record *)rec; |
296 | 970 | struct slice start = s; |
297 | 970 | int n = put_var_int(s, r->update_index); |
298 | 970 | assert(hash_size > 0); |
299 | 970 | if (n < 0) { |
300 | 0 | return -1; |
301 | 0 | } |
302 | 970 | slice_consume(&s, n); |
303 | 970 | |
304 | 970 | if (r->value != NULL) { |
305 | 424 | if (s.len < hash_size) { |
306 | 28 | return -1; |
307 | 28 | } |
308 | 396 | memcpy(s.buf, r->value, hash_size); |
309 | 396 | slice_consume(&s, hash_size); |
310 | 396 | } |
311 | 970 | |
312 | 970 | if (r->target_value != NULL) { |
313 | 103 | if (s.len < hash_size) { |
314 | 2 | return -1; |
315 | 2 | } |
316 | 101 | memcpy(s.buf, r->target_value, hash_size); |
317 | 101 | slice_consume(&s, hash_size); |
318 | 101 | } |
319 | 942 | |
320 | 942 | if (r->target != NULL) { |
321 | 539 | int n = encode_string(r->target, s); |
322 | 539 | if (n < 0) { |
323 | 0 | return -1; |
324 | 0 | } |
325 | 539 | slice_consume(&s, n); |
326 | 539 | } |
327 | 940 | |
328 | 940 | return start.len - s.len; |
329 | 940 | } |
330 | | |
331 | | static int reftable_ref_record_decode(void *rec, struct slice key, |
332 | | byte val_type, struct slice in, |
333 | | int hash_size) |
334 | 8.29k | { |
335 | 8.29k | struct reftable_ref_record *r = (struct reftable_ref_record *)rec; |
336 | 8.29k | struct slice start = in; |
337 | 8.29k | bool seen_value = false; |
338 | 8.29k | bool seen_target_value = false; |
339 | 8.29k | bool seen_target = false; |
340 | 8.29k | |
341 | 8.29k | int n = get_var_int(&r->update_index, in); |
342 | 8.29k | if (n < 0) { |
343 | 0 | return n; |
344 | 0 | } |
345 | 8.29k | assert(hash_size > 0); |
346 | 8.29k | |
347 | 8.29k | slice_consume(&in, n); |
348 | 8.29k | |
349 | 8.29k | r->ref_name = reftable_realloc(r->ref_name, key.len + 1); |
350 | 8.29k | memcpy(r->ref_name, key.buf, key.len); |
351 | 8.29k | r->ref_name[key.len] = 0; |
352 | 8.29k | |
353 | 8.29k | switch (val_type) { |
354 | 8.29k | case 1: |
355 | 1.81k | case 2: |
356 | 1.81k | if (in.len < hash_size) { |
357 | 0 | return -1; |
358 | 0 | } |
359 | 1.81k | |
360 | 1.81k | if (r->value == NULL) { |
361 | 460 | r->value = reftable_malloc(hash_size); |
362 | 460 | } |
363 | 1.81k | seen_value = true; |
364 | 1.81k | memcpy(r->value, in.buf, hash_size); |
365 | 1.81k | slice_consume(&in, hash_size); |
366 | 1.81k | if (val_type == 1) { |
367 | 1.74k | break; |
368 | 1.74k | } |
369 | 65 | if (r->target_value == NULL) { |
370 | 19 | r->target_value = reftable_malloc(hash_size); |
371 | 19 | } |
372 | 65 | seen_target_value = true; |
373 | 65 | memcpy(r->target_value, in.buf, hash_size); |
374 | 65 | slice_consume(&in, hash_size); |
375 | 65 | break; |
376 | 6.47k | case 3: { |
377 | 6.47k | struct slice dest = { 0 }; |
378 | 6.47k | int n = decode_string(&dest, in); |
379 | 6.47k | if (n < 0) { |
380 | 0 | return -1; |
381 | 0 | } |
382 | 6.47k | slice_consume(&in, n); |
383 | 6.47k | seen_target = true; |
384 | 6.47k | if (r->target != NULL) { |
385 | 4.65k | reftable_free(r->target); |
386 | 4.65k | } |
387 | 6.47k | r->target = (char *)slice_as_string(&dest); |
388 | 6.47k | } break; |
389 | 6.47k | |
390 | 6.47k | case 0: |
391 | 13 | break; |
392 | 6.47k | default: |
393 | 0 | abort(); |
394 | 6.47k | break; |
395 | 8.29k | } |
396 | 8.29k | |
397 | 8.29k | if (!seen_target && r->target != NULL) { |
398 | 3 | FREE_AND_NULL(r->target); |
399 | 3 | } |
400 | 8.29k | if (!seen_target_value && r->target_value != NULL) { |
401 | 3 | FREE_AND_NULL(r->target_value); |
402 | 3 | } |
403 | 8.29k | if (!seen_value && r->value != NULL) { |
404 | 2 | FREE_AND_NULL(r->value); |
405 | 2 | } |
406 | 8.29k | |
407 | 8.29k | return start.len - in.len; |
408 | 8.29k | } |
409 | | |
410 | | static bool reftable_ref_record_is_deletion_void(const void *p) |
411 | 108 | { |
412 | 108 | return reftable_ref_record_is_deletion( |
413 | 108 | (const struct reftable_ref_record *)p); |
414 | 108 | } |
415 | | |
416 | | struct record_vtable reftable_ref_record_vtable = { |
417 | | .key = &reftable_ref_record_key, |
418 | | .type = BLOCK_TYPE_REF, |
419 | | .copy_from = &reftable_ref_record_copy_from, |
420 | | .val_type = &reftable_ref_record_val_type, |
421 | | .encode = &reftable_ref_record_encode, |
422 | | .decode = &reftable_ref_record_decode, |
423 | | .clear = &reftable_ref_record_clear_void, |
424 | | .is_deletion = &reftable_ref_record_is_deletion_void, |
425 | | }; |
426 | | |
427 | | static void obj_record_key(const void *r, struct slice *dest) |
428 | 292 | { |
429 | 292 | const struct obj_record *rec = (const struct obj_record *)r; |
430 | 292 | slice_resize(dest, rec->hash_prefix_len); |
431 | 292 | memcpy(dest->buf, rec->hash_prefix, rec->hash_prefix_len); |
432 | 292 | } |
433 | | |
434 | | static void obj_record_clear(void *rec) |
435 | 15 | { |
436 | 15 | struct obj_record *obj = (struct obj_record *)rec; |
437 | 15 | FREE_AND_NULL(obj->hash_prefix); |
438 | 15 | FREE_AND_NULL(obj->offsets); |
439 | 15 | memset(obj, 0, sizeof(struct obj_record)); |
440 | 15 | } |
441 | | |
442 | | static void obj_record_copy_from(void *rec, const void *src_rec, int hash_size) |
443 | 6 | { |
444 | 6 | struct obj_record *obj = (struct obj_record *)rec; |
445 | 6 | const struct obj_record *src = (const struct obj_record *)src_rec; |
446 | 6 | |
447 | 6 | obj_record_clear(obj); |
448 | 6 | *obj = *src; |
449 | 6 | obj->hash_prefix = reftable_malloc(obj->hash_prefix_len); |
450 | 6 | memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len); |
451 | 6 | |
452 | 6 | { |
453 | 6 | int olen = obj->offset_len * sizeof(uint64_t); |
454 | 6 | obj->offsets = reftable_malloc(olen); |
455 | 6 | memcpy(obj->offsets, src->offsets, olen); |
456 | 6 | } |
457 | 6 | } |
458 | | |
459 | | static byte obj_record_val_type(const void *rec) |
460 | 290 | { |
461 | 290 | struct obj_record *r = (struct obj_record *)rec; |
462 | 290 | if (r->offset_len > 0 && r->offset_len < 8) { |
463 | 288 | return r->offset_len; |
464 | 288 | } |
465 | 2 | return 0; |
466 | 2 | } |
467 | | |
468 | | static int obj_record_encode(const void *rec, struct slice s, int hash_size) |
469 | 290 | { |
470 | 290 | struct obj_record *r = (struct obj_record *)rec; |
471 | 290 | struct slice start = s; |
472 | 290 | int n = 0; |
473 | 290 | if (r->offset_len == 0 || r->offset_len >= 8) { |
474 | 2 | n = put_var_int(s, r->offset_len); |
475 | 2 | if (n < 0) { |
476 | 0 | return -1; |
477 | 0 | } |
478 | 2 | slice_consume(&s, n); |
479 | 2 | } |
480 | 290 | if (r->offset_len == 0) { |
481 | 1 | return start.len - s.len; |
482 | 1 | } |
483 | 289 | n = put_var_int(s, r->offsets[0]); |
484 | 289 | if (n < 0) { |
485 | 0 | return -1; |
486 | 0 | } |
487 | 289 | slice_consume(&s, n); |
488 | 289 | |
489 | 289 | { |
490 | 289 | uint64_t last = r->offsets[0]; |
491 | 289 | int i = 0; |
492 | 367 | for (i = 1; i < r->offset_len; i++) { |
493 | 78 | int n = put_var_int(s, r->offsets[i] - last); |
494 | 78 | if (n < 0) { |
495 | 0 | return -1; |
496 | 0 | } |
497 | 78 | slice_consume(&s, n); |
498 | 78 | last = r->offsets[i]; |
499 | 78 | } |
500 | 289 | } |
501 | 289 | return start.len - s.len; |
502 | 289 | } |
503 | | |
504 | | static int obj_record_decode(void *rec, struct slice key, byte val_type, |
505 | | struct slice in, int hash_size) |
506 | 5 | { |
507 | 5 | struct slice start = in; |
508 | 5 | struct obj_record *r = (struct obj_record *)rec; |
509 | 5 | uint64_t count = val_type; |
510 | 5 | int n = 0; |
511 | 5 | r->hash_prefix = reftable_malloc(key.len); |
512 | 5 | memcpy(r->hash_prefix, key.buf, key.len); |
513 | 5 | r->hash_prefix_len = key.len; |
514 | 5 | |
515 | 5 | if (val_type == 0) { |
516 | 2 | n = get_var_int(&count, in); |
517 | 2 | if (n < 0) { |
518 | 0 | return n; |
519 | 0 | } |
520 | 2 | |
521 | 2 | slice_consume(&in, n); |
522 | 2 | } |
523 | 5 | |
524 | 5 | r->offsets = NULL; |
525 | 5 | r->offset_len = 0; |
526 | 5 | if (count == 0) { |
527 | 1 | return start.len - in.len; |
528 | 1 | } |
529 | 4 | |
530 | 4 | r->offsets = reftable_malloc(count * sizeof(uint64_t)); |
531 | 4 | r->offset_len = count; |
532 | 4 | |
533 | 4 | n = get_var_int(&r->offsets[0], in); |
534 | 4 | if (n < 0) { |
535 | 0 | return n; |
536 | 0 | } |
537 | 4 | slice_consume(&in, n); |
538 | 4 | |
539 | 4 | { |
540 | 4 | uint64_t last = r->offsets[0]; |
541 | 4 | int j = 1; |
542 | 20 | while (j < count) { |
543 | 16 | uint64_t delta = 0; |
544 | 16 | int n = get_var_int(&delta, in); |
545 | 16 | if (n < 0) { |
546 | 0 | return n; |
547 | 0 | } |
548 | 16 | slice_consume(&in, n); |
549 | 16 | |
550 | 16 | last = r->offsets[j] = (delta + last); |
551 | 16 | j++; |
552 | 16 | } |
553 | 4 | } |
554 | 4 | return start.len - in.len; |
555 | 4 | } |
556 | | |
557 | | static bool not_a_deletion(const void *p) |
558 | 0 | { |
559 | 0 | return false; |
560 | 0 | } |
561 | | |
562 | | struct record_vtable obj_record_vtable = { |
563 | | .key = &obj_record_key, |
564 | | .type = BLOCK_TYPE_OBJ, |
565 | | .copy_from = &obj_record_copy_from, |
566 | | .val_type = &obj_record_val_type, |
567 | | .encode = &obj_record_encode, |
568 | | .decode = &obj_record_decode, |
569 | | .clear = &obj_record_clear, |
570 | | .is_deletion = not_a_deletion, |
571 | | }; |
572 | | |
573 | | void reftable_log_record_print(struct reftable_log_record *log, |
574 | | uint32_t hash_id) |
575 | 0 | { |
576 | 0 | char hex[SHA256_SIZE + 1] = { 0 }; |
577 | 0 |
|
578 | 0 | printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n", log->ref_name, |
579 | 0 | log->update_index, log->name, log->email, log->time, |
580 | 0 | log->tz_offset); |
581 | 0 | hex_format(hex, log->old_hash, hash_size(hash_id)); |
582 | 0 | printf("%s => ", hex); |
583 | 0 | hex_format(hex, log->new_hash, hash_size(hash_id)); |
584 | 0 | printf("%s\n\n%s\n}\n", hex, log->message); |
585 | 0 | } |
586 | | |
587 | | static void reftable_log_record_key(const void *r, struct slice *dest) |
588 | 1.49k | { |
589 | 1.49k | const struct reftable_log_record *rec = |
590 | 1.49k | (const struct reftable_log_record *)r; |
591 | 1.49k | int len = strlen(rec->ref_name); |
592 | 1.49k | uint64_t ts = 0; |
593 | 1.49k | slice_resize(dest, len + 9); |
594 | 1.49k | memcpy(dest->buf, rec->ref_name, len + 1); |
595 | 1.49k | ts = (~ts) - rec->update_index; |
596 | 1.49k | put_be64(dest->buf + 1 + len, ts); |
597 | 1.49k | } |
598 | | |
599 | | static void reftable_log_record_copy_from(void *rec, const void *src_rec, |
600 | | int hash_size) |
601 | 122 | { |
602 | 122 | struct reftable_log_record *dst = (struct reftable_log_record *)rec; |
603 | 122 | const struct reftable_log_record *src = |
604 | 122 | (const struct reftable_log_record *)src_rec; |
605 | 122 | |
606 | 122 | reftable_log_record_clear(dst); |
607 | 122 | *dst = *src; |
608 | 122 | if (dst->ref_name != NULL) { |
609 | 122 | dst->ref_name = xstrdup(dst->ref_name); |
610 | 122 | } |
611 | 122 | if (dst->email != NULL) { |
612 | 118 | dst->email = xstrdup(dst->email); |
613 | 118 | } |
614 | 122 | if (dst->name != NULL) { |
615 | 118 | dst->name = xstrdup(dst->name); |
616 | 118 | } |
617 | 122 | if (dst->message != NULL) { |
618 | 118 | dst->message = xstrdup(dst->message); |
619 | 118 | } |
620 | 122 | |
621 | 122 | if (dst->new_hash != NULL) { |
622 | 118 | dst->new_hash = reftable_malloc(hash_size); |
623 | 118 | memcpy(dst->new_hash, src->new_hash, hash_size); |
624 | 118 | } |
625 | 122 | if (dst->old_hash != NULL) { |
626 | 118 | dst->old_hash = reftable_malloc(hash_size); |
627 | 118 | memcpy(dst->old_hash, src->old_hash, hash_size); |
628 | 118 | } |
629 | 122 | } |
630 | | |
631 | | static void reftable_log_record_clear_void(void *rec) |
632 | 407 | { |
633 | 407 | struct reftable_log_record *r = (struct reftable_log_record *)rec; |
634 | 407 | reftable_log_record_clear(r); |
635 | 407 | } |
636 | | |
637 | | void reftable_log_record_clear(struct reftable_log_record *r) |
638 | 632 | { |
639 | 632 | reftable_free(r->ref_name); |
640 | 632 | reftable_free(r->new_hash); |
641 | 632 | reftable_free(r->old_hash); |
642 | 632 | reftable_free(r->name); |
643 | 632 | reftable_free(r->email); |
644 | 632 | reftable_free(r->message); |
645 | 632 | memset(r, 0, sizeof(struct reftable_log_record)); |
646 | 632 | } |
647 | | |
648 | | static byte reftable_log_record_val_type(const void *rec) |
649 | 464 | { |
650 | 464 | const struct reftable_log_record *log = |
651 | 464 | (const struct reftable_log_record *)rec; |
652 | 464 | |
653 | 464 | return reftable_log_record_is_deletion(log) ? 0 : 1; |
654 | 464 | } |
655 | | |
656 | | static byte zero[SHA256_SIZE] = { 0 }; |
657 | | |
658 | | static int reftable_log_record_encode(const void *rec, struct slice s, |
659 | | int hash_size) |
660 | 463 | { |
661 | 463 | struct reftable_log_record *r = (struct reftable_log_record *)rec; |
662 | 463 | struct slice start = s; |
663 | 463 | int n = 0; |
664 | 463 | byte *oldh = r->old_hash; |
665 | 463 | byte *newh = r->new_hash; |
666 | 463 | if (reftable_log_record_is_deletion(r)) { |
667 | 2 | return 0; |
668 | 2 | } |
669 | 461 | |
670 | 461 | if (oldh == NULL) { |
671 | 361 | oldh = zero; |
672 | 361 | } |
673 | 461 | if (newh == NULL) { |
674 | 0 | newh = zero; |
675 | 0 | } |
676 | 461 | |
677 | 461 | if (s.len < 2 * hash_size) { |
678 | 88 | return -1; |
679 | 88 | } |
680 | 373 | |
681 | 373 | memcpy(s.buf, oldh, hash_size); |
682 | 373 | memcpy(s.buf + hash_size, newh, hash_size); |
683 | 373 | slice_consume(&s, 2 * hash_size); |
684 | 373 | |
685 | 373 | n = encode_string(r->name ? r->name : "", s); |
686 | 373 | if (n < 0) { |
687 | 0 | return -1; |
688 | 0 | } |
689 | 373 | slice_consume(&s, n); |
690 | 373 | |
691 | 373 | n = encode_string(r->email ? r->email : "", s); |
692 | 373 | if (n < 0) { |
693 | 0 | return -1; |
694 | 0 | } |
695 | 373 | slice_consume(&s, n); |
696 | 373 | |
697 | 373 | n = put_var_int(s, r->time); |
698 | 373 | if (n < 0) { |
699 | 0 | return -1; |
700 | 0 | } |
701 | 373 | slice_consume(&s, n); |
702 | 373 | |
703 | 373 | if (s.len < 2) { |
704 | 0 | return -1; |
705 | 0 | } |
706 | 373 | |
707 | 373 | put_be16(s.buf, r->tz_offset); |
708 | 373 | slice_consume(&s, 2); |
709 | 373 | |
710 | 373 | n = encode_string(r->message ? r->message : "", s); |
711 | 373 | if (n < 0) { |
712 | 0 | return -1; |
713 | 0 | } |
714 | 373 | slice_consume(&s, n); |
715 | 373 | |
716 | 373 | return start.len - s.len; |
717 | 373 | } |
718 | | |
719 | | static int reftable_log_record_decode(void *rec, struct slice key, |
720 | | byte val_type, struct slice in, |
721 | | int hash_size) |
722 | 175 | { |
723 | 175 | struct slice start = in; |
724 | 175 | struct reftable_log_record *r = (struct reftable_log_record *)rec; |
725 | 175 | uint64_t max = 0; |
726 | 175 | uint64_t ts = 0; |
727 | 175 | struct slice dest = { 0 }; |
728 | 175 | int n; |
729 | 175 | |
730 | 175 | if (key.len <= 9 || key.buf[key.len - 9] != 0) { |
731 | 0 | return REFTABLE_FORMAT_ERROR; |
732 | 0 | } |
733 | 175 | |
734 | 175 | r->ref_name = reftable_realloc(r->ref_name, key.len - 8); |
735 | 175 | memcpy(r->ref_name, key.buf, key.len - 8); |
736 | 175 | ts = get_be64(key.buf + key.len - 8); |
737 | 175 | |
738 | 175 | r->update_index = (~max) - ts; |
739 | 175 | |
740 | 175 | if (val_type == 0) { |
741 | 5 | FREE_AND_NULL(r->old_hash); |
742 | 5 | FREE_AND_NULL(r->new_hash); |
743 | 5 | FREE_AND_NULL(r->message); |
744 | 5 | FREE_AND_NULL(r->email); |
745 | 5 | FREE_AND_NULL(r->name); |
746 | 5 | return 0; |
747 | 5 | } |
748 | 170 | |
749 | 170 | if (in.len < 2 * hash_size) { |
750 | 0 | return REFTABLE_FORMAT_ERROR; |
751 | 0 | } |
752 | 170 | |
753 | 170 | r->old_hash = reftable_realloc(r->old_hash, hash_size); |
754 | 170 | r->new_hash = reftable_realloc(r->new_hash, hash_size); |
755 | 170 | |
756 | 170 | memcpy(r->old_hash, in.buf, hash_size); |
757 | 170 | memcpy(r->new_hash, in.buf + hash_size, hash_size); |
758 | 170 | |
759 | 170 | slice_consume(&in, 2 * hash_size); |
760 | 170 | |
761 | 170 | n = decode_string(&dest, in); |
762 | 170 | if (n < 0) { |
763 | 0 | goto error; |
764 | 0 | } |
765 | 170 | slice_consume(&in, n); |
766 | 170 | |
767 | 170 | r->name = reftable_realloc(r->name, dest.len + 1); |
768 | 170 | memcpy(r->name, dest.buf, dest.len); |
769 | 170 | r->name[dest.len] = 0; |
770 | 170 | |
771 | 170 | slice_resize(&dest, 0); |
772 | 170 | n = decode_string(&dest, in); |
773 | 170 | if (n < 0) { |
774 | 0 | goto error; |
775 | 0 | } |
776 | 170 | slice_consume(&in, n); |
777 | 170 | |
778 | 170 | r->email = reftable_realloc(r->email, dest.len + 1); |
779 | 170 | memcpy(r->email, dest.buf, dest.len); |
780 | 170 | r->email[dest.len] = 0; |
781 | 170 | |
782 | 170 | ts = 0; |
783 | 170 | n = get_var_int(&ts, in); |
784 | 170 | if (n < 0) { |
785 | 0 | goto error; |
786 | 0 | } |
787 | 170 | slice_consume(&in, n); |
788 | 170 | r->time = ts; |
789 | 170 | if (in.len < 2) { |
790 | 0 | goto error; |
791 | 0 | } |
792 | 170 | |
793 | 170 | r->tz_offset = get_be16(in.buf); |
794 | 170 | slice_consume(&in, 2); |
795 | 170 | |
796 | 170 | slice_resize(&dest, 0); |
797 | 170 | n = decode_string(&dest, in); |
798 | 170 | if (n < 0) { |
799 | 0 | goto error; |
800 | 0 | } |
801 | 170 | slice_consume(&in, n); |
802 | 170 | |
803 | 170 | r->message = reftable_realloc(r->message, dest.len + 1); |
804 | 170 | memcpy(r->message, dest.buf, dest.len); |
805 | 170 | r->message[dest.len] = 0; |
806 | 170 | |
807 | 170 | slice_clear(&dest); |
808 | 170 | return start.len - in.len; |
809 | 0 | |
810 | 0 | error: |
811 | 0 | slice_clear(&dest); |
812 | 0 | return REFTABLE_FORMAT_ERROR; |
813 | 170 | } |
814 | | |
815 | | static bool null_streq(char *a, char *b) |
816 | 24 | { |
817 | 24 | char *empty = ""; |
818 | 24 | if (a == NULL) { |
819 | 12 | a = empty; |
820 | 12 | } |
821 | 24 | if (b == NULL) { |
822 | 16 | b = empty; |
823 | 16 | } |
824 | 24 | return 0 == strcmp(a, b); |
825 | 24 | } |
826 | | |
827 | | static bool zero_hash_eq(byte *a, byte *b, int sz) |
828 | 16 | { |
829 | 16 | if (a == NULL) { |
830 | 8 | a = zero; |
831 | 8 | } |
832 | 16 | if (b == NULL) { |
833 | 10 | b = zero; |
834 | 10 | } |
835 | 16 | return !memcmp(a, b, sz); |
836 | 16 | } |
837 | | |
838 | | bool reftable_log_record_equal(struct reftable_log_record *a, |
839 | | struct reftable_log_record *b, int hash_size) |
840 | 8 | { |
841 | 8 | return null_streq(a->name, b->name) && null_streq(a->email, b->email) && |
842 | 8 | null_streq(a->message, b->message) && |
843 | 8 | zero_hash_eq(a->old_hash, b->old_hash, hash_size) && |
844 | 8 | zero_hash_eq(a->new_hash, b->new_hash, hash_size) && |
845 | 8 | a->time == b->time && a->tz_offset == b->tz_offset && |
846 | 8 | a->update_index == b->update_index; |
847 | 8 | } |
848 | | |
849 | | static bool reftable_log_record_is_deletion_void(const void *p) |
850 | 7 | { |
851 | 7 | return reftable_log_record_is_deletion( |
852 | 7 | (const struct reftable_log_record *)p); |
853 | 7 | } |
854 | | |
855 | | struct record_vtable reftable_log_record_vtable = { |
856 | | .key = &reftable_log_record_key, |
857 | | .type = BLOCK_TYPE_LOG, |
858 | | .copy_from = &reftable_log_record_copy_from, |
859 | | .val_type = &reftable_log_record_val_type, |
860 | | .encode = &reftable_log_record_encode, |
861 | | .decode = &reftable_log_record_decode, |
862 | | .clear = &reftable_log_record_clear_void, |
863 | | .is_deletion = &reftable_log_record_is_deletion_void, |
864 | | }; |
865 | | |
866 | | struct record new_record(byte typ) |
867 | 4.00k | { |
868 | 4.00k | struct record rec = { NULL }; |
869 | 4.00k | switch (typ) { |
870 | 4.00k | case BLOCK_TYPE_REF: { |
871 | 3.48k | struct reftable_ref_record *r = |
872 | 3.48k | reftable_calloc(sizeof(struct reftable_ref_record)); |
873 | 3.48k | record_from_ref(&rec, r); |
874 | 3.48k | return rec; |
875 | 4.00k | } |
876 | 4.00k | |
877 | 4.00k | case BLOCK_TYPE_OBJ: { |
878 | 5 | struct obj_record *r = |
879 | 5 | reftable_calloc(sizeof(struct obj_record)); |
880 | 5 | record_from_obj(&rec, r); |
881 | 5 | return rec; |
882 | 4.00k | } |
883 | 4.00k | case BLOCK_TYPE_LOG: { |
884 | 405 | struct reftable_log_record *r = |
885 | 405 | reftable_calloc(sizeof(struct reftable_log_record)); |
886 | 405 | record_from_log(&rec, r); |
887 | 405 | return rec; |
888 | 4.00k | } |
889 | 4.00k | case BLOCK_TYPE_INDEX: { |
890 | 109 | struct index_record *r = |
891 | 109 | reftable_calloc(sizeof(struct index_record)); |
892 | 109 | record_from_index(&rec, r); |
893 | 109 | return rec; |
894 | 0 | } |
895 | 0 | } |
896 | 0 | abort(); |
897 | 0 | return rec; |
898 | 0 | } |
899 | | |
900 | | void *record_yield(struct record *rec) |
901 | 3.97k | { |
902 | 3.97k | void *p = rec->data; |
903 | 3.97k | rec->data = NULL; |
904 | 3.97k | return p; |
905 | 3.97k | } |
906 | | |
907 | | void record_destroy(struct record *rec) |
908 | 3.97k | { |
909 | 3.97k | record_clear(*rec); |
910 | 3.97k | reftable_free(record_yield(rec)); |
911 | 3.97k | } |
912 | | |
913 | | static void index_record_key(const void *r, struct slice *dest) |
914 | 406 | { |
915 | 406 | struct index_record *rec = (struct index_record *)r; |
916 | 406 | slice_copy(dest, rec->last_key); |
917 | 406 | } |
918 | | |
919 | | static void index_record_copy_from(void *rec, const void *src_rec, |
920 | | int hash_size) |
921 | 2 | { |
922 | 2 | struct index_record *dst = (struct index_record *)rec; |
923 | 2 | struct index_record *src = (struct index_record *)src_rec; |
924 | 2 | |
925 | 2 | slice_copy(&dst->last_key, src->last_key); |
926 | 2 | dst->offset = src->offset; |
927 | 2 | } |
928 | | |
929 | | static void index_record_clear(void *rec) |
930 | 218 | { |
931 | 218 | struct index_record *idx = (struct index_record *)rec; |
932 | 218 | slice_clear(&idx->last_key); |
933 | 218 | } |
934 | | |
935 | | static byte index_record_val_type(const void *rec) |
936 | 172 | { |
937 | 172 | return 0; |
938 | 172 | } |
939 | | |
940 | | static int index_record_encode(const void *rec, struct slice out, int hash_size) |
941 | 161 | { |
942 | 161 | const struct index_record *r = (const struct index_record *)rec; |
943 | 161 | struct slice start = out; |
944 | 161 | |
945 | 161 | int n = put_var_int(out, r->offset); |
946 | 161 | if (n < 0) { |
947 | 0 | return n; |
948 | 0 | } |
949 | 161 | |
950 | 161 | slice_consume(&out, n); |
951 | 161 | |
952 | 161 | return start.len - out.len; |
953 | 161 | } |
954 | | |
955 | | static int index_record_decode(void *rec, struct slice key, byte val_type, |
956 | | struct slice in, int hash_size) |
957 | 233 | { |
958 | 233 | struct slice start = in; |
959 | 233 | struct index_record *r = (struct index_record *)rec; |
960 | 233 | int n = 0; |
961 | 233 | |
962 | 233 | slice_copy(&r->last_key, key); |
963 | 233 | |
964 | 233 | n = get_var_int(&r->offset, in); |
965 | 233 | if (n < 0) { |
966 | 0 | return n; |
967 | 0 | } |
968 | 233 | |
969 | 233 | slice_consume(&in, n); |
970 | 233 | return start.len - in.len; |
971 | 233 | } |
972 | | |
973 | | struct record_vtable index_record_vtable = { |
974 | | .key = &index_record_key, |
975 | | .type = BLOCK_TYPE_INDEX, |
976 | | .copy_from = &index_record_copy_from, |
977 | | .val_type = &index_record_val_type, |
978 | | .encode = &index_record_encode, |
979 | | .decode = &index_record_decode, |
980 | | .clear = &index_record_clear, |
981 | | .is_deletion = ¬_a_deletion, |
982 | | }; |
983 | | |
984 | | void record_key(struct record rec, struct slice *dest) |
985 | 18.5k | { |
986 | 18.5k | rec.ops->key(rec.data, dest); |
987 | 18.5k | } |
988 | | |
989 | | byte record_type(struct record rec) |
990 | 9.97k | { |
991 | 9.97k | return rec.ops->type; |
992 | 9.97k | } |
993 | | |
994 | | int record_encode(struct record rec, struct slice dest, int hash_size) |
995 | 1.88k | { |
996 | 1.88k | return rec.ops->encode(rec.data, dest, hash_size); |
997 | 1.88k | } |
998 | | |
999 | | void record_copy_from(struct record rec, struct record src, int hash_size) |
1000 | 684 | { |
1001 | 684 | assert(src.ops->type == rec.ops->type); |
1002 | 684 | |
1003 | 684 | rec.ops->copy_from(rec.data, src.data, hash_size); |
1004 | 684 | } |
1005 | | |
1006 | | byte record_val_type(struct record rec) |
1007 | 1.92k | { |
1008 | 1.92k | return rec.ops->val_type(rec.data); |
1009 | 1.92k | } |
1010 | | |
1011 | | int record_decode(struct record rec, struct slice key, byte extra, |
1012 | | struct slice src, int hash_size) |
1013 | 8.71k | { |
1014 | 8.71k | return rec.ops->decode(rec.data, key, extra, src, hash_size); |
1015 | 8.71k | } |
1016 | | |
1017 | | void record_clear(struct record rec) |
1018 | 4.10k | { |
1019 | 4.10k | rec.ops->clear(rec.data); |
1020 | 4.10k | } |
1021 | | |
1022 | | bool record_is_deletion(struct record rec) |
1023 | 115 | { |
1024 | 115 | return rec.ops->is_deletion(rec.data); |
1025 | 115 | } |
1026 | | |
1027 | | void record_from_ref(struct record *rec, struct reftable_ref_record *ref_rec) |
1028 | 6.25k | { |
1029 | 6.25k | assert(rec->ops == NULL); |
1030 | 6.25k | rec->data = ref_rec; |
1031 | 6.25k | rec->ops = &reftable_ref_record_vtable; |
1032 | 6.25k | } |
1033 | | |
1034 | | void record_from_obj(struct record *rec, struct obj_record *obj_rec) |
1035 | 295 | { |
1036 | 295 | assert(rec->ops == NULL); |
1037 | 295 | rec->data = obj_rec; |
1038 | 295 | rec->ops = &obj_record_vtable; |
1039 | 295 | } |
1040 | | |
1041 | | void record_from_index(struct record *rec, struct index_record *index_rec) |
1042 | 379 | { |
1043 | 379 | assert(rec->ops == NULL); |
1044 | 379 | rec->data = index_rec; |
1045 | 379 | rec->ops = &index_record_vtable; |
1046 | 379 | } |
1047 | | |
1048 | | void record_from_log(struct record *rec, struct reftable_log_record *log_rec) |
1049 | 1.04k | { |
1050 | 1.04k | assert(rec->ops == NULL); |
1051 | 1.04k | rec->data = log_rec; |
1052 | 1.04k | rec->ops = &reftable_log_record_vtable; |
1053 | 1.04k | } |
1054 | | |
1055 | | struct reftable_ref_record *record_as_ref(struct record rec) |
1056 | 60 | { |
1057 | 60 | assert(record_type(rec) == BLOCK_TYPE_REF); |
1058 | 60 | return (struct reftable_ref_record *)rec.data; |
1059 | 60 | } |
1060 | | |
1061 | | struct reftable_log_record *record_as_log(struct record rec) |
1062 | 4 | { |
1063 | 4 | assert(record_type(rec) == BLOCK_TYPE_LOG); |
1064 | 4 | return (struct reftable_log_record *)rec.data; |
1065 | 4 | } |
1066 | | |
1067 | | static bool hash_equal(byte *a, byte *b, int hash_size) |
1068 | 20 | { |
1069 | 20 | if (a != NULL && b != NULL) { |
1070 | 8 | return !memcmp(a, b, hash_size); |
1071 | 8 | } |
1072 | 12 | |
1073 | 12 | return a == b; |
1074 | 12 | } |
1075 | | |
1076 | | static bool str_equal(char *a, char *b) |
1077 | 10 | { |
1078 | 10 | if (a != NULL && b != NULL) { |
1079 | 1 | return 0 == strcmp(a, b); |
1080 | 1 | } |
1081 | 9 | |
1082 | 9 | return a == b; |
1083 | 9 | } |
1084 | | |
1085 | | bool reftable_ref_record_equal(struct reftable_ref_record *a, |
1086 | | struct reftable_ref_record *b, int hash_size) |
1087 | 10 | { |
1088 | 10 | assert(hash_size > 0); |
1089 | 10 | return 0 == strcmp(a->ref_name, b->ref_name) && |
1090 | 10 | a->update_index == b->update_index && |
1091 | 10 | hash_equal(a->value, b->value, hash_size) && |
1092 | 10 | hash_equal(a->target_value, b->target_value, hash_size) && |
1093 | 10 | str_equal(a->target, b->target); |
1094 | 10 | } |
1095 | | |
1096 | | int reftable_ref_record_compare_name(const void *a, const void *b) |
1097 | 0 | { |
1098 | 0 | return strcmp(((struct reftable_ref_record *)a)->ref_name, |
1099 | 0 | ((struct reftable_ref_record *)b)->ref_name); |
1100 | 0 | } |
1101 | | |
1102 | | bool reftable_ref_record_is_deletion(const struct reftable_ref_record *ref) |
1103 | 450 | { |
1104 | 450 | return ref->value == NULL && ref->target == NULL && |
1105 | 450 | ref->target_value == NULL; |
1106 | 450 | } |
1107 | | |
1108 | | int reftable_log_record_compare_key(const void *a, const void *b) |
1109 | 0 | { |
1110 | 0 | struct reftable_log_record *la = (struct reftable_log_record *)a; |
1111 | 0 | struct reftable_log_record *lb = (struct reftable_log_record *)b; |
1112 | 0 |
|
1113 | 0 | int cmp = strcmp(la->ref_name, lb->ref_name); |
1114 | 0 | if (cmp) { |
1115 | 0 | return cmp; |
1116 | 0 | } |
1117 | 0 | if (la->update_index > lb->update_index) { |
1118 | 0 | return -1; |
1119 | 0 | } |
1120 | 0 | return (la->update_index < lb->update_index) ? 1 : 0; |
1121 | 0 | } |
1122 | | |
1123 | | bool reftable_log_record_is_deletion(const struct reftable_log_record *log) |
1124 | 1.04k | { |
1125 | 1.04k | return (log->new_hash == NULL && log->old_hash == NULL && |
1126 | 1.04k | log->name == NULL && log->email == NULL && |
1127 | 1.04k | log->message == NULL && log->time == 0 && log->tz_offset == 0 && |
1128 | 1.04k | log->message == NULL); |
1129 | 1.04k | } |
1130 | | |
1131 | | int hash_size(uint32_t id) |
1132 | 3.99k | { |
1133 | 3.99k | switch (id) { |
1134 | 3.99k | case 0: |
1135 | 3.60k | case SHA1_ID: |
1136 | 3.60k | return SHA1_SIZE; |
1137 | 3.60k | case SHA256_ID: |
1138 | 385 | return SHA256_SIZE; |
1139 | 0 | } |
1140 | 0 | abort(); |
1141 | 0 | } |