Raw
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 #include "constants.h"
15 #include "reftable-error.h"
16 #include "basics.h"
17
18 static struct reftable_record_vtable *
19 reftable_record_vtable(struct reftable_record *rec);
20 static void *reftable_record_data(struct reftable_record *rec);
21
22 int get_var_int(uint64_t *dest, struct string_view *in)
23 {
24 const unsigned char *buf = in->buf;
25 unsigned char c;
26 uint64_t val;
27
28 if (!in->len)
29 return -1;
30 c = *buf++;
31 val = c & 0x7f;
32
33 while (c & 0x80) {
34 /*
35 * We use a micro-optimization here: whenever we see that the
36 * 0x80 bit is set, we know that the remainder of the value
37 * cannot be 0. The zero-values thus doesn't need to be encoded
38 * at all, which is why we subtract 1 when encoding and add 1
39 * when decoding.
40 *
41 * This allows us to save a byte in some edge cases.
42 */
43 val += 1;
44 if (!val || (val & (uint64_t)(~0ULL << (64 - 7))))
45 return -1; /* overflow */
46 if (buf >= in->buf + in->len)
47 return -1;
48 c = *buf++;
49 val = (val << 7) + (c & 0x7f);
50 }
51
52 *dest = val;
53 return buf - in->buf;
54 }
55
56 int put_var_int(struct string_view *dest, uint64_t value)
57 {
58 unsigned char varint[10];
59 unsigned pos = sizeof(varint) - 1;
60 varint[pos] = value & 0x7f;
61 while (value >>= 7)
62 varint[--pos] = 0x80 | (--value & 0x7f);
63 if (dest->len < sizeof(varint) - pos)
64 return REFTABLE_ENTRY_TOO_BIG_ERROR;
65 memcpy(dest->buf, varint + pos, sizeof(varint) - pos);
66 return sizeof(varint) - pos;
67 }
68
69 int reftable_is_block_type(uint8_t typ)
70 {
71 switch (typ) {
72 case REFTABLE_BLOCK_TYPE_REF:
73 case REFTABLE_BLOCK_TYPE_LOG:
74 case REFTABLE_BLOCK_TYPE_OBJ:
75 case REFTABLE_BLOCK_TYPE_INDEX:
76 return 1;
77 }
78 return 0;
79 }
80
81 const unsigned char *reftable_ref_record_val1(const struct reftable_ref_record *rec)
82 {
83 switch (rec->value_type) {
84 case REFTABLE_REF_VAL1:
85 return rec->value.val1;
86 case REFTABLE_REF_VAL2:
87 return rec->value.val2.value;
88 default:
89 return NULL;
90 }
91 }
92
93 const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record *rec)
94 {
95 switch (rec->value_type) {
96 case REFTABLE_REF_VAL2:
97 return rec->value.val2.target_value;
98 default:
99 return NULL;
100 }
101 }
102
103 static int decode_string(struct reftable_buf *dest, struct string_view in)
104 {
105 int start_len = in.len;
106 uint64_t tsize = 0;
107 int n, err;
108
109 n = get_var_int(&tsize, &in);
110 if (n <= 0)
111 return -1;
112 string_view_consume(&in, n);
113 if (in.len < tsize)
114 return -1;
115
116 reftable_buf_reset(dest);
117 err = reftable_buf_add(dest, in.buf, tsize);
118 if (err < 0)
119 return err;
120
121 string_view_consume(&in, tsize);
122
123 return start_len - in.len;
124 }
125
126 static int encode_string(const char *str, struct string_view s)
127 {
128 struct string_view start = s;
129 size_t l = strlen(str);
130 int n = put_var_int(&s, l);
131 if (n < 0)
132 return n;
133 string_view_consume(&s, n);
134 if (s.len < l)
135 return REFTABLE_ENTRY_TOO_BIG_ERROR;
136 memcpy(s.buf, str, l);
137 string_view_consume(&s, l);
138
139 return start.len - s.len;
140 }
141
142 int reftable_encode_key(int *restart, struct string_view dest,
143 struct reftable_buf prev_key, struct reftable_buf key,
144 uint8_t extra)
145 {
146 struct string_view start = dest;
147 size_t prefix_len = common_prefix_size(&prev_key, &key);
148 uint64_t suffix_len = key.len - prefix_len;
149 int n = put_var_int(&dest, prefix_len);
150 if (n < 0)
151 return n;
152 string_view_consume(&dest, n);
153
154 *restart = (prefix_len == 0);
155
156 n = put_var_int(&dest, suffix_len << 3 | (uint64_t)extra);
157 if (n < 0)
158 return n;
159 string_view_consume(&dest, n);
160
161 if (dest.len < suffix_len)
162 return REFTABLE_ENTRY_TOO_BIG_ERROR;
163 memcpy(dest.buf, key.buf + prefix_len, suffix_len);
164 string_view_consume(&dest, suffix_len);
165
166 return start.len - dest.len;
167 }
168
169 int reftable_decode_keylen(struct string_view in,
170 uint64_t *prefix_len,
171 uint64_t *suffix_len,
172 uint8_t *extra)
173 {
174 size_t start_len = in.len;
175 int n;
176
177 n = get_var_int(prefix_len, &in);
178 if (n < 0)
179 return -1;
180 string_view_consume(&in, n);
181
182 n = get_var_int(suffix_len, &in);
183 if (n <= 0)
184 return -1;
185 string_view_consume(&in, n);
186
187 *extra = (uint8_t)(*suffix_len & 0x7);
188 *suffix_len >>= 3;
189
190 return start_len - in.len;
191 }
192
193 int reftable_decode_key(struct reftable_buf *last_key, uint8_t *extra,
194 struct string_view in)
195 {
196 int start_len = in.len;
197 uint64_t prefix_len = 0;
198 uint64_t suffix_len = 0;
199 int err, n;
200
201 n = reftable_decode_keylen(in, &prefix_len, &suffix_len, extra);
202 if (n < 0)
203 return -1;
204 string_view_consume(&in, n);
205
206 if (in.len < suffix_len ||
207 prefix_len > last_key->len)
208 return -1;
209
210 err = reftable_buf_setlen(last_key, prefix_len);
211 if (err < 0)
212 return err;
213
214 err = reftable_buf_add(last_key, in.buf, suffix_len);
215 if (err < 0)
216 return err;
217
218 string_view_consume(&in, suffix_len);
219
220 return start_len - in.len;
221 }
222
223 static int reftable_ref_record_key(const void *r, struct reftable_buf *dest)
224 {
225 const struct reftable_ref_record *rec =
226 (const struct reftable_ref_record *)r;
227 reftable_buf_reset(dest);
228 return reftable_buf_addstr(dest, rec->refname);
229 }
230
231 static int reftable_ref_record_copy_from(void *rec, const void *src_rec,
232 uint32_t hash_size)
233 {
234 struct reftable_ref_record *ref = rec;
235 const struct reftable_ref_record *src = src_rec;
236 char *refname = NULL;
237 size_t refname_cap = 0;
238 int err;
239
240 REFTABLE_SWAP(refname, ref->refname);
241 REFTABLE_SWAP(refname_cap, ref->refname_cap);
242 reftable_ref_record_release(ref);
243 REFTABLE_SWAP(ref->refname, refname);
244 REFTABLE_SWAP(ref->refname_cap, refname_cap);
245
246 if (src->refname) {
247 size_t refname_len = strlen(src->refname);
248
249 REFTABLE_ALLOC_GROW_OR_NULL(ref->refname, refname_len + 1,
250 ref->refname_cap);
251 if (!ref->refname) {
252 err = REFTABLE_OUT_OF_MEMORY_ERROR;
253 goto out;
254 }
255
256 memcpy(ref->refname, src->refname, refname_len);
257 ref->refname[refname_len] = 0;
258 }
259
260 ref->update_index = src->update_index;
261 ref->value_type = src->value_type;
262 switch (src->value_type) {
263 case REFTABLE_REF_DELETION:
264 break;
265 case REFTABLE_REF_VAL1:
266 memcpy(ref->value.val1, src->value.val1, hash_size);
267 break;
268 case REFTABLE_REF_VAL2:
269 memcpy(ref->value.val2.value, src->value.val2.value, hash_size);
270 memcpy(ref->value.val2.target_value,
271 src->value.val2.target_value, hash_size);
272 break;
273 case REFTABLE_REF_SYMREF:
274 ref->value.symref = reftable_strdup(src->value.symref);
275 if (!ref->value.symref) {
276 err = REFTABLE_OUT_OF_MEMORY_ERROR;
277 goto out;
278 }
279 break;
280 }
281
282 err = 0;
283 out:
284 return err;
285 }
286
287 static void reftable_ref_record_release_void(void *rec)
288 {
289 reftable_ref_record_release(rec);
290 }
291
292 void reftable_ref_record_release(struct reftable_ref_record *ref)
293 {
294 switch (ref->value_type) {
295 case REFTABLE_REF_SYMREF:
296 reftable_free(ref->value.symref);
297 break;
298 case REFTABLE_REF_VAL2:
299 break;
300 case REFTABLE_REF_VAL1:
301 break;
302 case REFTABLE_REF_DELETION:
303 break;
304 default:
305 abort();
306 }
307
308 reftable_free(ref->refname);
309 memset(ref, 0, sizeof(struct reftable_ref_record));
310 }
311
312 static uint8_t reftable_ref_record_val_type(const void *rec)
313 {
314 const struct reftable_ref_record *r =
315 (const struct reftable_ref_record *)rec;
316 return r->value_type;
317 }
318
319 static int reftable_ref_record_encode(const void *rec, struct string_view s,
320 uint32_t hash_size)
321 {
322 const struct reftable_ref_record *r =
323 (const struct reftable_ref_record *)rec;
324 struct string_view start = s;
325 int n = put_var_int(&s, r->update_index);
326 if (n < 0)
327 return n;
328 string_view_consume(&s, n);
329
330 switch (r->value_type) {
331 case REFTABLE_REF_SYMREF:
332 n = encode_string(r->value.symref, s);
333 if (n < 0)
334 return n;
335 string_view_consume(&s, n);
336 break;
337 case REFTABLE_REF_VAL2:
338 if (s.len < 2 * hash_size)
339 return REFTABLE_ENTRY_TOO_BIG_ERROR;
340 memcpy(s.buf, r->value.val2.value, hash_size);
341 string_view_consume(&s, hash_size);
342 memcpy(s.buf, r->value.val2.target_value, hash_size);
343 string_view_consume(&s, hash_size);
344 break;
345 case REFTABLE_REF_VAL1:
346 if (s.len < hash_size)
347 return REFTABLE_ENTRY_TOO_BIG_ERROR;
348 memcpy(s.buf, r->value.val1, hash_size);
349 string_view_consume(&s, hash_size);
350 break;
351 case REFTABLE_REF_DELETION:
352 break;
353 default:
354 abort();
355 }
356
357 return start.len - s.len;
358 }
359
360 static int reftable_ref_record_decode(void *rec, struct reftable_buf key,
361 uint8_t val_type, struct string_view in,
362 uint32_t hash_size, struct reftable_buf *scratch)
363 {
364 struct reftable_ref_record *r = rec;
365 struct string_view start = in;
366 uint64_t update_index = 0;
367 const char *refname = NULL;
368 size_t refname_cap = 0;
369 int n, err;
370
371 n = get_var_int(&update_index, &in);
372 if (n < 0)
373 return n;
374 string_view_consume(&in, n);
375
376 REFTABLE_SWAP(refname, r->refname);
377 REFTABLE_SWAP(refname_cap, r->refname_cap);
378 reftable_ref_record_release(r);
379 REFTABLE_SWAP(r->refname, refname);
380 REFTABLE_SWAP(r->refname_cap, refname_cap);
381
382 REFTABLE_ALLOC_GROW_OR_NULL(r->refname, key.len + 1, r->refname_cap);
383 if (!r->refname) {
384 err = REFTABLE_OUT_OF_MEMORY_ERROR;
385 goto done;
386 }
387 memcpy(r->refname, key.buf, key.len);
388 r->refname[key.len] = 0;
389
390 r->update_index = update_index;
391 switch (val_type) {
392 case REFTABLE_REF_VAL1:
393 if (in.len < hash_size) {
394 err = REFTABLE_FORMAT_ERROR;
395 goto done;
396 }
397
398 memcpy(r->value.val1, in.buf, hash_size);
399 string_view_consume(&in, hash_size);
400 break;
401
402 case REFTABLE_REF_VAL2:
403 if (in.len < 2 * hash_size) {
404 err = REFTABLE_FORMAT_ERROR;
405 goto done;
406 }
407
408 memcpy(r->value.val2.value, in.buf, hash_size);
409 string_view_consume(&in, hash_size);
410
411 memcpy(r->value.val2.target_value, in.buf, hash_size);
412 string_view_consume(&in, hash_size);
413 break;
414
415 case REFTABLE_REF_SYMREF: {
416 int n = decode_string(scratch, in);
417 if (n < 0) {
418 err = REFTABLE_FORMAT_ERROR;
419 goto done;
420 }
421 string_view_consume(&in, n);
422 r->value.symref = reftable_buf_detach(scratch);
423 } break;
424
425 case REFTABLE_REF_DELETION:
426 break;
427 default:
428 err = REFTABLE_FORMAT_ERROR;
429 goto done;
430 }
431 r->value_type = val_type;
432
433 return start.len - in.len;
434
435 done:
436 return err;
437 }
438
439 static int reftable_ref_record_is_deletion_void(const void *p)
440 {
441 return reftable_ref_record_is_deletion(
442 (const struct reftable_ref_record *)p);
443 }
444
445 static int reftable_ref_record_equal_void(const void *a,
446 const void *b, uint32_t hash_size)
447 {
448 struct reftable_ref_record *ra = (struct reftable_ref_record *) a;
449 struct reftable_ref_record *rb = (struct reftable_ref_record *) b;
450 return reftable_ref_record_equal(ra, rb, hash_size);
451 }
452
453 static int reftable_ref_record_cmp_void(const void *_a, const void *_b)
454 {
455 const struct reftable_ref_record *a = _a;
456 const struct reftable_ref_record *b = _b;
457 return strcmp(a->refname, b->refname);
458 }
459
460 static struct reftable_record_vtable reftable_ref_record_vtable = {
461 .key = &reftable_ref_record_key,
462 .type = REFTABLE_BLOCK_TYPE_REF,
463 .copy_from = &reftable_ref_record_copy_from,
464 .val_type = &reftable_ref_record_val_type,
465 .encode = &reftable_ref_record_encode,
466 .decode = &reftable_ref_record_decode,
467 .release = &reftable_ref_record_release_void,
468 .is_deletion = &reftable_ref_record_is_deletion_void,
469 .equal = &reftable_ref_record_equal_void,
470 .cmp = &reftable_ref_record_cmp_void,
471 };
472
473 static int reftable_obj_record_key(const void *r, struct reftable_buf *dest)
474 {
475 const struct reftable_obj_record *rec =
476 (const struct reftable_obj_record *)r;
477 reftable_buf_reset(dest);
478 return reftable_buf_add(dest, rec->hash_prefix, rec->hash_prefix_len);
479 }
480
481 static void reftable_obj_record_release(void *rec)
482 {
483 struct reftable_obj_record *obj = rec;
484 REFTABLE_FREE_AND_NULL(obj->hash_prefix);
485 REFTABLE_FREE_AND_NULL(obj->offsets);
486 memset(obj, 0, sizeof(struct reftable_obj_record));
487 }
488
489 static int reftable_obj_record_copy_from(void *rec, const void *src_rec,
490 uint32_t hash_size REFTABLE_UNUSED)
491 {
492 struct reftable_obj_record *obj = rec;
493 const struct reftable_obj_record *src = src_rec;
494
495 reftable_obj_record_release(obj);
496
497 REFTABLE_ALLOC_ARRAY(obj->hash_prefix, src->hash_prefix_len);
498 if (!obj->hash_prefix)
499 return REFTABLE_OUT_OF_MEMORY_ERROR;
500 obj->hash_prefix_len = src->hash_prefix_len;
501 if (src->hash_prefix_len)
502 memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
503
504 if (src->offset_len) {
505 if (sizeof(*src->offsets) > SIZE_MAX / src->offset_len)
506 return REFTABLE_OUT_OF_MEMORY_ERROR;
507
508 REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len);
509 if (!obj->offsets)
510 return REFTABLE_OUT_OF_MEMORY_ERROR;
511
512 memcpy(obj->offsets, src->offsets, sizeof(*src->offsets) * src->offset_len);
513 obj->offset_len = src->offset_len;
514 }
515
516 return 0;
517 }
518
519 static uint8_t reftable_obj_record_val_type(const void *rec)
520 {
521 const struct reftable_obj_record *r = rec;
522 if (r->offset_len > 0 && r->offset_len < 8)
523 return r->offset_len;
524 return 0;
525 }
526
527 static int reftable_obj_record_encode(const void *rec, struct string_view s,
528 uint32_t hash_size REFTABLE_UNUSED)
529 {
530 const struct reftable_obj_record *r = rec;
531 struct string_view start = s;
532 int i = 0;
533 int n = 0;
534 uint64_t last = 0;
535 if (r->offset_len == 0 || r->offset_len >= 8) {
536 n = put_var_int(&s, r->offset_len);
537 if (n < 0)
538 return n;
539 string_view_consume(&s, n);
540 }
541 if (r->offset_len == 0)
542 return start.len - s.len;
543 n = put_var_int(&s, r->offsets[0]);
544 if (n < 0)
545 return n;
546 string_view_consume(&s, n);
547
548 last = r->offsets[0];
549 for (i = 1; i < r->offset_len; i++) {
550 int n = put_var_int(&s, r->offsets[i] - last);
551 if (n < 0)
552 return n;
553 string_view_consume(&s, n);
554 last = r->offsets[i];
555 }
556 return start.len - s.len;
557 }
558
559 static int reftable_obj_record_decode(void *rec, struct reftable_buf key,
560 uint8_t val_type, struct string_view in,
561 uint32_t hash_size REFTABLE_UNUSED,
562 struct reftable_buf *scratch REFTABLE_UNUSED)
563 {
564 struct string_view start = in;
565 struct reftable_obj_record *r = rec;
566 uint64_t count = val_type;
567 int n = 0;
568 uint64_t last;
569
570 reftable_obj_record_release(r);
571
572 REFTABLE_ALLOC_ARRAY(r->hash_prefix, key.len);
573 if (!r->hash_prefix)
574 return REFTABLE_OUT_OF_MEMORY_ERROR;
575 memcpy(r->hash_prefix, key.buf, key.len);
576 r->hash_prefix_len = key.len;
577
578 if (val_type == 0) {
579 n = get_var_int(&count, &in);
580 if (n < 0) {
581 return n;
582 }
583
584 string_view_consume(&in, n);
585 }
586
587 r->offsets = NULL;
588 r->offset_len = 0;
589 if (count == 0)
590 return start.len - in.len;
591
592 REFTABLE_ALLOC_ARRAY(r->offsets, count);
593 if (!r->offsets)
594 return REFTABLE_OUT_OF_MEMORY_ERROR;
595 r->offset_len = count;
596
597 n = get_var_int(&r->offsets[0], &in);
598 if (n < 0)
599 return n;
600 string_view_consume(&in, n);
601
602 last = r->offsets[0];
603 for (uint64_t j = 1; j < count; j++) {
604 uint64_t delta = 0;
605 int n = get_var_int(&delta, &in);
606 if (n < 0) {
607 return n;
608 }
609 string_view_consume(&in, n);
610
611 last = r->offsets[j] = (delta + last);
612 }
613 return start.len - in.len;
614 }
615
616 static int not_a_deletion(const void *p REFTABLE_UNUSED)
617 {
618 return 0;
619 }
620
621 static int reftable_obj_record_equal_void(const void *a, const void *b,
622 uint32_t hash_size REFTABLE_UNUSED)
623 {
624 struct reftable_obj_record *ra = (struct reftable_obj_record *) a;
625 struct reftable_obj_record *rb = (struct reftable_obj_record *) b;
626
627 if (ra->hash_prefix_len != rb->hash_prefix_len
628 || ra->offset_len != rb->offset_len)
629 return 0;
630
631 if (ra->hash_prefix_len &&
632 memcmp(ra->hash_prefix, rb->hash_prefix, ra->hash_prefix_len))
633 return 0;
634 if (ra->offset_len &&
635 memcmp(ra->offsets, rb->offsets, ra->offset_len * sizeof(uint64_t)))
636 return 0;
637
638 return 1;
639 }
640
641 static int reftable_obj_record_cmp_void(const void *_a, const void *_b)
642 {
643 const struct reftable_obj_record *a = _a;
644 const struct reftable_obj_record *b = _b;
645 int cmp;
646
647 cmp = memcmp(a->hash_prefix, b->hash_prefix,
648 a->hash_prefix_len > b->hash_prefix_len ?
649 a->hash_prefix_len : b->hash_prefix_len);
650 if (cmp)
651 return cmp;
652
653 /*
654 * When the prefix is the same then the object record that is longer is
655 * considered to be bigger.
656 */
657 return a->hash_prefix_len - b->hash_prefix_len;
658 }
659
660 static struct reftable_record_vtable reftable_obj_record_vtable = {
661 .key = &reftable_obj_record_key,
662 .type = REFTABLE_BLOCK_TYPE_OBJ,
663 .copy_from = &reftable_obj_record_copy_from,
664 .val_type = &reftable_obj_record_val_type,
665 .encode = &reftable_obj_record_encode,
666 .decode = &reftable_obj_record_decode,
667 .release = &reftable_obj_record_release,
668 .is_deletion = &not_a_deletion,
669 .equal = &reftable_obj_record_equal_void,
670 .cmp = &reftable_obj_record_cmp_void,
671 };
672
673 static int reftable_log_record_key(const void *r, struct reftable_buf *dest)
674 {
675 const struct reftable_log_record *rec =
676 (const struct reftable_log_record *)r;
677 int len = strlen(rec->refname), err;
678 uint8_t i64[8];
679 uint64_t ts = 0;
680
681 reftable_buf_reset(dest);
682 err = reftable_buf_add(dest, (uint8_t *)rec->refname, len + 1);
683 if (err < 0)
684 return err;
685
686 ts = (~ts) - rec->update_index;
687 reftable_put_be64(&i64[0], ts);
688
689 err = reftable_buf_add(dest, i64, sizeof(i64));
690 if (err < 0)
691 return err;
692
693 return 0;
694 }
695
696 static int reftable_log_record_copy_from(void *rec, const void *src_rec,
697 uint32_t hash_size)
698 {
699 struct reftable_log_record *dst = rec;
700 const struct reftable_log_record *src =
701 (const struct reftable_log_record *)src_rec;
702 int ret;
703
704 reftable_log_record_release(dst);
705 *dst = *src;
706
707 if (dst->refname) {
708 dst->refname = reftable_strdup(dst->refname);
709 if (!dst->refname) {
710 ret = REFTABLE_OUT_OF_MEMORY_ERROR;
711 goto out;
712 }
713 }
714
715 switch (dst->value_type) {
716 case REFTABLE_LOG_DELETION:
717 break;
718 case REFTABLE_LOG_UPDATE:
719 if (dst->value.update.email)
720 dst->value.update.email =
721 reftable_strdup(dst->value.update.email);
722 if (dst->value.update.name)
723 dst->value.update.name =
724 reftable_strdup(dst->value.update.name);
725 if (dst->value.update.message)
726 dst->value.update.message =
727 reftable_strdup(dst->value.update.message);
728
729 if (!dst->value.update.email ||
730 !dst->value.update.name ||
731 !dst->value.update.message) {
732 ret = REFTABLE_OUT_OF_MEMORY_ERROR;
733 goto out;
734 }
735
736 memcpy(dst->value.update.new_hash,
737 src->value.update.new_hash, hash_size);
738 memcpy(dst->value.update.old_hash,
739 src->value.update.old_hash, hash_size);
740 break;
741 }
742
743 ret = 0;
744 out:
745 return ret;
746 }
747
748 static void reftable_log_record_release_void(void *rec)
749 {
750 struct reftable_log_record *r = rec;
751 reftable_log_record_release(r);
752 }
753
754 void reftable_log_record_release(struct reftable_log_record *r)
755 {
756 reftable_free(r->refname);
757 switch (r->value_type) {
758 case REFTABLE_LOG_DELETION:
759 break;
760 case REFTABLE_LOG_UPDATE:
761 reftable_free(r->value.update.name);
762 reftable_free(r->value.update.email);
763 reftable_free(r->value.update.message);
764 break;
765 }
766 memset(r, 0, sizeof(struct reftable_log_record));
767 }
768
769 static uint8_t reftable_log_record_val_type(const void *rec)
770 {
771 const struct reftable_log_record *log =
772 (const struct reftable_log_record *)rec;
773
774 return reftable_log_record_is_deletion(log) ? 0 : 1;
775 }
776
777 static int reftable_log_record_encode(const void *rec, struct string_view s,
778 uint32_t hash_size)
779 {
780 const struct reftable_log_record *r = rec;
781 struct string_view start = s;
782 int n = 0;
783 if (reftable_log_record_is_deletion(r))
784 return 0;
785
786 if (s.len < 2 * hash_size)
787 return REFTABLE_ENTRY_TOO_BIG_ERROR;
788
789 memcpy(s.buf, r->value.update.old_hash, hash_size);
790 memcpy(s.buf + hash_size, r->value.update.new_hash, hash_size);
791 string_view_consume(&s, 2 * hash_size);
792
793 n = encode_string(r->value.update.name ? r->value.update.name : "", s);
794 if (n < 0)
795 return n;
796 string_view_consume(&s, n);
797
798 n = encode_string(r->value.update.email ? r->value.update.email : "",
799 s);
800 if (n < 0)
801 return n;
802 string_view_consume(&s, n);
803
804 n = put_var_int(&s, r->value.update.time);
805 if (n < 0)
806 return n;
807 string_view_consume(&s, n);
808
809 if (s.len < 2)
810 return REFTABLE_ENTRY_TOO_BIG_ERROR;
811
812 reftable_put_be16(s.buf, r->value.update.tz_offset);
813 string_view_consume(&s, 2);
814
815 n = encode_string(
816 r->value.update.message ? r->value.update.message : "", s);
817 if (n < 0)
818 return n;
819 string_view_consume(&s, n);
820
821 return start.len - s.len;
822 }
823
824 static int reftable_log_record_decode(void *rec, struct reftable_buf key,
825 uint8_t val_type, struct string_view in,
826 uint32_t hash_size, struct reftable_buf *scratch)
827 {
828 struct string_view start = in;
829 struct reftable_log_record *r = rec;
830 uint64_t max = 0;
831 uint64_t ts = 0;
832 int err, n;
833
834 if (key.len <= 9 || key.buf[key.len - 9] != 0)
835 return REFTABLE_FORMAT_ERROR;
836
837 REFTABLE_ALLOC_GROW_OR_NULL(r->refname, key.len - 8, r->refname_cap);
838 if (!r->refname) {
839 err = REFTABLE_OUT_OF_MEMORY_ERROR;
840 goto done;
841 }
842
843 memcpy(r->refname, key.buf, key.len - 8);
844 ts = reftable_get_be64((unsigned char *)key.buf + key.len - 8);
845
846 r->update_index = (~max) - ts;
847
848 if (val_type != r->value_type) {
849 switch (r->value_type) {
850 case REFTABLE_LOG_UPDATE:
851 REFTABLE_FREE_AND_NULL(r->value.update.message);
852 r->value.update.message_cap = 0;
853 REFTABLE_FREE_AND_NULL(r->value.update.email);
854 REFTABLE_FREE_AND_NULL(r->value.update.name);
855 break;
856 case REFTABLE_LOG_DELETION:
857 break;
858 }
859 }
860
861 r->value_type = val_type;
862 if (val_type == REFTABLE_LOG_DELETION)
863 return 0;
864
865 if (in.len < 2 * hash_size) {
866 err = REFTABLE_FORMAT_ERROR;
867 goto done;
868 }
869
870 memcpy(r->value.update.old_hash, in.buf, hash_size);
871 memcpy(r->value.update.new_hash, in.buf + hash_size, hash_size);
872
873 string_view_consume(&in, 2 * hash_size);
874
875 n = decode_string(scratch, in);
876 if (n < 0) {
877 err = REFTABLE_FORMAT_ERROR;
878 goto done;
879 }
880 string_view_consume(&in, n);
881
882 /*
883 * In almost all cases we can expect the reflog name to not change for
884 * reflog entries as they are tied to the local identity, not to the
885 * target commits. As an optimization for this common case we can thus
886 * skip copying over the name in case it's accurate already.
887 */
888 if (!r->value.update.name ||
889 strcmp(r->value.update.name, scratch->buf)) {
890 char *name = reftable_realloc(r->value.update.name, scratch->len + 1);
891 if (!name) {
892 err = REFTABLE_OUT_OF_MEMORY_ERROR;
893 goto done;
894 }
895
896 r->value.update.name = name;
897 memcpy(r->value.update.name, scratch->buf, scratch->len);
898 r->value.update.name[scratch->len] = 0;
899 }
900
901 n = decode_string(scratch, in);
902 if (n < 0) {
903 err = REFTABLE_FORMAT_ERROR;
904 goto done;
905 }
906 string_view_consume(&in, n);
907
908 /* Same as above, but for the reflog email. */
909 if (!r->value.update.email ||
910 strcmp(r->value.update.email, scratch->buf)) {
911 char *email = reftable_realloc(r->value.update.email, scratch->len + 1);
912 if (!email) {
913 err = REFTABLE_OUT_OF_MEMORY_ERROR;
914 goto done;
915 }
916
917 r->value.update.email = email;
918 memcpy(r->value.update.email, scratch->buf, scratch->len);
919 r->value.update.email[scratch->len] = 0;
920 }
921
922 ts = 0;
923 n = get_var_int(&ts, &in);
924 if (n < 0) {
925 err = REFTABLE_FORMAT_ERROR;
926 goto done;
927 }
928 string_view_consume(&in, n);
929 r->value.update.time = ts;
930 if (in.len < 2) {
931 err = REFTABLE_FORMAT_ERROR;
932 goto done;
933 }
934
935 r->value.update.tz_offset = reftable_get_be16(in.buf);
936 string_view_consume(&in, 2);
937
938 n = decode_string(scratch, in);
939 if (n < 0) {
940 err = REFTABLE_FORMAT_ERROR;
941 goto done;
942 }
943 string_view_consume(&in, n);
944
945 REFTABLE_ALLOC_GROW_OR_NULL(r->value.update.message, scratch->len + 1,
946 r->value.update.message_cap);
947 if (!r->value.update.message) {
948 err = REFTABLE_OUT_OF_MEMORY_ERROR;
949 goto done;
950 }
951
952 memcpy(r->value.update.message, scratch->buf, scratch->len);
953 r->value.update.message[scratch->len] = 0;
954
955 return start.len - in.len;
956
957 done:
958 return err;
959 }
960
961 static int null_streq(const char *a, const char *b)
962 {
963 const char *empty = "";
964 if (!a)
965 a = empty;
966
967 if (!b)
968 b = empty;
969
970 return 0 == strcmp(a, b);
971 }
972
973 static int reftable_log_record_equal_void(const void *a,
974 const void *b, uint32_t hash_size)
975 {
976 return reftable_log_record_equal((struct reftable_log_record *) a,
977 (struct reftable_log_record *) b,
978 hash_size);
979 }
980
981 static int reftable_log_record_cmp_void(const void *_a, const void *_b)
982 {
983 const struct reftable_log_record *a = _a;
984 const struct reftable_log_record *b = _b;
985 int cmp = strcmp(a->refname, b->refname);
986 if (cmp)
987 return cmp;
988
989 /*
990 * Note that the comparison here is reversed. This is because the
991 * update index is reversed when comparing keys. For reference, see how
992 * we handle this in reftable_log_record_key()`.
993 */
994 return b->update_index - a->update_index;
995 }
996
997 int reftable_log_record_equal(const struct reftable_log_record *a,
998 const struct reftable_log_record *b, uint32_t hash_size)
999 {
1000 if (!(null_streq(a->refname, b->refname) &&
1001 a->update_index == b->update_index &&
1002 a->value_type == b->value_type))
1003 return 0;
1004
1005 switch (a->value_type) {
1006 case REFTABLE_LOG_DELETION:
1007 return 1;
1008 case REFTABLE_LOG_UPDATE:
1009 return null_streq(a->value.update.name, b->value.update.name) &&
1010 a->value.update.time == b->value.update.time &&
1011 a->value.update.tz_offset == b->value.update.tz_offset &&
1012 null_streq(a->value.update.email,
1013 b->value.update.email) &&
1014 null_streq(a->value.update.message,
1015 b->value.update.message) &&
1016 !memcmp(a->value.update.old_hash,
1017 b->value.update.old_hash, hash_size) &&
1018 !memcmp(a->value.update.new_hash,
1019 b->value.update.new_hash, hash_size);
1020 }
1021
1022 abort();
1023 }
1024
1025 static int reftable_log_record_is_deletion_void(const void *p)
1026 {
1027 return reftable_log_record_is_deletion(
1028 (const struct reftable_log_record *)p);
1029 }
1030
1031 static struct reftable_record_vtable reftable_log_record_vtable = {
1032 .key = &reftable_log_record_key,
1033 .type = REFTABLE_BLOCK_TYPE_LOG,
1034 .copy_from = &reftable_log_record_copy_from,
1035 .val_type = &reftable_log_record_val_type,
1036 .encode = &reftable_log_record_encode,
1037 .decode = &reftable_log_record_decode,
1038 .release = &reftable_log_record_release_void,
1039 .is_deletion = &reftable_log_record_is_deletion_void,
1040 .equal = &reftable_log_record_equal_void,
1041 .cmp = &reftable_log_record_cmp_void,
1042 };
1043
1044 static int reftable_index_record_key(const void *r, struct reftable_buf *dest)
1045 {
1046 const struct reftable_index_record *rec = r;
1047 reftable_buf_reset(dest);
1048 return reftable_buf_add(dest, rec->last_key.buf, rec->last_key.len);
1049 }
1050
1051 static int reftable_index_record_copy_from(void *rec, const void *src_rec,
1052 uint32_t hash_size REFTABLE_UNUSED)
1053 {
1054 struct reftable_index_record *dst = rec;
1055 const struct reftable_index_record *src = src_rec;
1056 int err;
1057
1058 reftable_buf_reset(&dst->last_key);
1059 err = reftable_buf_add(&dst->last_key, src->last_key.buf, src->last_key.len);
1060 if (err < 0)
1061 return err;
1062 dst->offset = src->offset;
1063
1064 return 0;
1065 }
1066
1067 static void reftable_index_record_release(void *rec)
1068 {
1069 struct reftable_index_record *idx = rec;
1070 reftable_buf_release(&idx->last_key);
1071 }
1072
1073 static uint8_t reftable_index_record_val_type(const void *rec REFTABLE_UNUSED)
1074 {
1075 return 0;
1076 }
1077
1078 static int reftable_index_record_encode(const void *rec, struct string_view out,
1079 uint32_t hash_size REFTABLE_UNUSED)
1080 {
1081 const struct reftable_index_record *r =
1082 (const struct reftable_index_record *)rec;
1083 struct string_view start = out;
1084
1085 int n = put_var_int(&out, r->offset);
1086 if (n < 0)
1087 return n;
1088
1089 string_view_consume(&out, n);
1090
1091 return start.len - out.len;
1092 }
1093
1094 static int reftable_index_record_decode(void *rec, struct reftable_buf key,
1095 uint8_t val_type REFTABLE_UNUSED,
1096 struct string_view in,
1097 uint32_t hash_size REFTABLE_UNUSED,
1098 struct reftable_buf *scratch REFTABLE_UNUSED)
1099 {
1100 struct string_view start = in;
1101 struct reftable_index_record *r = rec;
1102 int err, n = 0;
1103
1104 reftable_buf_reset(&r->last_key);
1105 err = reftable_buf_add(&r->last_key, key.buf, key.len);
1106 if (err < 0)
1107 return err;
1108
1109 n = get_var_int(&r->offset, &in);
1110 if (n < 0)
1111 return n;
1112
1113 string_view_consume(&in, n);
1114 return start.len - in.len;
1115 }
1116
1117 static int reftable_index_record_equal(const void *a, const void *b,
1118 uint32_t hash_size REFTABLE_UNUSED)
1119 {
1120 struct reftable_index_record *ia = (struct reftable_index_record *) a;
1121 struct reftable_index_record *ib = (struct reftable_index_record *) b;
1122
1123 return ia->offset == ib->offset && !reftable_buf_cmp(&ia->last_key, &ib->last_key);
1124 }
1125
1126 static int reftable_index_record_cmp(const void *_a, const void *_b)
1127 {
1128 const struct reftable_index_record *a = _a;
1129 const struct reftable_index_record *b = _b;
1130 return reftable_buf_cmp(&a->last_key, &b->last_key);
1131 }
1132
1133 static struct reftable_record_vtable reftable_index_record_vtable = {
1134 .key = &reftable_index_record_key,
1135 .type = REFTABLE_BLOCK_TYPE_INDEX,
1136 .copy_from = &reftable_index_record_copy_from,
1137 .val_type = &reftable_index_record_val_type,
1138 .encode = &reftable_index_record_encode,
1139 .decode = &reftable_index_record_decode,
1140 .release = &reftable_index_record_release,
1141 .is_deletion = &not_a_deletion,
1142 .equal = &reftable_index_record_equal,
1143 .cmp = &reftable_index_record_cmp,
1144 };
1145
1146 int reftable_record_key(struct reftable_record *rec, struct reftable_buf *dest)
1147 {
1148 return reftable_record_vtable(rec)->key(reftable_record_data(rec), dest);
1149 }
1150
1151 int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
1152 uint32_t hash_size)
1153 {
1154 return reftable_record_vtable(rec)->encode(reftable_record_data(rec),
1155 dest, hash_size);
1156 }
1157
1158 int reftable_record_copy_from(struct reftable_record *rec,
1159 struct reftable_record *src, uint32_t hash_size)
1160 {
1161 assert(src->type == rec->type);
1162
1163 return reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
1164 reftable_record_data(src),
1165 hash_size);
1166 }
1167
1168 uint8_t reftable_record_val_type(struct reftable_record *rec)
1169 {
1170 return reftable_record_vtable(rec)->val_type(reftable_record_data(rec));
1171 }
1172
1173 int reftable_record_decode(struct reftable_record *rec, struct reftable_buf key,
1174 uint8_t extra, struct string_view src, uint32_t hash_size,
1175 struct reftable_buf *scratch)
1176 {
1177 return reftable_record_vtable(rec)->decode(reftable_record_data(rec),
1178 key, extra, src, hash_size,
1179 scratch);
1180 }
1181
1182 void reftable_record_release(struct reftable_record *rec)
1183 {
1184 reftable_record_vtable(rec)->release(reftable_record_data(rec));
1185 }
1186
1187 int reftable_record_is_deletion(struct reftable_record *rec)
1188 {
1189 return reftable_record_vtable(rec)->is_deletion(
1190 reftable_record_data(rec));
1191 }
1192
1193 int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b,
1194 int *cmp)
1195 {
1196 if (a->type != b->type)
1197 return -1;
1198 *cmp = reftable_record_vtable(a)->cmp(reftable_record_data(a),
1199 reftable_record_data(b));
1200 return 0;
1201 }
1202
1203 int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, uint32_t hash_size)
1204 {
1205 if (a->type != b->type)
1206 return 0;
1207 return reftable_record_vtable(a)->equal(
1208 reftable_record_data(a), reftable_record_data(b), hash_size);
1209 }
1210
1211 static int hash_equal(const unsigned char *a, const unsigned char *b, uint32_t hash_size)
1212 {
1213 if (a && b)
1214 return !memcmp(a, b, hash_size);
1215
1216 return a == b;
1217 }
1218
1219 int reftable_ref_record_equal(const struct reftable_ref_record *a,
1220 const struct reftable_ref_record *b, uint32_t hash_size)
1221 {
1222 if (!null_streq(a->refname, b->refname))
1223 return 0;
1224
1225 if (a->update_index != b->update_index ||
1226 a->value_type != b->value_type)
1227 return 0;
1228
1229 switch (a->value_type) {
1230 case REFTABLE_REF_SYMREF:
1231 return !strcmp(a->value.symref, b->value.symref);
1232 case REFTABLE_REF_VAL2:
1233 return hash_equal(a->value.val2.value, b->value.val2.value,
1234 hash_size) &&
1235 hash_equal(a->value.val2.target_value,
1236 b->value.val2.target_value, hash_size);
1237 case REFTABLE_REF_VAL1:
1238 return hash_equal(a->value.val1, b->value.val1, hash_size);
1239 case REFTABLE_REF_DELETION:
1240 return 1;
1241 default:
1242 abort();
1243 }
1244 }
1245
1246 int reftable_ref_record_compare_name(const void *a, const void *b)
1247 {
1248 return strcmp(((struct reftable_ref_record *)a)->refname,
1249 ((struct reftable_ref_record *)b)->refname);
1250 }
1251
1252 int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref)
1253 {
1254 return ref->value_type == REFTABLE_REF_DELETION;
1255 }
1256
1257 int reftable_log_record_compare_key(const void *a, const void *b)
1258 {
1259 const struct reftable_log_record *la = a;
1260 const struct reftable_log_record *lb = b;
1261
1262 int cmp = strcmp(la->refname, lb->refname);
1263 if (cmp)
1264 return cmp;
1265 if (la->update_index > lb->update_index)
1266 return -1;
1267 return (la->update_index < lb->update_index) ? 1 : 0;
1268 }
1269
1270 int reftable_log_record_is_deletion(const struct reftable_log_record *log)
1271 {
1272 return (log->value_type == REFTABLE_LOG_DELETION);
1273 }
1274
1275 static void *reftable_record_data(struct reftable_record *rec)
1276 {
1277 switch (rec->type) {
1278 case REFTABLE_BLOCK_TYPE_REF:
1279 return &rec->u.ref;
1280 case REFTABLE_BLOCK_TYPE_LOG:
1281 return &rec->u.log;
1282 case REFTABLE_BLOCK_TYPE_INDEX:
1283 return &rec->u.idx;
1284 case REFTABLE_BLOCK_TYPE_OBJ:
1285 return &rec->u.obj;
1286 }
1287 abort();
1288 }
1289
1290 static struct reftable_record_vtable *
1291 reftable_record_vtable(struct reftable_record *rec)
1292 {
1293 switch (rec->type) {
1294 case REFTABLE_BLOCK_TYPE_REF:
1295 return &reftable_ref_record_vtable;
1296 case REFTABLE_BLOCK_TYPE_LOG:
1297 return &reftable_log_record_vtable;
1298 case REFTABLE_BLOCK_TYPE_INDEX:
1299 return &reftable_index_record_vtable;
1300 case REFTABLE_BLOCK_TYPE_OBJ:
1301 return &reftable_obj_record_vtable;
1302 }
1303 abort();
1304 }
1305
1306 int reftable_record_init(struct reftable_record *rec, uint8_t typ)
1307 {
1308 memset(rec, 0, sizeof(*rec));
1309 rec->type = typ;
1310
1311 switch (typ) {
1312 case REFTABLE_BLOCK_TYPE_REF:
1313 case REFTABLE_BLOCK_TYPE_LOG:
1314 case REFTABLE_BLOCK_TYPE_OBJ:
1315 return 0;
1316 case REFTABLE_BLOCK_TYPE_INDEX:
1317 reftable_buf_init(&rec->u.idx.last_key);
1318 return 0;
1319 default:
1320 return REFTABLE_API_ERROR;
1321 }
1322 }