The eleventh batch
[git/gitster.git] / reftable / record.c
blobfb5652ed5754f2b0420080d394261735400a6dcf
1 /*
2 Copyright 2020 Google LLC
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 */
9 /* record.c - methods for different types of records. */
11 #include "record.h"
13 #include "system.h"
14 #include "constants.h"
15 #include "reftable-error.h"
16 #include "basics.h"
18 static struct reftable_record_vtable *
19 reftable_record_vtable(struct reftable_record *rec);
20 static void *reftable_record_data(struct reftable_record *rec);
22 int get_var_int(uint64_t *dest, struct string_view *in)
24 int ptr = 0;
25 uint64_t val;
27 if (in->len == 0)
28 return -1;
29 val = in->buf[ptr] & 0x7f;
31 while (in->buf[ptr] & 0x80) {
32 ptr++;
33 if (ptr > in->len) {
34 return -1;
36 val = (val + 1) << 7 | (uint64_t)(in->buf[ptr] & 0x7f);
39 *dest = val;
40 return ptr + 1;
43 int put_var_int(struct string_view *dest, uint64_t val)
45 uint8_t buf[10] = { 0 };
46 int i = 9;
47 int n = 0;
48 buf[i] = (uint8_t)(val & 0x7f);
49 i--;
50 while (1) {
51 val >>= 7;
52 if (!val) {
53 break;
55 val--;
56 buf[i] = 0x80 | (uint8_t)(val & 0x7f);
57 i--;
60 n = sizeof(buf) - i - 1;
61 if (dest->len < n)
62 return -1;
63 memcpy(dest->buf, &buf[i + 1], n);
64 return n;
67 int reftable_is_block_type(uint8_t typ)
69 switch (typ) {
70 case BLOCK_TYPE_REF:
71 case BLOCK_TYPE_LOG:
72 case BLOCK_TYPE_OBJ:
73 case BLOCK_TYPE_INDEX:
74 return 1;
76 return 0;
79 const unsigned char *reftable_ref_record_val1(const struct reftable_ref_record *rec)
81 switch (rec->value_type) {
82 case REFTABLE_REF_VAL1:
83 return rec->value.val1;
84 case REFTABLE_REF_VAL2:
85 return rec->value.val2.value;
86 default:
87 return NULL;
91 const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record *rec)
93 switch (rec->value_type) {
94 case REFTABLE_REF_VAL2:
95 return rec->value.val2.target_value;
96 default:
97 return NULL;
101 static int decode_string(struct reftable_buf *dest, struct string_view in)
103 int start_len = in.len;
104 uint64_t tsize = 0;
105 int n, err;
107 n = get_var_int(&tsize, &in);
108 if (n <= 0)
109 return -1;
110 string_view_consume(&in, n);
111 if (in.len < tsize)
112 return -1;
114 reftable_buf_reset(dest);
115 err = reftable_buf_add(dest, in.buf, tsize);
116 if (err < 0)
117 return err;
119 string_view_consume(&in, tsize);
121 return start_len - in.len;
124 static int encode_string(const char *str, struct string_view s)
126 struct string_view start = s;
127 int l = strlen(str);
128 int n = put_var_int(&s, l);
129 if (n < 0)
130 return -1;
131 string_view_consume(&s, n);
132 if (s.len < l)
133 return -1;
134 memcpy(s.buf, str, l);
135 string_view_consume(&s, l);
137 return start.len - s.len;
140 int reftable_encode_key(int *restart, struct string_view dest,
141 struct reftable_buf prev_key, struct reftable_buf key,
142 uint8_t extra)
144 struct string_view start = dest;
145 int prefix_len = common_prefix_size(&prev_key, &key);
146 uint64_t suffix_len = key.len - prefix_len;
147 int n = put_var_int(&dest, (uint64_t)prefix_len);
148 if (n < 0)
149 return -1;
150 string_view_consume(&dest, n);
152 *restart = (prefix_len == 0);
154 n = put_var_int(&dest, suffix_len << 3 | (uint64_t)extra);
155 if (n < 0)
156 return -1;
157 string_view_consume(&dest, n);
159 if (dest.len < suffix_len)
160 return -1;
161 memcpy(dest.buf, key.buf + prefix_len, suffix_len);
162 string_view_consume(&dest, suffix_len);
164 return start.len - dest.len;
167 int reftable_decode_keylen(struct string_view in,
168 uint64_t *prefix_len,
169 uint64_t *suffix_len,
170 uint8_t *extra)
172 size_t start_len = in.len;
173 int n;
175 n = get_var_int(prefix_len, &in);
176 if (n < 0)
177 return -1;
178 string_view_consume(&in, n);
180 n = get_var_int(suffix_len, &in);
181 if (n <= 0)
182 return -1;
183 string_view_consume(&in, n);
185 *extra = (uint8_t)(*suffix_len & 0x7);
186 *suffix_len >>= 3;
188 return start_len - in.len;
191 int reftable_decode_key(struct reftable_buf *last_key, uint8_t *extra,
192 struct string_view in)
194 int start_len = in.len;
195 uint64_t prefix_len = 0;
196 uint64_t suffix_len = 0;
197 int err, n;
199 n = reftable_decode_keylen(in, &prefix_len, &suffix_len, extra);
200 if (n < 0)
201 return -1;
202 string_view_consume(&in, n);
204 if (in.len < suffix_len ||
205 prefix_len > last_key->len)
206 return -1;
208 err = reftable_buf_setlen(last_key, prefix_len);
209 if (err < 0)
210 return err;
212 err = reftable_buf_add(last_key, in.buf, suffix_len);
213 if (err < 0)
214 return err;
216 string_view_consume(&in, suffix_len);
218 return start_len - in.len;
221 static int reftable_ref_record_key(const void *r, struct reftable_buf *dest)
223 const struct reftable_ref_record *rec =
224 (const struct reftable_ref_record *)r;
225 reftable_buf_reset(dest);
226 return reftable_buf_addstr(dest, rec->refname);
229 static int reftable_ref_record_copy_from(void *rec, const void *src_rec,
230 int hash_size)
232 struct reftable_ref_record *ref = rec;
233 const struct reftable_ref_record *src = src_rec;
234 char *refname = NULL;
235 size_t refname_cap = 0;
236 int err;
238 assert(hash_size > 0);
240 SWAP(refname, ref->refname);
241 SWAP(refname_cap, ref->refname_cap);
242 reftable_ref_record_release(ref);
243 SWAP(ref->refname, refname);
244 SWAP(ref->refname_cap, refname_cap);
246 if (src->refname) {
247 size_t refname_len = strlen(src->refname);
249 REFTABLE_ALLOC_GROW(ref->refname, refname_len + 1,
250 ref->refname_cap);
251 if (!ref->refname) {
252 err = REFTABLE_OUT_OF_MEMORY_ERROR;
253 goto out;
256 memcpy(ref->refname, src->refname, refname_len);
257 ref->refname[refname_len] = 0;
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;
279 break;
282 err = 0;
283 out:
284 return err;
287 static void reftable_ref_record_release_void(void *rec)
289 reftable_ref_record_release(rec);
292 void reftable_ref_record_release(struct reftable_ref_record *ref)
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();
308 reftable_free(ref->refname);
309 memset(ref, 0, sizeof(struct reftable_ref_record));
312 static uint8_t reftable_ref_record_val_type(const void *rec)
314 const struct reftable_ref_record *r =
315 (const struct reftable_ref_record *)rec;
316 return r->value_type;
319 static int reftable_ref_record_encode(const void *rec, struct string_view s,
320 int hash_size)
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 assert(hash_size > 0);
327 if (n < 0)
328 return -1;
329 string_view_consume(&s, n);
331 switch (r->value_type) {
332 case REFTABLE_REF_SYMREF:
333 n = encode_string(r->value.symref, s);
334 if (n < 0) {
335 return -1;
337 string_view_consume(&s, n);
338 break;
339 case REFTABLE_REF_VAL2:
340 if (s.len < 2 * hash_size) {
341 return -1;
343 memcpy(s.buf, r->value.val2.value, hash_size);
344 string_view_consume(&s, hash_size);
345 memcpy(s.buf, r->value.val2.target_value, hash_size);
346 string_view_consume(&s, hash_size);
347 break;
348 case REFTABLE_REF_VAL1:
349 if (s.len < hash_size) {
350 return -1;
352 memcpy(s.buf, r->value.val1, hash_size);
353 string_view_consume(&s, hash_size);
354 break;
355 case REFTABLE_REF_DELETION:
356 break;
357 default:
358 abort();
361 return start.len - s.len;
364 static int reftable_ref_record_decode(void *rec, struct reftable_buf key,
365 uint8_t val_type, struct string_view in,
366 int hash_size, struct reftable_buf *scratch)
368 struct reftable_ref_record *r = rec;
369 struct string_view start = in;
370 uint64_t update_index = 0;
371 const char *refname = NULL;
372 size_t refname_cap = 0;
373 int n, err;
375 assert(hash_size > 0);
377 n = get_var_int(&update_index, &in);
378 if (n < 0)
379 return n;
380 string_view_consume(&in, n);
382 SWAP(refname, r->refname);
383 SWAP(refname_cap, r->refname_cap);
384 reftable_ref_record_release(r);
385 SWAP(r->refname, refname);
386 SWAP(r->refname_cap, refname_cap);
388 REFTABLE_ALLOC_GROW(r->refname, key.len + 1, r->refname_cap);
389 if (!r->refname) {
390 err = REFTABLE_OUT_OF_MEMORY_ERROR;
391 goto done;
393 memcpy(r->refname, key.buf, key.len);
394 r->refname[key.len] = 0;
396 r->update_index = update_index;
397 r->value_type = val_type;
398 switch (val_type) {
399 case REFTABLE_REF_VAL1:
400 if (in.len < hash_size) {
401 err = REFTABLE_FORMAT_ERROR;
402 goto done;
405 memcpy(r->value.val1, in.buf, hash_size);
406 string_view_consume(&in, hash_size);
407 break;
409 case REFTABLE_REF_VAL2:
410 if (in.len < 2 * hash_size) {
411 err = REFTABLE_FORMAT_ERROR;
412 goto done;
415 memcpy(r->value.val2.value, in.buf, hash_size);
416 string_view_consume(&in, hash_size);
418 memcpy(r->value.val2.target_value, in.buf, hash_size);
419 string_view_consume(&in, hash_size);
420 break;
422 case REFTABLE_REF_SYMREF: {
423 int n = decode_string(scratch, in);
424 if (n < 0) {
425 err = REFTABLE_FORMAT_ERROR;
426 goto done;
428 string_view_consume(&in, n);
429 r->value.symref = reftable_buf_detach(scratch);
430 } break;
432 case REFTABLE_REF_DELETION:
433 break;
434 default:
435 abort();
436 break;
439 return start.len - in.len;
441 done:
442 return err;
445 static int reftable_ref_record_is_deletion_void(const void *p)
447 return reftable_ref_record_is_deletion(
448 (const struct reftable_ref_record *)p);
451 static int reftable_ref_record_equal_void(const void *a,
452 const void *b, int hash_size)
454 struct reftable_ref_record *ra = (struct reftable_ref_record *) a;
455 struct reftable_ref_record *rb = (struct reftable_ref_record *) b;
456 return reftable_ref_record_equal(ra, rb, hash_size);
459 static int reftable_ref_record_cmp_void(const void *_a, const void *_b)
461 const struct reftable_ref_record *a = _a;
462 const struct reftable_ref_record *b = _b;
463 return strcmp(a->refname, b->refname);
466 static struct reftable_record_vtable reftable_ref_record_vtable = {
467 .key = &reftable_ref_record_key,
468 .type = BLOCK_TYPE_REF,
469 .copy_from = &reftable_ref_record_copy_from,
470 .val_type = &reftable_ref_record_val_type,
471 .encode = &reftable_ref_record_encode,
472 .decode = &reftable_ref_record_decode,
473 .release = &reftable_ref_record_release_void,
474 .is_deletion = &reftable_ref_record_is_deletion_void,
475 .equal = &reftable_ref_record_equal_void,
476 .cmp = &reftable_ref_record_cmp_void,
479 static int reftable_obj_record_key(const void *r, struct reftable_buf *dest)
481 const struct reftable_obj_record *rec =
482 (const struct reftable_obj_record *)r;
483 reftable_buf_reset(dest);
484 return reftable_buf_add(dest, rec->hash_prefix, rec->hash_prefix_len);
487 static void reftable_obj_record_release(void *rec)
489 struct reftable_obj_record *obj = rec;
490 REFTABLE_FREE_AND_NULL(obj->hash_prefix);
491 REFTABLE_FREE_AND_NULL(obj->offsets);
492 memset(obj, 0, sizeof(struct reftable_obj_record));
495 static int reftable_obj_record_copy_from(void *rec, const void *src_rec,
496 int hash_size UNUSED)
498 struct reftable_obj_record *obj = rec;
499 const struct reftable_obj_record *src = src_rec;
501 reftable_obj_record_release(obj);
503 REFTABLE_ALLOC_ARRAY(obj->hash_prefix, src->hash_prefix_len);
504 if (!obj->hash_prefix)
505 return REFTABLE_OUT_OF_MEMORY_ERROR;
506 obj->hash_prefix_len = src->hash_prefix_len;
507 if (src->hash_prefix_len)
508 memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
510 REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len);
511 if (!obj->offsets)
512 return REFTABLE_OUT_OF_MEMORY_ERROR;
513 obj->offset_len = src->offset_len;
514 COPY_ARRAY(obj->offsets, src->offsets, src->offset_len);
516 return 0;
519 static uint8_t reftable_obj_record_val_type(const void *rec)
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;
527 static int reftable_obj_record_encode(const void *rec, struct string_view s,
528 int hash_size UNUSED)
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 -1;
540 string_view_consume(&s, n);
542 if (r->offset_len == 0)
543 return start.len - s.len;
544 n = put_var_int(&s, r->offsets[0]);
545 if (n < 0)
546 return -1;
547 string_view_consume(&s, n);
549 last = r->offsets[0];
550 for (i = 1; i < r->offset_len; i++) {
551 int n = put_var_int(&s, r->offsets[i] - last);
552 if (n < 0) {
553 return -1;
555 string_view_consume(&s, n);
556 last = r->offsets[i];
558 return start.len - s.len;
561 static int reftable_obj_record_decode(void *rec, struct reftable_buf key,
562 uint8_t val_type, struct string_view in,
563 int hash_size UNUSED,
564 struct reftable_buf *scratch UNUSED)
566 struct string_view start = in;
567 struct reftable_obj_record *r = rec;
568 uint64_t count = val_type;
569 int n = 0;
570 uint64_t last;
571 int j;
573 reftable_obj_record_release(r);
575 REFTABLE_ALLOC_ARRAY(r->hash_prefix, key.len);
576 if (!r->hash_prefix)
577 return REFTABLE_OUT_OF_MEMORY_ERROR;
578 memcpy(r->hash_prefix, key.buf, key.len);
579 r->hash_prefix_len = key.len;
581 if (val_type == 0) {
582 n = get_var_int(&count, &in);
583 if (n < 0) {
584 return n;
587 string_view_consume(&in, n);
590 r->offsets = NULL;
591 r->offset_len = 0;
592 if (count == 0)
593 return start.len - in.len;
595 REFTABLE_ALLOC_ARRAY(r->offsets, count);
596 if (!r->offsets)
597 return REFTABLE_OUT_OF_MEMORY_ERROR;
598 r->offset_len = count;
600 n = get_var_int(&r->offsets[0], &in);
601 if (n < 0)
602 return n;
603 string_view_consume(&in, n);
605 last = r->offsets[0];
606 j = 1;
607 while (j < count) {
608 uint64_t delta = 0;
609 int n = get_var_int(&delta, &in);
610 if (n < 0) {
611 return n;
613 string_view_consume(&in, n);
615 last = r->offsets[j] = (delta + last);
616 j++;
618 return start.len - in.len;
621 static int not_a_deletion(const void *p UNUSED)
623 return 0;
626 static int reftable_obj_record_equal_void(const void *a, const void *b,
627 int hash_size UNUSED)
629 struct reftable_obj_record *ra = (struct reftable_obj_record *) a;
630 struct reftable_obj_record *rb = (struct reftable_obj_record *) b;
632 if (ra->hash_prefix_len != rb->hash_prefix_len
633 || ra->offset_len != rb->offset_len)
634 return 0;
636 if (ra->hash_prefix_len &&
637 memcmp(ra->hash_prefix, rb->hash_prefix, ra->hash_prefix_len))
638 return 0;
639 if (ra->offset_len &&
640 memcmp(ra->offsets, rb->offsets, ra->offset_len * sizeof(uint64_t)))
641 return 0;
643 return 1;
646 static int reftable_obj_record_cmp_void(const void *_a, const void *_b)
648 const struct reftable_obj_record *a = _a;
649 const struct reftable_obj_record *b = _b;
650 int cmp;
652 cmp = memcmp(a->hash_prefix, b->hash_prefix,
653 a->hash_prefix_len > b->hash_prefix_len ?
654 a->hash_prefix_len : b->hash_prefix_len);
655 if (cmp)
656 return cmp;
659 * When the prefix is the same then the object record that is longer is
660 * considered to be bigger.
662 return a->hash_prefix_len - b->hash_prefix_len;
665 static struct reftable_record_vtable reftable_obj_record_vtable = {
666 .key = &reftable_obj_record_key,
667 .type = BLOCK_TYPE_OBJ,
668 .copy_from = &reftable_obj_record_copy_from,
669 .val_type = &reftable_obj_record_val_type,
670 .encode = &reftable_obj_record_encode,
671 .decode = &reftable_obj_record_decode,
672 .release = &reftable_obj_record_release,
673 .is_deletion = &not_a_deletion,
674 .equal = &reftable_obj_record_equal_void,
675 .cmp = &reftable_obj_record_cmp_void,
678 static int reftable_log_record_key(const void *r, struct reftable_buf *dest)
680 const struct reftable_log_record *rec =
681 (const struct reftable_log_record *)r;
682 int len = strlen(rec->refname), err;
683 uint8_t i64[8];
684 uint64_t ts = 0;
686 reftable_buf_reset(dest);
687 err = reftable_buf_add(dest, (uint8_t *)rec->refname, len + 1);
688 if (err < 0)
689 return err;
691 ts = (~ts) - rec->update_index;
692 put_be64(&i64[0], ts);
694 err = reftable_buf_add(dest, i64, sizeof(i64));
695 if (err < 0)
696 return err;
698 return 0;
701 static int reftable_log_record_copy_from(void *rec, const void *src_rec,
702 int hash_size)
704 struct reftable_log_record *dst = rec;
705 const struct reftable_log_record *src =
706 (const struct reftable_log_record *)src_rec;
707 int ret;
709 reftable_log_record_release(dst);
710 *dst = *src;
712 if (dst->refname) {
713 dst->refname = reftable_strdup(dst->refname);
714 if (!dst->refname) {
715 ret = REFTABLE_OUT_OF_MEMORY_ERROR;
716 goto out;
720 switch (dst->value_type) {
721 case REFTABLE_LOG_DELETION:
722 break;
723 case REFTABLE_LOG_UPDATE:
724 if (dst->value.update.email)
725 dst->value.update.email =
726 reftable_strdup(dst->value.update.email);
727 if (dst->value.update.name)
728 dst->value.update.name =
729 reftable_strdup(dst->value.update.name);
730 if (dst->value.update.message)
731 dst->value.update.message =
732 reftable_strdup(dst->value.update.message);
734 if (!dst->value.update.email ||
735 !dst->value.update.name ||
736 !dst->value.update.message) {
737 ret = REFTABLE_OUT_OF_MEMORY_ERROR;
738 goto out;
741 memcpy(dst->value.update.new_hash,
742 src->value.update.new_hash, hash_size);
743 memcpy(dst->value.update.old_hash,
744 src->value.update.old_hash, hash_size);
745 break;
748 ret = 0;
749 out:
750 return ret;
753 static void reftable_log_record_release_void(void *rec)
755 struct reftable_log_record *r = rec;
756 reftable_log_record_release(r);
759 void reftable_log_record_release(struct reftable_log_record *r)
761 reftable_free(r->refname);
762 switch (r->value_type) {
763 case REFTABLE_LOG_DELETION:
764 break;
765 case REFTABLE_LOG_UPDATE:
766 reftable_free(r->value.update.name);
767 reftable_free(r->value.update.email);
768 reftable_free(r->value.update.message);
769 break;
771 memset(r, 0, sizeof(struct reftable_log_record));
774 static uint8_t reftable_log_record_val_type(const void *rec)
776 const struct reftable_log_record *log =
777 (const struct reftable_log_record *)rec;
779 return reftable_log_record_is_deletion(log) ? 0 : 1;
782 static int reftable_log_record_encode(const void *rec, struct string_view s,
783 int hash_size)
785 const struct reftable_log_record *r = rec;
786 struct string_view start = s;
787 int n = 0;
788 if (reftable_log_record_is_deletion(r))
789 return 0;
791 if (s.len < 2 * hash_size)
792 return -1;
794 memcpy(s.buf, r->value.update.old_hash, hash_size);
795 memcpy(s.buf + hash_size, r->value.update.new_hash, hash_size);
796 string_view_consume(&s, 2 * hash_size);
798 n = encode_string(r->value.update.name ? r->value.update.name : "", s);
799 if (n < 0)
800 return -1;
801 string_view_consume(&s, n);
803 n = encode_string(r->value.update.email ? r->value.update.email : "",
805 if (n < 0)
806 return -1;
807 string_view_consume(&s, n);
809 n = put_var_int(&s, r->value.update.time);
810 if (n < 0)
811 return -1;
812 string_view_consume(&s, n);
814 if (s.len < 2)
815 return -1;
817 put_be16(s.buf, r->value.update.tz_offset);
818 string_view_consume(&s, 2);
820 n = encode_string(
821 r->value.update.message ? r->value.update.message : "", s);
822 if (n < 0)
823 return -1;
824 string_view_consume(&s, n);
826 return start.len - s.len;
829 static int reftable_log_record_decode(void *rec, struct reftable_buf key,
830 uint8_t val_type, struct string_view in,
831 int hash_size, struct reftable_buf *scratch)
833 struct string_view start = in;
834 struct reftable_log_record *r = rec;
835 uint64_t max = 0;
836 uint64_t ts = 0;
837 int err, n;
839 if (key.len <= 9 || key.buf[key.len - 9] != 0)
840 return REFTABLE_FORMAT_ERROR;
842 REFTABLE_ALLOC_GROW(r->refname, key.len - 8, r->refname_cap);
843 if (!r->refname) {
844 err = REFTABLE_OUT_OF_MEMORY_ERROR;
845 goto done;
848 memcpy(r->refname, key.buf, key.len - 8);
849 ts = get_be64(key.buf + key.len - 8);
851 r->update_index = (~max) - ts;
853 if (val_type != r->value_type) {
854 switch (r->value_type) {
855 case REFTABLE_LOG_UPDATE:
856 REFTABLE_FREE_AND_NULL(r->value.update.message);
857 r->value.update.message_cap = 0;
858 REFTABLE_FREE_AND_NULL(r->value.update.email);
859 REFTABLE_FREE_AND_NULL(r->value.update.name);
860 break;
861 case REFTABLE_LOG_DELETION:
862 break;
866 r->value_type = val_type;
867 if (val_type == REFTABLE_LOG_DELETION)
868 return 0;
870 if (in.len < 2 * hash_size) {
871 err = REFTABLE_FORMAT_ERROR;
872 goto done;
875 memcpy(r->value.update.old_hash, in.buf, hash_size);
876 memcpy(r->value.update.new_hash, in.buf + hash_size, hash_size);
878 string_view_consume(&in, 2 * hash_size);
880 n = decode_string(scratch, in);
881 if (n < 0) {
882 err = REFTABLE_FORMAT_ERROR;
883 goto done;
885 string_view_consume(&in, n);
888 * In almost all cases we can expect the reflog name to not change for
889 * reflog entries as they are tied to the local identity, not to the
890 * target commits. As an optimization for this common case we can thus
891 * skip copying over the name in case it's accurate already.
893 if (!r->value.update.name ||
894 strcmp(r->value.update.name, scratch->buf)) {
895 char *name = reftable_realloc(r->value.update.name, scratch->len + 1);
896 if (!name) {
897 err = REFTABLE_OUT_OF_MEMORY_ERROR;
898 goto done;
901 r->value.update.name = name;
902 memcpy(r->value.update.name, scratch->buf, scratch->len);
903 r->value.update.name[scratch->len] = 0;
906 n = decode_string(scratch, in);
907 if (n < 0) {
908 err = REFTABLE_FORMAT_ERROR;
909 goto done;
911 string_view_consume(&in, n);
913 /* Same as above, but for the reflog email. */
914 if (!r->value.update.email ||
915 strcmp(r->value.update.email, scratch->buf)) {
916 char *email = reftable_realloc(r->value.update.email, scratch->len + 1);
917 if (!email) {
918 err = REFTABLE_OUT_OF_MEMORY_ERROR;
919 goto done;
922 r->value.update.email = email;
923 memcpy(r->value.update.email, scratch->buf, scratch->len);
924 r->value.update.email[scratch->len] = 0;
927 ts = 0;
928 n = get_var_int(&ts, &in);
929 if (n < 0) {
930 err = REFTABLE_FORMAT_ERROR;
931 goto done;
933 string_view_consume(&in, n);
934 r->value.update.time = ts;
935 if (in.len < 2) {
936 err = REFTABLE_FORMAT_ERROR;
937 goto done;
940 r->value.update.tz_offset = get_be16(in.buf);
941 string_view_consume(&in, 2);
943 n = decode_string(scratch, in);
944 if (n < 0) {
945 err = REFTABLE_FORMAT_ERROR;
946 goto done;
948 string_view_consume(&in, n);
950 REFTABLE_ALLOC_GROW(r->value.update.message, scratch->len + 1,
951 r->value.update.message_cap);
952 if (!r->value.update.message) {
953 err = REFTABLE_OUT_OF_MEMORY_ERROR;
954 goto done;
957 memcpy(r->value.update.message, scratch->buf, scratch->len);
958 r->value.update.message[scratch->len] = 0;
960 return start.len - in.len;
962 done:
963 return err;
966 static int null_streq(const char *a, const char *b)
968 const char *empty = "";
969 if (!a)
970 a = empty;
972 if (!b)
973 b = empty;
975 return 0 == strcmp(a, b);
978 static int reftable_log_record_equal_void(const void *a,
979 const void *b, int hash_size)
981 return reftable_log_record_equal((struct reftable_log_record *) a,
982 (struct reftable_log_record *) b,
983 hash_size);
986 static int reftable_log_record_cmp_void(const void *_a, const void *_b)
988 const struct reftable_log_record *a = _a;
989 const struct reftable_log_record *b = _b;
990 int cmp = strcmp(a->refname, b->refname);
991 if (cmp)
992 return cmp;
995 * Note that the comparison here is reversed. This is because the
996 * update index is reversed when comparing keys. For reference, see how
997 * we handle this in reftable_log_record_key()`.
999 return b->update_index - a->update_index;
1002 int reftable_log_record_equal(const struct reftable_log_record *a,
1003 const struct reftable_log_record *b, int hash_size)
1005 if (!(null_streq(a->refname, b->refname) &&
1006 a->update_index == b->update_index &&
1007 a->value_type == b->value_type))
1008 return 0;
1010 switch (a->value_type) {
1011 case REFTABLE_LOG_DELETION:
1012 return 1;
1013 case REFTABLE_LOG_UPDATE:
1014 return null_streq(a->value.update.name, b->value.update.name) &&
1015 a->value.update.time == b->value.update.time &&
1016 a->value.update.tz_offset == b->value.update.tz_offset &&
1017 null_streq(a->value.update.email,
1018 b->value.update.email) &&
1019 null_streq(a->value.update.message,
1020 b->value.update.message) &&
1021 !memcmp(a->value.update.old_hash,
1022 b->value.update.old_hash, hash_size) &&
1023 !memcmp(a->value.update.new_hash,
1024 b->value.update.new_hash, hash_size);
1027 abort();
1030 static int reftable_log_record_is_deletion_void(const void *p)
1032 return reftable_log_record_is_deletion(
1033 (const struct reftable_log_record *)p);
1036 static struct reftable_record_vtable reftable_log_record_vtable = {
1037 .key = &reftable_log_record_key,
1038 .type = BLOCK_TYPE_LOG,
1039 .copy_from = &reftable_log_record_copy_from,
1040 .val_type = &reftable_log_record_val_type,
1041 .encode = &reftable_log_record_encode,
1042 .decode = &reftable_log_record_decode,
1043 .release = &reftable_log_record_release_void,
1044 .is_deletion = &reftable_log_record_is_deletion_void,
1045 .equal = &reftable_log_record_equal_void,
1046 .cmp = &reftable_log_record_cmp_void,
1049 static int reftable_index_record_key(const void *r, struct reftable_buf *dest)
1051 const struct reftable_index_record *rec = r;
1052 reftable_buf_reset(dest);
1053 return reftable_buf_add(dest, rec->last_key.buf, rec->last_key.len);
1056 static int reftable_index_record_copy_from(void *rec, const void *src_rec,
1057 int hash_size UNUSED)
1059 struct reftable_index_record *dst = rec;
1060 const struct reftable_index_record *src = src_rec;
1061 int err;
1063 reftable_buf_reset(&dst->last_key);
1064 err = reftable_buf_add(&dst->last_key, src->last_key.buf, src->last_key.len);
1065 if (err < 0)
1066 return err;
1067 dst->offset = src->offset;
1069 return 0;
1072 static void reftable_index_record_release(void *rec)
1074 struct reftable_index_record *idx = rec;
1075 reftable_buf_release(&idx->last_key);
1078 static uint8_t reftable_index_record_val_type(const void *rec UNUSED)
1080 return 0;
1083 static int reftable_index_record_encode(const void *rec, struct string_view out,
1084 int hash_size UNUSED)
1086 const struct reftable_index_record *r =
1087 (const struct reftable_index_record *)rec;
1088 struct string_view start = out;
1090 int n = put_var_int(&out, r->offset);
1091 if (n < 0)
1092 return n;
1094 string_view_consume(&out, n);
1096 return start.len - out.len;
1099 static int reftable_index_record_decode(void *rec, struct reftable_buf key,
1100 uint8_t val_type UNUSED,
1101 struct string_view in,
1102 int hash_size UNUSED,
1103 struct reftable_buf *scratch UNUSED)
1105 struct string_view start = in;
1106 struct reftable_index_record *r = rec;
1107 int err, n = 0;
1109 reftable_buf_reset(&r->last_key);
1110 err = reftable_buf_add(&r->last_key, key.buf, key.len);
1111 if (err < 0)
1112 return err;
1114 n = get_var_int(&r->offset, &in);
1115 if (n < 0)
1116 return n;
1118 string_view_consume(&in, n);
1119 return start.len - in.len;
1122 static int reftable_index_record_equal(const void *a, const void *b,
1123 int hash_size UNUSED)
1125 struct reftable_index_record *ia = (struct reftable_index_record *) a;
1126 struct reftable_index_record *ib = (struct reftable_index_record *) b;
1128 return ia->offset == ib->offset && !reftable_buf_cmp(&ia->last_key, &ib->last_key);
1131 static int reftable_index_record_cmp(const void *_a, const void *_b)
1133 const struct reftable_index_record *a = _a;
1134 const struct reftable_index_record *b = _b;
1135 return reftable_buf_cmp(&a->last_key, &b->last_key);
1138 static struct reftable_record_vtable reftable_index_record_vtable = {
1139 .key = &reftable_index_record_key,
1140 .type = BLOCK_TYPE_INDEX,
1141 .copy_from = &reftable_index_record_copy_from,
1142 .val_type = &reftable_index_record_val_type,
1143 .encode = &reftable_index_record_encode,
1144 .decode = &reftable_index_record_decode,
1145 .release = &reftable_index_record_release,
1146 .is_deletion = &not_a_deletion,
1147 .equal = &reftable_index_record_equal,
1148 .cmp = &reftable_index_record_cmp,
1151 int reftable_record_key(struct reftable_record *rec, struct reftable_buf *dest)
1153 return reftable_record_vtable(rec)->key(reftable_record_data(rec), dest);
1156 int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
1157 int hash_size)
1159 return reftable_record_vtable(rec)->encode(reftable_record_data(rec),
1160 dest, hash_size);
1163 int reftable_record_copy_from(struct reftable_record *rec,
1164 struct reftable_record *src, int hash_size)
1166 assert(src->type == rec->type);
1168 return reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
1169 reftable_record_data(src),
1170 hash_size);
1173 uint8_t reftable_record_val_type(struct reftable_record *rec)
1175 return reftable_record_vtable(rec)->val_type(reftable_record_data(rec));
1178 int reftable_record_decode(struct reftable_record *rec, struct reftable_buf key,
1179 uint8_t extra, struct string_view src, int hash_size,
1180 struct reftable_buf *scratch)
1182 return reftable_record_vtable(rec)->decode(reftable_record_data(rec),
1183 key, extra, src, hash_size,
1184 scratch);
1187 void reftable_record_release(struct reftable_record *rec)
1189 reftable_record_vtable(rec)->release(reftable_record_data(rec));
1192 int reftable_record_is_deletion(struct reftable_record *rec)
1194 return reftable_record_vtable(rec)->is_deletion(
1195 reftable_record_data(rec));
1198 int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b)
1200 if (a->type != b->type)
1201 BUG("cannot compare reftable records of different type");
1202 return reftable_record_vtable(a)->cmp(
1203 reftable_record_data(a), reftable_record_data(b));
1206 int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size)
1208 if (a->type != b->type)
1209 return 0;
1210 return reftable_record_vtable(a)->equal(
1211 reftable_record_data(a), reftable_record_data(b), hash_size);
1214 static int hash_equal(const unsigned char *a, const unsigned char *b, int hash_size)
1216 if (a && b)
1217 return !memcmp(a, b, hash_size);
1219 return a == b;
1222 int reftable_ref_record_equal(const struct reftable_ref_record *a,
1223 const struct reftable_ref_record *b, int hash_size)
1225 assert(hash_size > 0);
1226 if (!null_streq(a->refname, b->refname))
1227 return 0;
1229 if (a->update_index != b->update_index ||
1230 a->value_type != b->value_type)
1231 return 0;
1233 switch (a->value_type) {
1234 case REFTABLE_REF_SYMREF:
1235 return !strcmp(a->value.symref, b->value.symref);
1236 case REFTABLE_REF_VAL2:
1237 return hash_equal(a->value.val2.value, b->value.val2.value,
1238 hash_size) &&
1239 hash_equal(a->value.val2.target_value,
1240 b->value.val2.target_value, hash_size);
1241 case REFTABLE_REF_VAL1:
1242 return hash_equal(a->value.val1, b->value.val1, hash_size);
1243 case REFTABLE_REF_DELETION:
1244 return 1;
1245 default:
1246 abort();
1250 int reftable_ref_record_compare_name(const void *a, const void *b)
1252 return strcmp(((struct reftable_ref_record *)a)->refname,
1253 ((struct reftable_ref_record *)b)->refname);
1256 int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref)
1258 return ref->value_type == REFTABLE_REF_DELETION;
1261 int reftable_log_record_compare_key(const void *a, const void *b)
1263 const struct reftable_log_record *la = a;
1264 const struct reftable_log_record *lb = b;
1266 int cmp = strcmp(la->refname, lb->refname);
1267 if (cmp)
1268 return cmp;
1269 if (la->update_index > lb->update_index)
1270 return -1;
1271 return (la->update_index < lb->update_index) ? 1 : 0;
1274 int reftable_log_record_is_deletion(const struct reftable_log_record *log)
1276 return (log->value_type == REFTABLE_LOG_DELETION);
1279 static void *reftable_record_data(struct reftable_record *rec)
1281 switch (rec->type) {
1282 case BLOCK_TYPE_REF:
1283 return &rec->u.ref;
1284 case BLOCK_TYPE_LOG:
1285 return &rec->u.log;
1286 case BLOCK_TYPE_INDEX:
1287 return &rec->u.idx;
1288 case BLOCK_TYPE_OBJ:
1289 return &rec->u.obj;
1291 abort();
1294 static struct reftable_record_vtable *
1295 reftable_record_vtable(struct reftable_record *rec)
1297 switch (rec->type) {
1298 case BLOCK_TYPE_REF:
1299 return &reftable_ref_record_vtable;
1300 case BLOCK_TYPE_LOG:
1301 return &reftable_log_record_vtable;
1302 case BLOCK_TYPE_INDEX:
1303 return &reftable_index_record_vtable;
1304 case BLOCK_TYPE_OBJ:
1305 return &reftable_obj_record_vtable;
1307 abort();
1310 void reftable_record_init(struct reftable_record *rec, uint8_t typ)
1312 memset(rec, 0, sizeof(*rec));
1313 rec->type = typ;
1315 switch (typ) {
1316 case BLOCK_TYPE_REF:
1317 case BLOCK_TYPE_LOG:
1318 case BLOCK_TYPE_OBJ:
1319 return;
1320 case BLOCK_TYPE_INDEX:
1321 reftable_buf_init(&rec->u.idx.last_key);
1322 return;
1323 default:
1324 BUG("unhandled record type");