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 strbuf
*dest
, struct string_view in
)
103 int start_len
= in
.len
;
105 int n
= get_var_int(&tsize
, &in
);
108 string_view_consume(&in
, n
);
113 strbuf_add(dest
, in
.buf
, tsize
);
114 string_view_consume(&in
, tsize
);
116 return start_len
- in
.len
;
119 static int encode_string(char *str
, struct string_view s
)
121 struct string_view start
= s
;
123 int n
= put_var_int(&s
, l
);
126 string_view_consume(&s
, n
);
129 memcpy(s
.buf
, str
, l
);
130 string_view_consume(&s
, l
);
132 return start
.len
- s
.len
;
135 int reftable_encode_key(int *restart
, struct string_view dest
,
136 struct strbuf prev_key
, struct strbuf key
,
139 struct string_view start
= dest
;
140 int prefix_len
= common_prefix_size(&prev_key
, &key
);
141 uint64_t suffix_len
= key
.len
- prefix_len
;
142 int n
= put_var_int(&dest
, (uint64_t)prefix_len
);
145 string_view_consume(&dest
, n
);
147 *restart
= (prefix_len
== 0);
149 n
= put_var_int(&dest
, suffix_len
<< 3 | (uint64_t)extra
);
152 string_view_consume(&dest
, n
);
154 if (dest
.len
< suffix_len
)
156 memcpy(dest
.buf
, key
.buf
+ prefix_len
, suffix_len
);
157 string_view_consume(&dest
, suffix_len
);
159 return start
.len
- dest
.len
;
162 int reftable_decode_keylen(struct string_view in
,
163 uint64_t *prefix_len
,
164 uint64_t *suffix_len
,
167 size_t start_len
= in
.len
;
170 n
= get_var_int(prefix_len
, &in
);
173 string_view_consume(&in
, n
);
175 n
= get_var_int(suffix_len
, &in
);
178 string_view_consume(&in
, n
);
180 *extra
= (uint8_t)(*suffix_len
& 0x7);
183 return start_len
- in
.len
;
186 int reftable_decode_key(struct strbuf
*last_key
, uint8_t *extra
,
187 struct string_view in
)
189 int start_len
= in
.len
;
190 uint64_t prefix_len
= 0;
191 uint64_t suffix_len
= 0;
194 n
= reftable_decode_keylen(in
, &prefix_len
, &suffix_len
, extra
);
197 string_view_consume(&in
, n
);
199 if (in
.len
< suffix_len
||
200 prefix_len
> last_key
->len
)
203 strbuf_setlen(last_key
, prefix_len
);
204 strbuf_add(last_key
, in
.buf
, suffix_len
);
205 string_view_consume(&in
, suffix_len
);
207 return start_len
- in
.len
;
210 static void reftable_ref_record_key(const void *r
, struct strbuf
*dest
)
212 const struct reftable_ref_record
*rec
=
213 (const struct reftable_ref_record
*)r
;
215 strbuf_addstr(dest
, rec
->refname
);
218 static void reftable_ref_record_copy_from(void *rec
, const void *src_rec
,
221 struct reftable_ref_record
*ref
= rec
;
222 const struct reftable_ref_record
*src
= src_rec
;
223 char *refname
= NULL
;
224 size_t refname_cap
= 0;
226 assert(hash_size
> 0);
228 SWAP(refname
, ref
->refname
);
229 SWAP(refname_cap
, ref
->refname_cap
);
230 reftable_ref_record_release(ref
);
231 SWAP(ref
->refname
, refname
);
232 SWAP(ref
->refname_cap
, refname_cap
);
235 size_t refname_len
= strlen(src
->refname
);
237 REFTABLE_ALLOC_GROW(ref
->refname
, refname_len
+ 1,
239 memcpy(ref
->refname
, src
->refname
, refname_len
);
240 ref
->refname
[refname_len
] = 0;
243 ref
->update_index
= src
->update_index
;
244 ref
->value_type
= src
->value_type
;
245 switch (src
->value_type
) {
246 case REFTABLE_REF_DELETION
:
248 case REFTABLE_REF_VAL1
:
249 memcpy(ref
->value
.val1
, src
->value
.val1
, hash_size
);
251 case REFTABLE_REF_VAL2
:
252 memcpy(ref
->value
.val2
.value
, src
->value
.val2
.value
, hash_size
);
253 memcpy(ref
->value
.val2
.target_value
,
254 src
->value
.val2
.target_value
, hash_size
);
256 case REFTABLE_REF_SYMREF
:
257 ref
->value
.symref
= xstrdup(src
->value
.symref
);
262 static char hexdigit(int c
)
266 return 'a' + (c
- 10);
269 static void hex_format(char *dest
, const unsigned char *src
, int hash_size
)
271 assert(hash_size
> 0);
274 for (i
= 0; i
< hash_size
; i
++) {
275 dest
[2 * i
] = hexdigit(src
[i
] >> 4);
276 dest
[2 * i
+ 1] = hexdigit(src
[i
] & 0xf);
278 dest
[2 * hash_size
] = 0;
282 static void reftable_ref_record_print_sz(const struct reftable_ref_record
*ref
,
285 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 }; /* BUG */
286 printf("ref{%s(%" PRIu64
") ", ref
->refname
, ref
->update_index
);
287 switch (ref
->value_type
) {
288 case REFTABLE_REF_SYMREF
:
289 printf("=> %s", ref
->value
.symref
);
291 case REFTABLE_REF_VAL2
:
292 hex_format(hex
, ref
->value
.val2
.value
, hash_size
);
293 printf("val 2 %s", hex
);
294 hex_format(hex
, ref
->value
.val2
.target_value
,
296 printf("(T %s)", hex
);
298 case REFTABLE_REF_VAL1
:
299 hex_format(hex
, ref
->value
.val1
, hash_size
);
300 printf("val 1 %s", hex
);
302 case REFTABLE_REF_DELETION
:
309 void reftable_ref_record_print(const struct reftable_ref_record
*ref
,
311 reftable_ref_record_print_sz(ref
, hash_size(hash_id
));
314 static void reftable_ref_record_release_void(void *rec
)
316 reftable_ref_record_release(rec
);
319 void reftable_ref_record_release(struct reftable_ref_record
*ref
)
321 switch (ref
->value_type
) {
322 case REFTABLE_REF_SYMREF
:
323 reftable_free(ref
->value
.symref
);
325 case REFTABLE_REF_VAL2
:
327 case REFTABLE_REF_VAL1
:
329 case REFTABLE_REF_DELETION
:
335 reftable_free(ref
->refname
);
336 memset(ref
, 0, sizeof(struct reftable_ref_record
));
339 static uint8_t reftable_ref_record_val_type(const void *rec
)
341 const struct reftable_ref_record
*r
=
342 (const struct reftable_ref_record
*)rec
;
343 return r
->value_type
;
346 static int reftable_ref_record_encode(const void *rec
, struct string_view s
,
349 const struct reftable_ref_record
*r
=
350 (const struct reftable_ref_record
*)rec
;
351 struct string_view start
= s
;
352 int n
= put_var_int(&s
, r
->update_index
);
353 assert(hash_size
> 0);
356 string_view_consume(&s
, n
);
358 switch (r
->value_type
) {
359 case REFTABLE_REF_SYMREF
:
360 n
= encode_string(r
->value
.symref
, s
);
364 string_view_consume(&s
, n
);
366 case REFTABLE_REF_VAL2
:
367 if (s
.len
< 2 * hash_size
) {
370 memcpy(s
.buf
, r
->value
.val2
.value
, hash_size
);
371 string_view_consume(&s
, hash_size
);
372 memcpy(s
.buf
, r
->value
.val2
.target_value
, hash_size
);
373 string_view_consume(&s
, hash_size
);
375 case REFTABLE_REF_VAL1
:
376 if (s
.len
< hash_size
) {
379 memcpy(s
.buf
, r
->value
.val1
, hash_size
);
380 string_view_consume(&s
, hash_size
);
382 case REFTABLE_REF_DELETION
:
388 return start
.len
- s
.len
;
391 static int reftable_ref_record_decode(void *rec
, struct strbuf key
,
392 uint8_t val_type
, struct string_view in
,
393 int hash_size
, struct strbuf
*scratch
)
395 struct reftable_ref_record
*r
= rec
;
396 struct string_view start
= in
;
397 uint64_t update_index
= 0;
398 const char *refname
= NULL
;
399 size_t refname_cap
= 0;
402 assert(hash_size
> 0);
404 n
= get_var_int(&update_index
, &in
);
407 string_view_consume(&in
, n
);
409 SWAP(refname
, r
->refname
);
410 SWAP(refname_cap
, r
->refname_cap
);
411 reftable_ref_record_release(r
);
412 SWAP(r
->refname
, refname
);
413 SWAP(r
->refname_cap
, refname_cap
);
415 REFTABLE_ALLOC_GROW(r
->refname
, key
.len
+ 1, r
->refname_cap
);
416 memcpy(r
->refname
, key
.buf
, key
.len
);
417 r
->refname
[key
.len
] = 0;
419 r
->update_index
= update_index
;
420 r
->value_type
= val_type
;
422 case REFTABLE_REF_VAL1
:
423 if (in
.len
< hash_size
) {
427 memcpy(r
->value
.val1
, in
.buf
, hash_size
);
428 string_view_consume(&in
, hash_size
);
431 case REFTABLE_REF_VAL2
:
432 if (in
.len
< 2 * hash_size
) {
436 memcpy(r
->value
.val2
.value
, in
.buf
, hash_size
);
437 string_view_consume(&in
, hash_size
);
439 memcpy(r
->value
.val2
.target_value
, in
.buf
, hash_size
);
440 string_view_consume(&in
, hash_size
);
443 case REFTABLE_REF_SYMREF
: {
444 int n
= decode_string(scratch
, in
);
448 string_view_consume(&in
, n
);
449 r
->value
.symref
= strbuf_detach(scratch
, NULL
);
452 case REFTABLE_REF_DELETION
:
459 return start
.len
- in
.len
;
462 static int reftable_ref_record_is_deletion_void(const void *p
)
464 return reftable_ref_record_is_deletion(
465 (const struct reftable_ref_record
*)p
);
468 static int reftable_ref_record_equal_void(const void *a
,
469 const void *b
, int hash_size
)
471 struct reftable_ref_record
*ra
= (struct reftable_ref_record
*) a
;
472 struct reftable_ref_record
*rb
= (struct reftable_ref_record
*) b
;
473 return reftable_ref_record_equal(ra
, rb
, hash_size
);
476 static int reftable_ref_record_cmp_void(const void *_a
, const void *_b
)
478 const struct reftable_ref_record
*a
= _a
;
479 const struct reftable_ref_record
*b
= _b
;
480 return strcmp(a
->refname
, b
->refname
);
483 static void reftable_ref_record_print_void(const void *rec
,
486 reftable_ref_record_print_sz((struct reftable_ref_record
*) rec
, hash_size
);
489 static struct reftable_record_vtable reftable_ref_record_vtable
= {
490 .key
= &reftable_ref_record_key
,
491 .type
= BLOCK_TYPE_REF
,
492 .copy_from
= &reftable_ref_record_copy_from
,
493 .val_type
= &reftable_ref_record_val_type
,
494 .encode
= &reftable_ref_record_encode
,
495 .decode
= &reftable_ref_record_decode
,
496 .release
= &reftable_ref_record_release_void
,
497 .is_deletion
= &reftable_ref_record_is_deletion_void
,
498 .equal
= &reftable_ref_record_equal_void
,
499 .cmp
= &reftable_ref_record_cmp_void
,
500 .print
= &reftable_ref_record_print_void
,
503 static void reftable_obj_record_key(const void *r
, struct strbuf
*dest
)
505 const struct reftable_obj_record
*rec
=
506 (const struct reftable_obj_record
*)r
;
508 strbuf_add(dest
, rec
->hash_prefix
, rec
->hash_prefix_len
);
511 static void reftable_obj_record_release(void *rec
)
513 struct reftable_obj_record
*obj
= rec
;
514 FREE_AND_NULL(obj
->hash_prefix
);
515 FREE_AND_NULL(obj
->offsets
);
516 memset(obj
, 0, sizeof(struct reftable_obj_record
));
519 static void reftable_obj_record_print(const void *rec
, int hash_size
)
521 const struct reftable_obj_record
*obj
= rec
;
522 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 };
523 struct strbuf offset_str
= STRBUF_INIT
;
526 for (i
= 0; i
< obj
->offset_len
; i
++)
527 strbuf_addf(&offset_str
, "%" PRIu64
" ", obj
->offsets
[i
]);
528 hex_format(hex
, obj
->hash_prefix
, obj
->hash_prefix_len
);
529 printf("prefix %s (len %d), offsets [%s]\n",
530 hex
, obj
->hash_prefix_len
, offset_str
.buf
);
531 strbuf_release(&offset_str
);
534 static void reftable_obj_record_copy_from(void *rec
, const void *src_rec
,
537 struct reftable_obj_record
*obj
= rec
;
538 const struct reftable_obj_record
*src
=
539 (const struct reftable_obj_record
*)src_rec
;
541 reftable_obj_record_release(obj
);
543 REFTABLE_ALLOC_ARRAY(obj
->hash_prefix
, src
->hash_prefix_len
);
544 obj
->hash_prefix_len
= src
->hash_prefix_len
;
545 if (src
->hash_prefix_len
)
546 memcpy(obj
->hash_prefix
, src
->hash_prefix
, obj
->hash_prefix_len
);
548 REFTABLE_ALLOC_ARRAY(obj
->offsets
, src
->offset_len
);
549 obj
->offset_len
= src
->offset_len
;
550 COPY_ARRAY(obj
->offsets
, src
->offsets
, src
->offset_len
);
553 static uint8_t reftable_obj_record_val_type(const void *rec
)
555 const struct reftable_obj_record
*r
= rec
;
556 if (r
->offset_len
> 0 && r
->offset_len
< 8)
557 return r
->offset_len
;
561 static int reftable_obj_record_encode(const void *rec
, struct string_view s
,
564 const struct reftable_obj_record
*r
= rec
;
565 struct string_view start
= s
;
569 if (r
->offset_len
== 0 || r
->offset_len
>= 8) {
570 n
= put_var_int(&s
, r
->offset_len
);
574 string_view_consume(&s
, n
);
576 if (r
->offset_len
== 0)
577 return start
.len
- s
.len
;
578 n
= put_var_int(&s
, r
->offsets
[0]);
581 string_view_consume(&s
, n
);
583 last
= r
->offsets
[0];
584 for (i
= 1; i
< r
->offset_len
; i
++) {
585 int n
= put_var_int(&s
, r
->offsets
[i
] - last
);
589 string_view_consume(&s
, n
);
590 last
= r
->offsets
[i
];
592 return start
.len
- s
.len
;
595 static int reftable_obj_record_decode(void *rec
, struct strbuf key
,
596 uint8_t val_type
, struct string_view in
,
597 int hash_size
, struct strbuf
*scratch UNUSED
)
599 struct string_view start
= in
;
600 struct reftable_obj_record
*r
= rec
;
601 uint64_t count
= val_type
;
606 reftable_obj_record_release(r
);
608 REFTABLE_ALLOC_ARRAY(r
->hash_prefix
, key
.len
);
609 memcpy(r
->hash_prefix
, key
.buf
, key
.len
);
610 r
->hash_prefix_len
= key
.len
;
613 n
= get_var_int(&count
, &in
);
618 string_view_consume(&in
, n
);
624 return start
.len
- in
.len
;
626 REFTABLE_ALLOC_ARRAY(r
->offsets
, count
);
627 r
->offset_len
= count
;
629 n
= get_var_int(&r
->offsets
[0], &in
);
632 string_view_consume(&in
, n
);
634 last
= r
->offsets
[0];
638 int n
= get_var_int(&delta
, &in
);
642 string_view_consume(&in
, n
);
644 last
= r
->offsets
[j
] = (delta
+ last
);
647 return start
.len
- in
.len
;
650 static int not_a_deletion(const void *p
)
655 static int reftable_obj_record_equal_void(const void *a
, const void *b
, int hash_size
)
657 struct reftable_obj_record
*ra
= (struct reftable_obj_record
*) a
;
658 struct reftable_obj_record
*rb
= (struct reftable_obj_record
*) b
;
660 if (ra
->hash_prefix_len
!= rb
->hash_prefix_len
661 || ra
->offset_len
!= rb
->offset_len
)
664 if (ra
->hash_prefix_len
&&
665 memcmp(ra
->hash_prefix
, rb
->hash_prefix
, ra
->hash_prefix_len
))
667 if (ra
->offset_len
&&
668 memcmp(ra
->offsets
, rb
->offsets
, ra
->offset_len
* sizeof(uint64_t)))
674 static int reftable_obj_record_cmp_void(const void *_a
, const void *_b
)
676 const struct reftable_obj_record
*a
= _a
;
677 const struct reftable_obj_record
*b
= _b
;
680 cmp
= memcmp(a
->hash_prefix
, b
->hash_prefix
,
681 a
->hash_prefix_len
> b
->hash_prefix_len
?
682 a
->hash_prefix_len
: b
->hash_prefix_len
);
687 * When the prefix is the same then the object record that is longer is
688 * considered to be bigger.
690 return a
->hash_prefix_len
- b
->hash_prefix_len
;
693 static struct reftable_record_vtable reftable_obj_record_vtable
= {
694 .key
= &reftable_obj_record_key
,
695 .type
= BLOCK_TYPE_OBJ
,
696 .copy_from
= &reftable_obj_record_copy_from
,
697 .val_type
= &reftable_obj_record_val_type
,
698 .encode
= &reftable_obj_record_encode
,
699 .decode
= &reftable_obj_record_decode
,
700 .release
= &reftable_obj_record_release
,
701 .is_deletion
= ¬_a_deletion
,
702 .equal
= &reftable_obj_record_equal_void
,
703 .cmp
= &reftable_obj_record_cmp_void
,
704 .print
= &reftable_obj_record_print
,
707 static void reftable_log_record_print_sz(struct reftable_log_record
*log
,
710 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 };
712 switch (log
->value_type
) {
713 case REFTABLE_LOG_DELETION
:
714 printf("log{%s(%" PRIu64
") delete\n", log
->refname
,
717 case REFTABLE_LOG_UPDATE
:
718 printf("log{%s(%" PRIu64
") %s <%s> %" PRIu64
" %04d\n",
719 log
->refname
, log
->update_index
,
720 log
->value
.update
.name
? log
->value
.update
.name
: "",
721 log
->value
.update
.email
? log
->value
.update
.email
: "",
722 log
->value
.update
.time
,
723 log
->value
.update
.tz_offset
);
724 hex_format(hex
, log
->value
.update
.old_hash
, hash_size
);
725 printf("%s => ", hex
);
726 hex_format(hex
, log
->value
.update
.new_hash
, hash_size
);
727 printf("%s\n\n%s\n}\n", hex
,
728 log
->value
.update
.message
? log
->value
.update
.message
: "");
733 void reftable_log_record_print(struct reftable_log_record
*log
,
736 reftable_log_record_print_sz(log
, hash_size(hash_id
));
739 static void reftable_log_record_key(const void *r
, struct strbuf
*dest
)
741 const struct reftable_log_record
*rec
=
742 (const struct reftable_log_record
*)r
;
743 int len
= strlen(rec
->refname
);
747 strbuf_add(dest
, (uint8_t *)rec
->refname
, len
+ 1);
749 ts
= (~ts
) - rec
->update_index
;
750 put_be64(&i64
[0], ts
);
751 strbuf_add(dest
, i64
, sizeof(i64
));
754 static void reftable_log_record_copy_from(void *rec
, const void *src_rec
,
757 struct reftable_log_record
*dst
= rec
;
758 const struct reftable_log_record
*src
=
759 (const struct reftable_log_record
*)src_rec
;
761 reftable_log_record_release(dst
);
764 dst
->refname
= xstrdup(dst
->refname
);
766 switch (dst
->value_type
) {
767 case REFTABLE_LOG_DELETION
:
769 case REFTABLE_LOG_UPDATE
:
770 if (dst
->value
.update
.email
) {
771 dst
->value
.update
.email
=
772 xstrdup(dst
->value
.update
.email
);
774 if (dst
->value
.update
.name
) {
775 dst
->value
.update
.name
=
776 xstrdup(dst
->value
.update
.name
);
778 if (dst
->value
.update
.message
) {
779 dst
->value
.update
.message
=
780 xstrdup(dst
->value
.update
.message
);
783 memcpy(dst
->value
.update
.new_hash
,
784 src
->value
.update
.new_hash
, hash_size
);
785 memcpy(dst
->value
.update
.old_hash
,
786 src
->value
.update
.old_hash
, hash_size
);
791 static void reftable_log_record_release_void(void *rec
)
793 struct reftable_log_record
*r
= rec
;
794 reftable_log_record_release(r
);
797 void reftable_log_record_release(struct reftable_log_record
*r
)
799 reftable_free(r
->refname
);
800 switch (r
->value_type
) {
801 case REFTABLE_LOG_DELETION
:
803 case REFTABLE_LOG_UPDATE
:
804 reftable_free(r
->value
.update
.name
);
805 reftable_free(r
->value
.update
.email
);
806 reftable_free(r
->value
.update
.message
);
809 memset(r
, 0, sizeof(struct reftable_log_record
));
812 static uint8_t reftable_log_record_val_type(const void *rec
)
814 const struct reftable_log_record
*log
=
815 (const struct reftable_log_record
*)rec
;
817 return reftable_log_record_is_deletion(log
) ? 0 : 1;
820 static int reftable_log_record_encode(const void *rec
, struct string_view s
,
823 const struct reftable_log_record
*r
= rec
;
824 struct string_view start
= s
;
826 if (reftable_log_record_is_deletion(r
))
829 if (s
.len
< 2 * hash_size
)
832 memcpy(s
.buf
, r
->value
.update
.old_hash
, hash_size
);
833 memcpy(s
.buf
+ hash_size
, r
->value
.update
.new_hash
, hash_size
);
834 string_view_consume(&s
, 2 * hash_size
);
836 n
= encode_string(r
->value
.update
.name
? r
->value
.update
.name
: "", s
);
839 string_view_consume(&s
, n
);
841 n
= encode_string(r
->value
.update
.email
? r
->value
.update
.email
: "",
845 string_view_consume(&s
, n
);
847 n
= put_var_int(&s
, r
->value
.update
.time
);
850 string_view_consume(&s
, n
);
855 put_be16(s
.buf
, r
->value
.update
.tz_offset
);
856 string_view_consume(&s
, 2);
859 r
->value
.update
.message
? r
->value
.update
.message
: "", s
);
862 string_view_consume(&s
, n
);
864 return start
.len
- s
.len
;
867 static int reftable_log_record_decode(void *rec
, struct strbuf key
,
868 uint8_t val_type
, struct string_view in
,
869 int hash_size
, struct strbuf
*scratch
)
871 struct string_view start
= in
;
872 struct reftable_log_record
*r
= rec
;
877 if (key
.len
<= 9 || key
.buf
[key
.len
- 9] != 0)
878 return REFTABLE_FORMAT_ERROR
;
880 REFTABLE_ALLOC_GROW(r
->refname
, key
.len
- 8, r
->refname_cap
);
881 memcpy(r
->refname
, key
.buf
, key
.len
- 8);
882 ts
= get_be64(key
.buf
+ key
.len
- 8);
884 r
->update_index
= (~max
) - ts
;
886 if (val_type
!= r
->value_type
) {
887 switch (r
->value_type
) {
888 case REFTABLE_LOG_UPDATE
:
889 FREE_AND_NULL(r
->value
.update
.message
);
890 r
->value
.update
.message_cap
= 0;
891 FREE_AND_NULL(r
->value
.update
.email
);
892 FREE_AND_NULL(r
->value
.update
.name
);
894 case REFTABLE_LOG_DELETION
:
899 r
->value_type
= val_type
;
900 if (val_type
== REFTABLE_LOG_DELETION
)
903 if (in
.len
< 2 * hash_size
)
904 return REFTABLE_FORMAT_ERROR
;
906 memcpy(r
->value
.update
.old_hash
, in
.buf
, hash_size
);
907 memcpy(r
->value
.update
.new_hash
, in
.buf
+ hash_size
, hash_size
);
909 string_view_consume(&in
, 2 * hash_size
);
911 n
= decode_string(scratch
, in
);
914 string_view_consume(&in
, n
);
917 * In almost all cases we can expect the reflog name to not change for
918 * reflog entries as they are tied to the local identity, not to the
919 * target commits. As an optimization for this common case we can thus
920 * skip copying over the name in case it's accurate already.
922 if (!r
->value
.update
.name
||
923 strcmp(r
->value
.update
.name
, scratch
->buf
)) {
924 r
->value
.update
.name
=
925 reftable_realloc(r
->value
.update
.name
, scratch
->len
+ 1);
926 memcpy(r
->value
.update
.name
, scratch
->buf
, scratch
->len
);
927 r
->value
.update
.name
[scratch
->len
] = 0;
930 n
= decode_string(scratch
, in
);
933 string_view_consume(&in
, n
);
935 /* Same as above, but for the reflog email. */
936 if (!r
->value
.update
.email
||
937 strcmp(r
->value
.update
.email
, scratch
->buf
)) {
938 r
->value
.update
.email
=
939 reftable_realloc(r
->value
.update
.email
, scratch
->len
+ 1);
940 memcpy(r
->value
.update
.email
, scratch
->buf
, scratch
->len
);
941 r
->value
.update
.email
[scratch
->len
] = 0;
945 n
= get_var_int(&ts
, &in
);
948 string_view_consume(&in
, n
);
949 r
->value
.update
.time
= ts
;
953 r
->value
.update
.tz_offset
= get_be16(in
.buf
);
954 string_view_consume(&in
, 2);
956 n
= decode_string(scratch
, in
);
959 string_view_consume(&in
, n
);
961 REFTABLE_ALLOC_GROW(r
->value
.update
.message
, scratch
->len
+ 1,
962 r
->value
.update
.message_cap
);
963 memcpy(r
->value
.update
.message
, scratch
->buf
, scratch
->len
);
964 r
->value
.update
.message
[scratch
->len
] = 0;
966 return start
.len
- in
.len
;
969 return REFTABLE_FORMAT_ERROR
;
972 static int null_streq(char *a
, char *b
)
981 return 0 == strcmp(a
, b
);
984 static int reftable_log_record_equal_void(const void *a
,
985 const void *b
, int hash_size
)
987 return reftable_log_record_equal((struct reftable_log_record
*) a
,
988 (struct reftable_log_record
*) b
,
992 static int reftable_log_record_cmp_void(const void *_a
, const void *_b
)
994 const struct reftable_log_record
*a
= _a
;
995 const struct reftable_log_record
*b
= _b
;
996 int cmp
= strcmp(a
->refname
, b
->refname
);
1001 * Note that the comparison here is reversed. This is because the
1002 * update index is reversed when comparing keys. For reference, see how
1003 * we handle this in reftable_log_record_key()`.
1005 return b
->update_index
- a
->update_index
;
1008 int reftable_log_record_equal(const struct reftable_log_record
*a
,
1009 const struct reftable_log_record
*b
, int hash_size
)
1011 if (!(null_streq(a
->refname
, b
->refname
) &&
1012 a
->update_index
== b
->update_index
&&
1013 a
->value_type
== b
->value_type
))
1016 switch (a
->value_type
) {
1017 case REFTABLE_LOG_DELETION
:
1019 case REFTABLE_LOG_UPDATE
:
1020 return null_streq(a
->value
.update
.name
, b
->value
.update
.name
) &&
1021 a
->value
.update
.time
== b
->value
.update
.time
&&
1022 a
->value
.update
.tz_offset
== b
->value
.update
.tz_offset
&&
1023 null_streq(a
->value
.update
.email
,
1024 b
->value
.update
.email
) &&
1025 null_streq(a
->value
.update
.message
,
1026 b
->value
.update
.message
) &&
1027 !memcmp(a
->value
.update
.old_hash
,
1028 b
->value
.update
.old_hash
, hash_size
) &&
1029 !memcmp(a
->value
.update
.new_hash
,
1030 b
->value
.update
.new_hash
, hash_size
);
1036 static int reftable_log_record_is_deletion_void(const void *p
)
1038 return reftable_log_record_is_deletion(
1039 (const struct reftable_log_record
*)p
);
1042 static void reftable_log_record_print_void(const void *rec
, int hash_size
)
1044 reftable_log_record_print_sz((struct reftable_log_record
*)rec
, hash_size
);
1047 static struct reftable_record_vtable reftable_log_record_vtable
= {
1048 .key
= &reftable_log_record_key
,
1049 .type
= BLOCK_TYPE_LOG
,
1050 .copy_from
= &reftable_log_record_copy_from
,
1051 .val_type
= &reftable_log_record_val_type
,
1052 .encode
= &reftable_log_record_encode
,
1053 .decode
= &reftable_log_record_decode
,
1054 .release
= &reftable_log_record_release_void
,
1055 .is_deletion
= &reftable_log_record_is_deletion_void
,
1056 .equal
= &reftable_log_record_equal_void
,
1057 .cmp
= &reftable_log_record_cmp_void
,
1058 .print
= &reftable_log_record_print_void
,
1061 static void reftable_index_record_key(const void *r
, struct strbuf
*dest
)
1063 const struct reftable_index_record
*rec
= r
;
1065 strbuf_addbuf(dest
, &rec
->last_key
);
1068 static void reftable_index_record_copy_from(void *rec
, const void *src_rec
,
1071 struct reftable_index_record
*dst
= rec
;
1072 const struct reftable_index_record
*src
= src_rec
;
1074 strbuf_reset(&dst
->last_key
);
1075 strbuf_addbuf(&dst
->last_key
, &src
->last_key
);
1076 dst
->offset
= src
->offset
;
1079 static void reftable_index_record_release(void *rec
)
1081 struct reftable_index_record
*idx
= rec
;
1082 strbuf_release(&idx
->last_key
);
1085 static uint8_t reftable_index_record_val_type(const void *rec
)
1090 static int reftable_index_record_encode(const void *rec
, struct string_view out
,
1093 const struct reftable_index_record
*r
=
1094 (const struct reftable_index_record
*)rec
;
1095 struct string_view start
= out
;
1097 int n
= put_var_int(&out
, r
->offset
);
1101 string_view_consume(&out
, n
);
1103 return start
.len
- out
.len
;
1106 static int reftable_index_record_decode(void *rec
, struct strbuf key
,
1107 uint8_t val_type
, struct string_view in
,
1108 int hash_size
, struct strbuf
*scratch UNUSED
)
1110 struct string_view start
= in
;
1111 struct reftable_index_record
*r
= rec
;
1114 strbuf_reset(&r
->last_key
);
1115 strbuf_addbuf(&r
->last_key
, &key
);
1117 n
= get_var_int(&r
->offset
, &in
);
1121 string_view_consume(&in
, n
);
1122 return start
.len
- in
.len
;
1125 static int reftable_index_record_equal(const void *a
, const void *b
, int hash_size
)
1127 struct reftable_index_record
*ia
= (struct reftable_index_record
*) a
;
1128 struct reftable_index_record
*ib
= (struct reftable_index_record
*) b
;
1130 return ia
->offset
== ib
->offset
&& !strbuf_cmp(&ia
->last_key
, &ib
->last_key
);
1133 static int reftable_index_record_cmp(const void *_a
, const void *_b
)
1135 const struct reftable_index_record
*a
= _a
;
1136 const struct reftable_index_record
*b
= _b
;
1137 return strbuf_cmp(&a
->last_key
, &b
->last_key
);
1140 static void reftable_index_record_print(const void *rec
, int hash_size
)
1142 const struct reftable_index_record
*idx
= rec
;
1143 /* TODO: escape null chars? */
1144 printf("\"%s\" %" PRIu64
"\n", idx
->last_key
.buf
, idx
->offset
);
1147 static struct reftable_record_vtable reftable_index_record_vtable
= {
1148 .key
= &reftable_index_record_key
,
1149 .type
= BLOCK_TYPE_INDEX
,
1150 .copy_from
= &reftable_index_record_copy_from
,
1151 .val_type
= &reftable_index_record_val_type
,
1152 .encode
= &reftable_index_record_encode
,
1153 .decode
= &reftable_index_record_decode
,
1154 .release
= &reftable_index_record_release
,
1155 .is_deletion
= ¬_a_deletion
,
1156 .equal
= &reftable_index_record_equal
,
1157 .cmp
= &reftable_index_record_cmp
,
1158 .print
= &reftable_index_record_print
,
1161 void reftable_record_key(struct reftable_record
*rec
, struct strbuf
*dest
)
1163 reftable_record_vtable(rec
)->key(reftable_record_data(rec
), dest
);
1166 int reftable_record_encode(struct reftable_record
*rec
, struct string_view dest
,
1169 return reftable_record_vtable(rec
)->encode(reftable_record_data(rec
),
1173 void reftable_record_copy_from(struct reftable_record
*rec
,
1174 struct reftable_record
*src
, int hash_size
)
1176 assert(src
->type
== rec
->type
);
1178 reftable_record_vtable(rec
)->copy_from(reftable_record_data(rec
),
1179 reftable_record_data(src
),
1183 uint8_t reftable_record_val_type(struct reftable_record
*rec
)
1185 return reftable_record_vtable(rec
)->val_type(reftable_record_data(rec
));
1188 int reftable_record_decode(struct reftable_record
*rec
, struct strbuf key
,
1189 uint8_t extra
, struct string_view src
, int hash_size
,
1190 struct strbuf
*scratch
)
1192 return reftable_record_vtable(rec
)->decode(reftable_record_data(rec
),
1193 key
, extra
, src
, hash_size
,
1197 void reftable_record_release(struct reftable_record
*rec
)
1199 reftable_record_vtable(rec
)->release(reftable_record_data(rec
));
1202 int reftable_record_is_deletion(struct reftable_record
*rec
)
1204 return reftable_record_vtable(rec
)->is_deletion(
1205 reftable_record_data(rec
));
1208 int reftable_record_cmp(struct reftable_record
*a
, struct reftable_record
*b
)
1210 if (a
->type
!= b
->type
)
1211 BUG("cannot compare reftable records of different type");
1212 return reftable_record_vtable(a
)->cmp(
1213 reftable_record_data(a
), reftable_record_data(b
));
1216 int reftable_record_equal(struct reftable_record
*a
, struct reftable_record
*b
, int hash_size
)
1218 if (a
->type
!= b
->type
)
1220 return reftable_record_vtable(a
)->equal(
1221 reftable_record_data(a
), reftable_record_data(b
), hash_size
);
1224 static int hash_equal(const unsigned char *a
, const unsigned char *b
, int hash_size
)
1227 return !memcmp(a
, b
, hash_size
);
1232 int reftable_ref_record_equal(const struct reftable_ref_record
*a
,
1233 const struct reftable_ref_record
*b
, int hash_size
)
1235 assert(hash_size
> 0);
1236 if (!null_streq(a
->refname
, b
->refname
))
1239 if (a
->update_index
!= b
->update_index
||
1240 a
->value_type
!= b
->value_type
)
1243 switch (a
->value_type
) {
1244 case REFTABLE_REF_SYMREF
:
1245 return !strcmp(a
->value
.symref
, b
->value
.symref
);
1246 case REFTABLE_REF_VAL2
:
1247 return hash_equal(a
->value
.val2
.value
, b
->value
.val2
.value
,
1249 hash_equal(a
->value
.val2
.target_value
,
1250 b
->value
.val2
.target_value
, hash_size
);
1251 case REFTABLE_REF_VAL1
:
1252 return hash_equal(a
->value
.val1
, b
->value
.val1
, hash_size
);
1253 case REFTABLE_REF_DELETION
:
1260 int reftable_ref_record_compare_name(const void *a
, const void *b
)
1262 return strcmp(((struct reftable_ref_record
*)a
)->refname
,
1263 ((struct reftable_ref_record
*)b
)->refname
);
1266 int reftable_ref_record_is_deletion(const struct reftable_ref_record
*ref
)
1268 return ref
->value_type
== REFTABLE_REF_DELETION
;
1271 int reftable_log_record_compare_key(const void *a
, const void *b
)
1273 const struct reftable_log_record
*la
= a
;
1274 const struct reftable_log_record
*lb
= b
;
1276 int cmp
= strcmp(la
->refname
, lb
->refname
);
1279 if (la
->update_index
> lb
->update_index
)
1281 return (la
->update_index
< lb
->update_index
) ? 1 : 0;
1284 int reftable_log_record_is_deletion(const struct reftable_log_record
*log
)
1286 return (log
->value_type
== REFTABLE_LOG_DELETION
);
1289 static void *reftable_record_data(struct reftable_record
*rec
)
1291 switch (rec
->type
) {
1292 case BLOCK_TYPE_REF
:
1294 case BLOCK_TYPE_LOG
:
1296 case BLOCK_TYPE_INDEX
:
1298 case BLOCK_TYPE_OBJ
:
1304 static struct reftable_record_vtable
*
1305 reftable_record_vtable(struct reftable_record
*rec
)
1307 switch (rec
->type
) {
1308 case BLOCK_TYPE_REF
:
1309 return &reftable_ref_record_vtable
;
1310 case BLOCK_TYPE_LOG
:
1311 return &reftable_log_record_vtable
;
1312 case BLOCK_TYPE_INDEX
:
1313 return &reftable_index_record_vtable
;
1314 case BLOCK_TYPE_OBJ
:
1315 return &reftable_obj_record_vtable
;
1320 void reftable_record_init(struct reftable_record
*rec
, uint8_t typ
)
1322 memset(rec
, 0, sizeof(*rec
));
1326 case BLOCK_TYPE_REF
:
1327 case BLOCK_TYPE_LOG
:
1328 case BLOCK_TYPE_OBJ
:
1330 case BLOCK_TYPE_INDEX
:
1331 strbuf_init(&rec
->u
.idx
.last_key
, 0);
1334 BUG("unhandled record type");
1338 void reftable_record_print(struct reftable_record
*rec
, int hash_size
)
1340 printf("'%c': ", rec
->type
);
1341 reftable_record_vtable(rec
)->print(reftable_record_data(rec
), hash_size
);