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
9 /* record.c - methods for different types of records. */
14 #include "constants.h"
15 #include "reftable-error.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
)
29 val
= in
->buf
[ptr
] & 0x7f;
31 while (in
->buf
[ptr
] & 0x80) {
36 val
= (val
+ 1) << 7 | (uint64_t)(in
->buf
[ptr
] & 0x7f);
43 int put_var_int(struct string_view
*dest
, uint64_t val
)
45 uint8_t buf
[10] = { 0 };
48 buf
[i
] = (uint8_t)(val
& 0x7f);
56 buf
[i
] = 0x80 | (uint8_t)(val
& 0x7f);
60 n
= sizeof(buf
) - i
- 1;
63 memcpy(dest
->buf
, &buf
[i
+ 1], n
);
67 int reftable_is_block_type(uint8_t typ
)
73 case BLOCK_TYPE_INDEX
:
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
;
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
;
101 static int decode_string(struct reftable_buf
*dest
, struct string_view in
)
103 int start_len
= in
.len
;
107 n
= get_var_int(&tsize
, &in
);
110 string_view_consume(&in
, n
);
114 reftable_buf_reset(dest
);
115 err
= reftable_buf_add(dest
, in
.buf
, tsize
);
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
;
128 int n
= put_var_int(&s
, l
);
131 string_view_consume(&s
, n
);
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
,
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
);
150 string_view_consume(&dest
, n
);
152 *restart
= (prefix_len
== 0);
154 n
= put_var_int(&dest
, suffix_len
<< 3 | (uint64_t)extra
);
157 string_view_consume(&dest
, n
);
159 if (dest
.len
< suffix_len
)
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
,
172 size_t start_len
= in
.len
;
175 n
= get_var_int(prefix_len
, &in
);
178 string_view_consume(&in
, n
);
180 n
= get_var_int(suffix_len
, &in
);
183 string_view_consume(&in
, n
);
185 *extra
= (uint8_t)(*suffix_len
& 0x7);
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;
199 n
= reftable_decode_keylen(in
, &prefix_len
, &suffix_len
, extra
);
202 string_view_consume(&in
, n
);
204 if (in
.len
< suffix_len
||
205 prefix_len
> last_key
->len
)
208 err
= reftable_buf_setlen(last_key
, prefix_len
);
212 err
= reftable_buf_add(last_key
, in
.buf
, suffix_len
);
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
,
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;
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
);
247 size_t refname_len
= strlen(src
->refname
);
249 REFTABLE_ALLOC_GROW(ref
->refname
, refname_len
+ 1,
252 err
= REFTABLE_OUT_OF_MEMORY_ERROR
;
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
:
265 case REFTABLE_REF_VAL1
:
266 memcpy(ref
->value
.val1
, src
->value
.val1
, hash_size
);
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
);
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
;
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
);
298 case REFTABLE_REF_VAL2
:
300 case REFTABLE_REF_VAL1
:
302 case REFTABLE_REF_DELETION
:
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
,
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);
329 string_view_consume(&s
, n
);
331 switch (r
->value_type
) {
332 case REFTABLE_REF_SYMREF
:
333 n
= encode_string(r
->value
.symref
, s
);
337 string_view_consume(&s
, n
);
339 case REFTABLE_REF_VAL2
:
340 if (s
.len
< 2 * hash_size
) {
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
);
348 case REFTABLE_REF_VAL1
:
349 if (s
.len
< hash_size
) {
352 memcpy(s
.buf
, r
->value
.val1
, hash_size
);
353 string_view_consume(&s
, hash_size
);
355 case REFTABLE_REF_DELETION
:
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;
375 assert(hash_size
> 0);
377 n
= get_var_int(&update_index
, &in
);
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
);
390 err
= REFTABLE_OUT_OF_MEMORY_ERROR
;
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
;
399 case REFTABLE_REF_VAL1
:
400 if (in
.len
< hash_size
) {
401 err
= REFTABLE_FORMAT_ERROR
;
405 memcpy(r
->value
.val1
, in
.buf
, hash_size
);
406 string_view_consume(&in
, hash_size
);
409 case REFTABLE_REF_VAL2
:
410 if (in
.len
< 2 * hash_size
) {
411 err
= REFTABLE_FORMAT_ERROR
;
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
);
422 case REFTABLE_REF_SYMREF
: {
423 int n
= decode_string(scratch
, in
);
425 err
= REFTABLE_FORMAT_ERROR
;
428 string_view_consume(&in
, n
);
429 r
->value
.symref
= reftable_buf_detach(scratch
);
432 case REFTABLE_REF_DELETION
:
439 return start
.len
- in
.len
;
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
);
512 return REFTABLE_OUT_OF_MEMORY_ERROR
;
513 obj
->offset_len
= src
->offset_len
;
514 COPY_ARRAY(obj
->offsets
, src
->offsets
, src
->offset_len
);
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
;
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
;
535 if (r
->offset_len
== 0 || r
->offset_len
>= 8) {
536 n
= put_var_int(&s
, r
->offset_len
);
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]);
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
);
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
;
573 reftable_obj_record_release(r
);
575 REFTABLE_ALLOC_ARRAY(r
->hash_prefix
, key
.len
);
577 return REFTABLE_OUT_OF_MEMORY_ERROR
;
578 memcpy(r
->hash_prefix
, key
.buf
, key
.len
);
579 r
->hash_prefix_len
= key
.len
;
582 n
= get_var_int(&count
, &in
);
587 string_view_consume(&in
, n
);
593 return start
.len
- in
.len
;
595 REFTABLE_ALLOC_ARRAY(r
->offsets
, count
);
597 return REFTABLE_OUT_OF_MEMORY_ERROR
;
598 r
->offset_len
= count
;
600 n
= get_var_int(&r
->offsets
[0], &in
);
603 string_view_consume(&in
, n
);
605 last
= r
->offsets
[0];
609 int n
= get_var_int(&delta
, &in
);
613 string_view_consume(&in
, n
);
615 last
= r
->offsets
[j
] = (delta
+ last
);
618 return start
.len
- in
.len
;
621 static int not_a_deletion(const void *p UNUSED
)
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
)
636 if (ra
->hash_prefix_len
&&
637 memcmp(ra
->hash_prefix
, rb
->hash_prefix
, ra
->hash_prefix_len
))
639 if (ra
->offset_len
&&
640 memcmp(ra
->offsets
, rb
->offsets
, ra
->offset_len
* sizeof(uint64_t)))
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
;
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
);
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
= ¬_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
;
686 reftable_buf_reset(dest
);
687 err
= reftable_buf_add(dest
, (uint8_t *)rec
->refname
, len
+ 1);
691 ts
= (~ts
) - rec
->update_index
;
692 put_be64(&i64
[0], ts
);
694 err
= reftable_buf_add(dest
, i64
, sizeof(i64
));
701 static int reftable_log_record_copy_from(void *rec
, const void *src_rec
,
704 struct reftable_log_record
*dst
= rec
;
705 const struct reftable_log_record
*src
=
706 (const struct reftable_log_record
*)src_rec
;
709 reftable_log_record_release(dst
);
713 dst
->refname
= reftable_strdup(dst
->refname
);
715 ret
= REFTABLE_OUT_OF_MEMORY_ERROR
;
720 switch (dst
->value_type
) {
721 case REFTABLE_LOG_DELETION
:
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
;
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
);
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
:
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
);
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
,
785 const struct reftable_log_record
*r
= rec
;
786 struct string_view start
= s
;
788 if (reftable_log_record_is_deletion(r
))
791 if (s
.len
< 2 * hash_size
)
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
);
801 string_view_consume(&s
, n
);
803 n
= encode_string(r
->value
.update
.email
? r
->value
.update
.email
: "",
807 string_view_consume(&s
, n
);
809 n
= put_var_int(&s
, r
->value
.update
.time
);
812 string_view_consume(&s
, n
);
817 put_be16(s
.buf
, r
->value
.update
.tz_offset
);
818 string_view_consume(&s
, 2);
821 r
->value
.update
.message
? r
->value
.update
.message
: "", s
);
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
;
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
);
844 err
= REFTABLE_OUT_OF_MEMORY_ERROR
;
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
);
861 case REFTABLE_LOG_DELETION
:
866 r
->value_type
= val_type
;
867 if (val_type
== REFTABLE_LOG_DELETION
)
870 if (in
.len
< 2 * hash_size
) {
871 err
= REFTABLE_FORMAT_ERROR
;
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
);
882 err
= REFTABLE_FORMAT_ERROR
;
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);
897 err
= REFTABLE_OUT_OF_MEMORY_ERROR
;
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
);
908 err
= REFTABLE_FORMAT_ERROR
;
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);
918 err
= REFTABLE_OUT_OF_MEMORY_ERROR
;
922 r
->value
.update
.email
= email
;
923 memcpy(r
->value
.update
.email
, scratch
->buf
, scratch
->len
);
924 r
->value
.update
.email
[scratch
->len
] = 0;
928 n
= get_var_int(&ts
, &in
);
930 err
= REFTABLE_FORMAT_ERROR
;
933 string_view_consume(&in
, n
);
934 r
->value
.update
.time
= ts
;
936 err
= REFTABLE_FORMAT_ERROR
;
940 r
->value
.update
.tz_offset
= get_be16(in
.buf
);
941 string_view_consume(&in
, 2);
943 n
= decode_string(scratch
, in
);
945 err
= REFTABLE_FORMAT_ERROR
;
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
;
957 memcpy(r
->value
.update
.message
, scratch
->buf
, scratch
->len
);
958 r
->value
.update
.message
[scratch
->len
] = 0;
960 return start
.len
- in
.len
;
966 static int null_streq(const char *a
, const char *b
)
968 const char *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
,
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
);
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
))
1010 switch (a
->value_type
) {
1011 case REFTABLE_LOG_DELETION
:
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
);
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
;
1063 reftable_buf_reset(&dst
->last_key
);
1064 err
= reftable_buf_add(&dst
->last_key
, src
->last_key
.buf
, src
->last_key
.len
);
1067 dst
->offset
= src
->offset
;
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
)
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
);
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
;
1109 reftable_buf_reset(&r
->last_key
);
1110 err
= reftable_buf_add(&r
->last_key
, key
.buf
, key
.len
);
1114 n
= get_var_int(&r
->offset
, &in
);
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
= ¬_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
,
1159 return reftable_record_vtable(rec
)->encode(reftable_record_data(rec
),
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
),
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
,
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
)
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
)
1217 return !memcmp(a
, b
, hash_size
);
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
))
1229 if (a
->update_index
!= b
->update_index
||
1230 a
->value_type
!= b
->value_type
)
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
,
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
:
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
);
1269 if (la
->update_index
> lb
->update_index
)
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
:
1284 case BLOCK_TYPE_LOG
:
1286 case BLOCK_TYPE_INDEX
:
1288 case BLOCK_TYPE_OBJ
:
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
;
1310 void reftable_record_init(struct reftable_record
*rec
, uint8_t typ
)
1312 memset(rec
, 0, sizeof(*rec
));
1316 case BLOCK_TYPE_REF
:
1317 case BLOCK_TYPE_LOG
:
1318 case BLOCK_TYPE_OBJ
:
1320 case BLOCK_TYPE_INDEX
:
1321 reftable_buf_init(&rec
->u
.idx
.last_key
);
1324 BUG("unhandled record type");