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_key(struct strbuf
*key
, uint8_t *extra
,
163 struct strbuf last_key
, struct string_view in
)
165 int start_len
= in
.len
;
166 uint64_t prefix_len
= 0;
167 uint64_t suffix_len
= 0;
168 int n
= get_var_int(&prefix_len
, &in
);
171 string_view_consume(&in
, n
);
173 if (prefix_len
> last_key
.len
)
176 n
= get_var_int(&suffix_len
, &in
);
179 string_view_consume(&in
, n
);
181 *extra
= (uint8_t)(suffix_len
& 0x7);
184 if (in
.len
< suffix_len
)
188 strbuf_add(key
, last_key
.buf
, prefix_len
);
189 strbuf_add(key
, in
.buf
, suffix_len
);
190 string_view_consume(&in
, suffix_len
);
192 return start_len
- in
.len
;
195 static void reftable_ref_record_key(const void *r
, struct strbuf
*dest
)
197 const struct reftable_ref_record
*rec
=
198 (const struct reftable_ref_record
*)r
;
200 strbuf_addstr(dest
, rec
->refname
);
203 static void reftable_ref_record_copy_from(void *rec
, const void *src_rec
,
206 struct reftable_ref_record
*ref
= rec
;
207 const struct reftable_ref_record
*src
= src_rec
;
208 assert(hash_size
> 0);
210 /* This is simple and correct, but we could probably reuse the hash
212 reftable_ref_record_release(ref
);
214 ref
->refname
= xstrdup(src
->refname
);
216 ref
->update_index
= src
->update_index
;
217 ref
->value_type
= src
->value_type
;
218 switch (src
->value_type
) {
219 case REFTABLE_REF_DELETION
:
221 case REFTABLE_REF_VAL1
:
222 memcpy(ref
->value
.val1
, src
->value
.val1
, hash_size
);
224 case REFTABLE_REF_VAL2
:
225 memcpy(ref
->value
.val2
.value
, src
->value
.val2
.value
, hash_size
);
226 memcpy(ref
->value
.val2
.target_value
,
227 src
->value
.val2
.target_value
, hash_size
);
229 case REFTABLE_REF_SYMREF
:
230 ref
->value
.symref
= xstrdup(src
->value
.symref
);
235 static char hexdigit(int c
)
239 return 'a' + (c
- 10);
242 static void hex_format(char *dest
, const unsigned char *src
, int hash_size
)
244 assert(hash_size
> 0);
247 for (i
= 0; i
< hash_size
; i
++) {
248 dest
[2 * i
] = hexdigit(src
[i
] >> 4);
249 dest
[2 * i
+ 1] = hexdigit(src
[i
] & 0xf);
251 dest
[2 * hash_size
] = 0;
255 static void reftable_ref_record_print_sz(const struct reftable_ref_record
*ref
,
258 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 }; /* BUG */
259 printf("ref{%s(%" PRIu64
") ", ref
->refname
, ref
->update_index
);
260 switch (ref
->value_type
) {
261 case REFTABLE_REF_SYMREF
:
262 printf("=> %s", ref
->value
.symref
);
264 case REFTABLE_REF_VAL2
:
265 hex_format(hex
, ref
->value
.val2
.value
, hash_size
);
266 printf("val 2 %s", hex
);
267 hex_format(hex
, ref
->value
.val2
.target_value
,
269 printf("(T %s)", hex
);
271 case REFTABLE_REF_VAL1
:
272 hex_format(hex
, ref
->value
.val1
, hash_size
);
273 printf("val 1 %s", hex
);
275 case REFTABLE_REF_DELETION
:
282 void reftable_ref_record_print(const struct reftable_ref_record
*ref
,
284 reftable_ref_record_print_sz(ref
, hash_size(hash_id
));
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 strbuf key
,
365 uint8_t val_type
, struct string_view in
,
368 struct reftable_ref_record
*r
= rec
;
369 struct string_view start
= in
;
370 uint64_t update_index
= 0;
371 int n
= get_var_int(&update_index
, &in
);
374 string_view_consume(&in
, n
);
376 reftable_ref_record_release(r
);
378 assert(hash_size
> 0);
380 r
->refname
= reftable_realloc(r
->refname
, key
.len
+ 1);
381 memcpy(r
->refname
, key
.buf
, key
.len
);
382 r
->update_index
= update_index
;
383 r
->refname
[key
.len
] = 0;
384 r
->value_type
= val_type
;
386 case REFTABLE_REF_VAL1
:
387 if (in
.len
< hash_size
) {
391 memcpy(r
->value
.val1
, in
.buf
, hash_size
);
392 string_view_consume(&in
, hash_size
);
395 case REFTABLE_REF_VAL2
:
396 if (in
.len
< 2 * hash_size
) {
400 memcpy(r
->value
.val2
.value
, in
.buf
, hash_size
);
401 string_view_consume(&in
, hash_size
);
403 memcpy(r
->value
.val2
.target_value
, in
.buf
, hash_size
);
404 string_view_consume(&in
, hash_size
);
407 case REFTABLE_REF_SYMREF
: {
408 struct strbuf dest
= STRBUF_INIT
;
409 int n
= decode_string(&dest
, in
);
413 string_view_consume(&in
, n
);
414 r
->value
.symref
= dest
.buf
;
417 case REFTABLE_REF_DELETION
:
424 return start
.len
- in
.len
;
427 static int reftable_ref_record_is_deletion_void(const void *p
)
429 return reftable_ref_record_is_deletion(
430 (const struct reftable_ref_record
*)p
);
433 static int reftable_ref_record_equal_void(const void *a
,
434 const void *b
, int hash_size
)
436 struct reftable_ref_record
*ra
= (struct reftable_ref_record
*) a
;
437 struct reftable_ref_record
*rb
= (struct reftable_ref_record
*) b
;
438 return reftable_ref_record_equal(ra
, rb
, hash_size
);
441 static int reftable_ref_record_cmp_void(const void *_a
, const void *_b
)
443 const struct reftable_ref_record
*a
= _a
;
444 const struct reftable_ref_record
*b
= _b
;
445 return strcmp(a
->refname
, b
->refname
);
448 static void reftable_ref_record_print_void(const void *rec
,
451 reftable_ref_record_print_sz((struct reftable_ref_record
*) rec
, hash_size
);
454 static struct reftable_record_vtable reftable_ref_record_vtable
= {
455 .key
= &reftable_ref_record_key
,
456 .type
= BLOCK_TYPE_REF
,
457 .copy_from
= &reftable_ref_record_copy_from
,
458 .val_type
= &reftable_ref_record_val_type
,
459 .encode
= &reftable_ref_record_encode
,
460 .decode
= &reftable_ref_record_decode
,
461 .release
= &reftable_ref_record_release_void
,
462 .is_deletion
= &reftable_ref_record_is_deletion_void
,
463 .equal
= &reftable_ref_record_equal_void
,
464 .cmp
= &reftable_ref_record_cmp_void
,
465 .print
= &reftable_ref_record_print_void
,
468 static void reftable_obj_record_key(const void *r
, struct strbuf
*dest
)
470 const struct reftable_obj_record
*rec
=
471 (const struct reftable_obj_record
*)r
;
473 strbuf_add(dest
, rec
->hash_prefix
, rec
->hash_prefix_len
);
476 static void reftable_obj_record_release(void *rec
)
478 struct reftable_obj_record
*obj
= rec
;
479 FREE_AND_NULL(obj
->hash_prefix
);
480 FREE_AND_NULL(obj
->offsets
);
481 memset(obj
, 0, sizeof(struct reftable_obj_record
));
484 static void reftable_obj_record_print(const void *rec
, int hash_size
)
486 const struct reftable_obj_record
*obj
= rec
;
487 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 };
488 struct strbuf offset_str
= STRBUF_INIT
;
491 for (i
= 0; i
< obj
->offset_len
; i
++)
492 strbuf_addf(&offset_str
, "%" PRIu64
" ", obj
->offsets
[i
]);
493 hex_format(hex
, obj
->hash_prefix
, obj
->hash_prefix_len
);
494 printf("prefix %s (len %d), offsets [%s]\n",
495 hex
, obj
->hash_prefix_len
, offset_str
.buf
);
496 strbuf_release(&offset_str
);
499 static void reftable_obj_record_copy_from(void *rec
, const void *src_rec
,
502 struct reftable_obj_record
*obj
= rec
;
503 const struct reftable_obj_record
*src
=
504 (const struct reftable_obj_record
*)src_rec
;
506 reftable_obj_record_release(obj
);
507 obj
->hash_prefix
= reftable_malloc(src
->hash_prefix_len
);
508 obj
->hash_prefix_len
= src
->hash_prefix_len
;
509 if (src
->hash_prefix_len
)
510 memcpy(obj
->hash_prefix
, src
->hash_prefix
, obj
->hash_prefix_len
);
512 obj
->offsets
= reftable_malloc(src
->offset_len
* sizeof(uint64_t));
513 obj
->offset_len
= src
->offset_len
;
514 COPY_ARRAY(obj
->offsets
, src
->offsets
, src
->offset_len
);
517 static uint8_t reftable_obj_record_val_type(const void *rec
)
519 const struct reftable_obj_record
*r
= rec
;
520 if (r
->offset_len
> 0 && r
->offset_len
< 8)
521 return r
->offset_len
;
525 static int reftable_obj_record_encode(const void *rec
, struct string_view s
,
528 const struct reftable_obj_record
*r
= rec
;
529 struct string_view start
= s
;
533 if (r
->offset_len
== 0 || r
->offset_len
>= 8) {
534 n
= put_var_int(&s
, r
->offset_len
);
538 string_view_consume(&s
, n
);
540 if (r
->offset_len
== 0)
541 return start
.len
- s
.len
;
542 n
= put_var_int(&s
, r
->offsets
[0]);
545 string_view_consume(&s
, n
);
547 last
= r
->offsets
[0];
548 for (i
= 1; i
< r
->offset_len
; i
++) {
549 int n
= put_var_int(&s
, r
->offsets
[i
] - last
);
553 string_view_consume(&s
, n
);
554 last
= r
->offsets
[i
];
556 return start
.len
- s
.len
;
559 static int reftable_obj_record_decode(void *rec
, struct strbuf key
,
560 uint8_t val_type
, struct string_view in
,
563 struct string_view start
= in
;
564 struct reftable_obj_record
*r
= rec
;
565 uint64_t count
= val_type
;
569 r
->hash_prefix
= reftable_malloc(key
.len
);
570 memcpy(r
->hash_prefix
, key
.buf
, key
.len
);
571 r
->hash_prefix_len
= key
.len
;
574 n
= get_var_int(&count
, &in
);
579 string_view_consume(&in
, n
);
585 return start
.len
- in
.len
;
587 r
->offsets
= reftable_malloc(count
* sizeof(uint64_t));
588 r
->offset_len
= count
;
590 n
= get_var_int(&r
->offsets
[0], &in
);
593 string_view_consume(&in
, n
);
595 last
= r
->offsets
[0];
599 int n
= get_var_int(&delta
, &in
);
603 string_view_consume(&in
, n
);
605 last
= r
->offsets
[j
] = (delta
+ last
);
608 return start
.len
- in
.len
;
611 static int not_a_deletion(const void *p
)
616 static int reftable_obj_record_equal_void(const void *a
, const void *b
, int hash_size
)
618 struct reftable_obj_record
*ra
= (struct reftable_obj_record
*) a
;
619 struct reftable_obj_record
*rb
= (struct reftable_obj_record
*) b
;
621 if (ra
->hash_prefix_len
!= rb
->hash_prefix_len
622 || ra
->offset_len
!= rb
->offset_len
)
625 if (ra
->hash_prefix_len
&&
626 memcmp(ra
->hash_prefix
, rb
->hash_prefix
, ra
->hash_prefix_len
))
628 if (ra
->offset_len
&&
629 memcmp(ra
->offsets
, rb
->offsets
, ra
->offset_len
* sizeof(uint64_t)))
635 static int reftable_obj_record_cmp_void(const void *_a
, const void *_b
)
637 const struct reftable_obj_record
*a
= _a
;
638 const struct reftable_obj_record
*b
= _b
;
641 cmp
= memcmp(a
->hash_prefix
, b
->hash_prefix
,
642 a
->hash_prefix_len
> b
->hash_prefix_len
?
643 a
->hash_prefix_len
: b
->hash_prefix_len
);
648 * When the prefix is the same then the object record that is longer is
649 * considered to be bigger.
651 return a
->hash_prefix_len
- b
->hash_prefix_len
;
654 static struct reftable_record_vtable reftable_obj_record_vtable
= {
655 .key
= &reftable_obj_record_key
,
656 .type
= BLOCK_TYPE_OBJ
,
657 .copy_from
= &reftable_obj_record_copy_from
,
658 .val_type
= &reftable_obj_record_val_type
,
659 .encode
= &reftable_obj_record_encode
,
660 .decode
= &reftable_obj_record_decode
,
661 .release
= &reftable_obj_record_release
,
662 .is_deletion
= ¬_a_deletion
,
663 .equal
= &reftable_obj_record_equal_void
,
664 .cmp
= &reftable_obj_record_cmp_void
,
665 .print
= &reftable_obj_record_print
,
668 static void reftable_log_record_print_sz(struct reftable_log_record
*log
,
671 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 };
673 switch (log
->value_type
) {
674 case REFTABLE_LOG_DELETION
:
675 printf("log{%s(%" PRIu64
") delete\n", log
->refname
,
678 case REFTABLE_LOG_UPDATE
:
679 printf("log{%s(%" PRIu64
") %s <%s> %" PRIu64
" %04d\n",
680 log
->refname
, log
->update_index
,
681 log
->value
.update
.name
? log
->value
.update
.name
: "",
682 log
->value
.update
.email
? log
->value
.update
.email
: "",
683 log
->value
.update
.time
,
684 log
->value
.update
.tz_offset
);
685 hex_format(hex
, log
->value
.update
.old_hash
, hash_size
);
686 printf("%s => ", hex
);
687 hex_format(hex
, log
->value
.update
.new_hash
, hash_size
);
688 printf("%s\n\n%s\n}\n", hex
,
689 log
->value
.update
.message
? log
->value
.update
.message
: "");
694 void reftable_log_record_print(struct reftable_log_record
*log
,
697 reftable_log_record_print_sz(log
, hash_size(hash_id
));
700 static void reftable_log_record_key(const void *r
, struct strbuf
*dest
)
702 const struct reftable_log_record
*rec
=
703 (const struct reftable_log_record
*)r
;
704 int len
= strlen(rec
->refname
);
708 strbuf_add(dest
, (uint8_t *)rec
->refname
, len
+ 1);
710 ts
= (~ts
) - rec
->update_index
;
711 put_be64(&i64
[0], ts
);
712 strbuf_add(dest
, i64
, sizeof(i64
));
715 static void reftable_log_record_copy_from(void *rec
, const void *src_rec
,
718 struct reftable_log_record
*dst
= rec
;
719 const struct reftable_log_record
*src
=
720 (const struct reftable_log_record
*)src_rec
;
722 reftable_log_record_release(dst
);
725 dst
->refname
= xstrdup(dst
->refname
);
727 switch (dst
->value_type
) {
728 case REFTABLE_LOG_DELETION
:
730 case REFTABLE_LOG_UPDATE
:
731 if (dst
->value
.update
.email
) {
732 dst
->value
.update
.email
=
733 xstrdup(dst
->value
.update
.email
);
735 if (dst
->value
.update
.name
) {
736 dst
->value
.update
.name
=
737 xstrdup(dst
->value
.update
.name
);
739 if (dst
->value
.update
.message
) {
740 dst
->value
.update
.message
=
741 xstrdup(dst
->value
.update
.message
);
744 if (dst
->value
.update
.new_hash
) {
745 dst
->value
.update
.new_hash
= reftable_malloc(hash_size
);
746 memcpy(dst
->value
.update
.new_hash
,
747 src
->value
.update
.new_hash
, hash_size
);
749 if (dst
->value
.update
.old_hash
) {
750 dst
->value
.update
.old_hash
= reftable_malloc(hash_size
);
751 memcpy(dst
->value
.update
.old_hash
,
752 src
->value
.update
.old_hash
, hash_size
);
758 static void reftable_log_record_release_void(void *rec
)
760 struct reftable_log_record
*r
= rec
;
761 reftable_log_record_release(r
);
764 void reftable_log_record_release(struct reftable_log_record
*r
)
766 reftable_free(r
->refname
);
767 switch (r
->value_type
) {
768 case REFTABLE_LOG_DELETION
:
770 case REFTABLE_LOG_UPDATE
:
771 reftable_free(r
->value
.update
.new_hash
);
772 reftable_free(r
->value
.update
.old_hash
);
773 reftable_free(r
->value
.update
.name
);
774 reftable_free(r
->value
.update
.email
);
775 reftable_free(r
->value
.update
.message
);
778 memset(r
, 0, sizeof(struct reftable_log_record
));
781 static uint8_t reftable_log_record_val_type(const void *rec
)
783 const struct reftable_log_record
*log
=
784 (const struct reftable_log_record
*)rec
;
786 return reftable_log_record_is_deletion(log
) ? 0 : 1;
789 static uint8_t zero
[GIT_SHA256_RAWSZ
] = { 0 };
791 static int reftable_log_record_encode(const void *rec
, struct string_view s
,
794 const struct reftable_log_record
*r
= rec
;
795 struct string_view start
= s
;
797 uint8_t *oldh
= NULL
;
798 uint8_t *newh
= NULL
;
799 if (reftable_log_record_is_deletion(r
))
802 oldh
= r
->value
.update
.old_hash
;
803 newh
= r
->value
.update
.new_hash
;
811 if (s
.len
< 2 * hash_size
)
814 memcpy(s
.buf
, oldh
, hash_size
);
815 memcpy(s
.buf
+ hash_size
, newh
, hash_size
);
816 string_view_consume(&s
, 2 * hash_size
);
818 n
= encode_string(r
->value
.update
.name
? r
->value
.update
.name
: "", s
);
821 string_view_consume(&s
, n
);
823 n
= encode_string(r
->value
.update
.email
? r
->value
.update
.email
: "",
827 string_view_consume(&s
, n
);
829 n
= put_var_int(&s
, r
->value
.update
.time
);
832 string_view_consume(&s
, n
);
837 put_be16(s
.buf
, r
->value
.update
.tz_offset
);
838 string_view_consume(&s
, 2);
841 r
->value
.update
.message
? r
->value
.update
.message
: "", s
);
844 string_view_consume(&s
, n
);
846 return start
.len
- s
.len
;
849 static int reftable_log_record_decode(void *rec
, struct strbuf key
,
850 uint8_t val_type
, struct string_view in
,
853 struct string_view start
= in
;
854 struct reftable_log_record
*r
= rec
;
857 struct strbuf dest
= STRBUF_INIT
;
860 if (key
.len
<= 9 || key
.buf
[key
.len
- 9] != 0)
861 return REFTABLE_FORMAT_ERROR
;
863 r
->refname
= reftable_realloc(r
->refname
, key
.len
- 8);
864 memcpy(r
->refname
, key
.buf
, key
.len
- 8);
865 ts
= get_be64(key
.buf
+ key
.len
- 8);
867 r
->update_index
= (~max
) - ts
;
869 if (val_type
!= r
->value_type
) {
870 switch (r
->value_type
) {
871 case REFTABLE_LOG_UPDATE
:
872 FREE_AND_NULL(r
->value
.update
.old_hash
);
873 FREE_AND_NULL(r
->value
.update
.new_hash
);
874 FREE_AND_NULL(r
->value
.update
.message
);
875 FREE_AND_NULL(r
->value
.update
.email
);
876 FREE_AND_NULL(r
->value
.update
.name
);
878 case REFTABLE_LOG_DELETION
:
883 r
->value_type
= val_type
;
884 if (val_type
== REFTABLE_LOG_DELETION
)
887 if (in
.len
< 2 * hash_size
)
888 return REFTABLE_FORMAT_ERROR
;
890 r
->value
.update
.old_hash
=
891 reftable_realloc(r
->value
.update
.old_hash
, hash_size
);
892 r
->value
.update
.new_hash
=
893 reftable_realloc(r
->value
.update
.new_hash
, hash_size
);
895 memcpy(r
->value
.update
.old_hash
, in
.buf
, hash_size
);
896 memcpy(r
->value
.update
.new_hash
, in
.buf
+ hash_size
, hash_size
);
898 string_view_consume(&in
, 2 * hash_size
);
900 n
= decode_string(&dest
, in
);
903 string_view_consume(&in
, n
);
905 r
->value
.update
.name
=
906 reftable_realloc(r
->value
.update
.name
, dest
.len
+ 1);
907 memcpy(r
->value
.update
.name
, dest
.buf
, dest
.len
);
908 r
->value
.update
.name
[dest
.len
] = 0;
911 n
= decode_string(&dest
, in
);
914 string_view_consume(&in
, n
);
916 r
->value
.update
.email
=
917 reftable_realloc(r
->value
.update
.email
, dest
.len
+ 1);
918 memcpy(r
->value
.update
.email
, dest
.buf
, dest
.len
);
919 r
->value
.update
.email
[dest
.len
] = 0;
922 n
= get_var_int(&ts
, &in
);
925 string_view_consume(&in
, n
);
926 r
->value
.update
.time
= ts
;
930 r
->value
.update
.tz_offset
= get_be16(in
.buf
);
931 string_view_consume(&in
, 2);
934 n
= decode_string(&dest
, in
);
937 string_view_consume(&in
, n
);
939 r
->value
.update
.message
=
940 reftable_realloc(r
->value
.update
.message
, dest
.len
+ 1);
941 memcpy(r
->value
.update
.message
, dest
.buf
, dest
.len
);
942 r
->value
.update
.message
[dest
.len
] = 0;
944 strbuf_release(&dest
);
945 return start
.len
- in
.len
;
948 strbuf_release(&dest
);
949 return REFTABLE_FORMAT_ERROR
;
952 static int null_streq(char *a
, char *b
)
961 return 0 == strcmp(a
, b
);
964 static int zero_hash_eq(uint8_t *a
, uint8_t *b
, int sz
)
972 return !memcmp(a
, b
, sz
);
975 static int reftable_log_record_equal_void(const void *a
,
976 const void *b
, int hash_size
)
978 return reftable_log_record_equal((struct reftable_log_record
*) a
,
979 (struct reftable_log_record
*) b
,
983 static int reftable_log_record_cmp_void(const void *_a
, const void *_b
)
985 const struct reftable_log_record
*a
= _a
;
986 const struct reftable_log_record
*b
= _b
;
987 int cmp
= strcmp(a
->refname
, b
->refname
);
992 * Note that the comparison here is reversed. This is because the
993 * update index is reversed when comparing keys. For reference, see how
994 * we handle this in reftable_log_record_key()`.
996 return b
->update_index
- a
->update_index
;
999 int reftable_log_record_equal(const struct reftable_log_record
*a
,
1000 const struct reftable_log_record
*b
, int hash_size
)
1002 if (!(null_streq(a
->refname
, b
->refname
) &&
1003 a
->update_index
== b
->update_index
&&
1004 a
->value_type
== b
->value_type
))
1007 switch (a
->value_type
) {
1008 case REFTABLE_LOG_DELETION
:
1010 case REFTABLE_LOG_UPDATE
:
1011 return null_streq(a
->value
.update
.name
, b
->value
.update
.name
) &&
1012 a
->value
.update
.time
== b
->value
.update
.time
&&
1013 a
->value
.update
.tz_offset
== b
->value
.update
.tz_offset
&&
1014 null_streq(a
->value
.update
.email
,
1015 b
->value
.update
.email
) &&
1016 null_streq(a
->value
.update
.message
,
1017 b
->value
.update
.message
) &&
1018 zero_hash_eq(a
->value
.update
.old_hash
,
1019 b
->value
.update
.old_hash
, hash_size
) &&
1020 zero_hash_eq(a
->value
.update
.new_hash
,
1021 b
->value
.update
.new_hash
, hash_size
);
1027 static int reftable_log_record_is_deletion_void(const void *p
)
1029 return reftable_log_record_is_deletion(
1030 (const struct reftable_log_record
*)p
);
1033 static void reftable_log_record_print_void(const void *rec
, int hash_size
)
1035 reftable_log_record_print_sz((struct reftable_log_record
*)rec
, hash_size
);
1038 static struct reftable_record_vtable reftable_log_record_vtable
= {
1039 .key
= &reftable_log_record_key
,
1040 .type
= BLOCK_TYPE_LOG
,
1041 .copy_from
= &reftable_log_record_copy_from
,
1042 .val_type
= &reftable_log_record_val_type
,
1043 .encode
= &reftable_log_record_encode
,
1044 .decode
= &reftable_log_record_decode
,
1045 .release
= &reftable_log_record_release_void
,
1046 .is_deletion
= &reftable_log_record_is_deletion_void
,
1047 .equal
= &reftable_log_record_equal_void
,
1048 .cmp
= &reftable_log_record_cmp_void
,
1049 .print
= &reftable_log_record_print_void
,
1052 static void reftable_index_record_key(const void *r
, struct strbuf
*dest
)
1054 const struct reftable_index_record
*rec
= r
;
1056 strbuf_addbuf(dest
, &rec
->last_key
);
1059 static void reftable_index_record_copy_from(void *rec
, const void *src_rec
,
1062 struct reftable_index_record
*dst
= rec
;
1063 const struct reftable_index_record
*src
= src_rec
;
1065 strbuf_reset(&dst
->last_key
);
1066 strbuf_addbuf(&dst
->last_key
, &src
->last_key
);
1067 dst
->offset
= src
->offset
;
1070 static void reftable_index_record_release(void *rec
)
1072 struct reftable_index_record
*idx
= rec
;
1073 strbuf_release(&idx
->last_key
);
1076 static uint8_t reftable_index_record_val_type(const void *rec
)
1081 static int reftable_index_record_encode(const void *rec
, struct string_view out
,
1084 const struct reftable_index_record
*r
=
1085 (const struct reftable_index_record
*)rec
;
1086 struct string_view start
= out
;
1088 int n
= put_var_int(&out
, r
->offset
);
1092 string_view_consume(&out
, n
);
1094 return start
.len
- out
.len
;
1097 static int reftable_index_record_decode(void *rec
, struct strbuf key
,
1098 uint8_t val_type
, struct string_view in
,
1101 struct string_view start
= in
;
1102 struct reftable_index_record
*r
= rec
;
1105 strbuf_reset(&r
->last_key
);
1106 strbuf_addbuf(&r
->last_key
, &key
);
1108 n
= get_var_int(&r
->offset
, &in
);
1112 string_view_consume(&in
, n
);
1113 return start
.len
- in
.len
;
1116 static int reftable_index_record_equal(const void *a
, const void *b
, int hash_size
)
1118 struct reftable_index_record
*ia
= (struct reftable_index_record
*) a
;
1119 struct reftable_index_record
*ib
= (struct reftable_index_record
*) b
;
1121 return ia
->offset
== ib
->offset
&& !strbuf_cmp(&ia
->last_key
, &ib
->last_key
);
1124 static int reftable_index_record_cmp(const void *_a
, const void *_b
)
1126 const struct reftable_index_record
*a
= _a
;
1127 const struct reftable_index_record
*b
= _b
;
1128 return strbuf_cmp(&a
->last_key
, &b
->last_key
);
1131 static void reftable_index_record_print(const void *rec
, int hash_size
)
1133 const struct reftable_index_record
*idx
= rec
;
1134 /* TODO: escape null chars? */
1135 printf("\"%s\" %" PRIu64
"\n", idx
->last_key
.buf
, idx
->offset
);
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
,
1149 .print
= &reftable_index_record_print
,
1152 void reftable_record_key(struct reftable_record
*rec
, struct strbuf
*dest
)
1154 reftable_record_vtable(rec
)->key(reftable_record_data(rec
), dest
);
1157 uint8_t reftable_record_type(struct reftable_record
*rec
)
1162 int reftable_record_encode(struct reftable_record
*rec
, struct string_view dest
,
1165 return reftable_record_vtable(rec
)->encode(reftable_record_data(rec
),
1169 void reftable_record_copy_from(struct reftable_record
*rec
,
1170 struct reftable_record
*src
, int hash_size
)
1172 assert(src
->type
== rec
->type
);
1174 reftable_record_vtable(rec
)->copy_from(reftable_record_data(rec
),
1175 reftable_record_data(src
),
1179 uint8_t reftable_record_val_type(struct reftable_record
*rec
)
1181 return reftable_record_vtable(rec
)->val_type(reftable_record_data(rec
));
1184 int reftable_record_decode(struct reftable_record
*rec
, struct strbuf key
,
1185 uint8_t extra
, struct string_view src
, int hash_size
)
1187 return reftable_record_vtable(rec
)->decode(reftable_record_data(rec
),
1188 key
, extra
, src
, hash_size
);
1191 void reftable_record_release(struct reftable_record
*rec
)
1193 reftable_record_vtable(rec
)->release(reftable_record_data(rec
));
1196 int reftable_record_is_deletion(struct reftable_record
*rec
)
1198 return reftable_record_vtable(rec
)->is_deletion(
1199 reftable_record_data(rec
));
1202 int reftable_record_cmp(struct reftable_record
*a
, struct reftable_record
*b
)
1204 if (a
->type
!= b
->type
)
1205 BUG("cannot compare reftable records of different type");
1206 return reftable_record_vtable(a
)->cmp(
1207 reftable_record_data(a
), reftable_record_data(b
));
1210 int reftable_record_equal(struct reftable_record
*a
, struct reftable_record
*b
, int hash_size
)
1212 if (a
->type
!= b
->type
)
1214 return reftable_record_vtable(a
)->equal(
1215 reftable_record_data(a
), reftable_record_data(b
), hash_size
);
1218 static int hash_equal(const unsigned char *a
, const unsigned char *b
, int hash_size
)
1221 return !memcmp(a
, b
, hash_size
);
1226 int reftable_ref_record_equal(const struct reftable_ref_record
*a
,
1227 const struct reftable_ref_record
*b
, int hash_size
)
1229 assert(hash_size
> 0);
1230 if (!null_streq(a
->refname
, b
->refname
))
1233 if (a
->update_index
!= b
->update_index
||
1234 a
->value_type
!= b
->value_type
)
1237 switch (a
->value_type
) {
1238 case REFTABLE_REF_SYMREF
:
1239 return !strcmp(a
->value
.symref
, b
->value
.symref
);
1240 case REFTABLE_REF_VAL2
:
1241 return hash_equal(a
->value
.val2
.value
, b
->value
.val2
.value
,
1243 hash_equal(a
->value
.val2
.target_value
,
1244 b
->value
.val2
.target_value
, hash_size
);
1245 case REFTABLE_REF_VAL1
:
1246 return hash_equal(a
->value
.val1
, b
->value
.val1
, hash_size
);
1247 case REFTABLE_REF_DELETION
:
1254 int reftable_ref_record_compare_name(const void *a
, const void *b
)
1256 return strcmp(((struct reftable_ref_record
*)a
)->refname
,
1257 ((struct reftable_ref_record
*)b
)->refname
);
1260 int reftable_ref_record_is_deletion(const struct reftable_ref_record
*ref
)
1262 return ref
->value_type
== REFTABLE_REF_DELETION
;
1265 int reftable_log_record_compare_key(const void *a
, const void *b
)
1267 const struct reftable_log_record
*la
= a
;
1268 const struct reftable_log_record
*lb
= b
;
1270 int cmp
= strcmp(la
->refname
, lb
->refname
);
1273 if (la
->update_index
> lb
->update_index
)
1275 return (la
->update_index
< lb
->update_index
) ? 1 : 0;
1278 int reftable_log_record_is_deletion(const struct reftable_log_record
*log
)
1280 return (log
->value_type
== REFTABLE_LOG_DELETION
);
1283 void string_view_consume(struct string_view
*s
, int n
)
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 struct reftable_record
reftable_new_record(uint8_t typ
)
1322 struct reftable_record clean
= {
1326 /* the following is involved, but the naive solution (just return
1327 * `clean` as is, except for BLOCK_TYPE_INDEX), returns a garbage
1328 * clean.u.obj.offsets pointer on Windows VS CI. Go figure.
1331 case BLOCK_TYPE_OBJ
:
1333 struct reftable_obj_record obj
= { 0 };
1337 case BLOCK_TYPE_INDEX
:
1339 struct reftable_index_record idx
= {
1340 .last_key
= STRBUF_INIT
,
1345 case BLOCK_TYPE_REF
:
1347 struct reftable_ref_record ref
= { 0 };
1351 case BLOCK_TYPE_LOG
:
1353 struct reftable_log_record log
= { 0 };
1361 void reftable_record_print(struct reftable_record
*rec
, int hash_size
)
1363 printf("'%c': ", rec
->type
);
1364 reftable_record_vtable(rec
)->print(reftable_record_data(rec
), hash_size
);