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 uint8_t *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 uint8_t *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 ref
->value
.val1
= reftable_malloc(hash_size
);
223 memcpy(ref
->value
.val1
, src
->value
.val1
, hash_size
);
225 case REFTABLE_REF_VAL2
:
226 ref
->value
.val2
.value
= reftable_malloc(hash_size
);
227 memcpy(ref
->value
.val2
.value
, src
->value
.val2
.value
, hash_size
);
228 ref
->value
.val2
.target_value
= reftable_malloc(hash_size
);
229 memcpy(ref
->value
.val2
.target_value
,
230 src
->value
.val2
.target_value
, hash_size
);
232 case REFTABLE_REF_SYMREF
:
233 ref
->value
.symref
= xstrdup(src
->value
.symref
);
238 static char hexdigit(int c
)
242 return 'a' + (c
- 10);
245 static void hex_format(char *dest
, uint8_t *src
, int hash_size
)
247 assert(hash_size
> 0);
250 for (i
= 0; i
< hash_size
; i
++) {
251 dest
[2 * i
] = hexdigit(src
[i
] >> 4);
252 dest
[2 * i
+ 1] = hexdigit(src
[i
] & 0xf);
254 dest
[2 * hash_size
] = 0;
258 static void reftable_ref_record_print_sz(const struct reftable_ref_record
*ref
,
261 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 }; /* BUG */
262 printf("ref{%s(%" PRIu64
") ", ref
->refname
, ref
->update_index
);
263 switch (ref
->value_type
) {
264 case REFTABLE_REF_SYMREF
:
265 printf("=> %s", ref
->value
.symref
);
267 case REFTABLE_REF_VAL2
:
268 hex_format(hex
, ref
->value
.val2
.value
, hash_size
);
269 printf("val 2 %s", hex
);
270 hex_format(hex
, ref
->value
.val2
.target_value
,
272 printf("(T %s)", hex
);
274 case REFTABLE_REF_VAL1
:
275 hex_format(hex
, ref
->value
.val1
, hash_size
);
276 printf("val 1 %s", hex
);
278 case REFTABLE_REF_DELETION
:
285 void reftable_ref_record_print(const struct reftable_ref_record
*ref
,
287 reftable_ref_record_print_sz(ref
, hash_size(hash_id
));
290 static void reftable_ref_record_release_void(void *rec
)
292 reftable_ref_record_release(rec
);
295 void reftable_ref_record_release(struct reftable_ref_record
*ref
)
297 switch (ref
->value_type
) {
298 case REFTABLE_REF_SYMREF
:
299 reftable_free(ref
->value
.symref
);
301 case REFTABLE_REF_VAL2
:
302 reftable_free(ref
->value
.val2
.target_value
);
303 reftable_free(ref
->value
.val2
.value
);
305 case REFTABLE_REF_VAL1
:
306 reftable_free(ref
->value
.val1
);
308 case REFTABLE_REF_DELETION
:
314 reftable_free(ref
->refname
);
315 memset(ref
, 0, sizeof(struct reftable_ref_record
));
318 static uint8_t reftable_ref_record_val_type(const void *rec
)
320 const struct reftable_ref_record
*r
=
321 (const struct reftable_ref_record
*)rec
;
322 return r
->value_type
;
325 static int reftable_ref_record_encode(const void *rec
, struct string_view s
,
328 const struct reftable_ref_record
*r
=
329 (const struct reftable_ref_record
*)rec
;
330 struct string_view start
= s
;
331 int n
= put_var_int(&s
, r
->update_index
);
332 assert(hash_size
> 0);
335 string_view_consume(&s
, n
);
337 switch (r
->value_type
) {
338 case REFTABLE_REF_SYMREF
:
339 n
= encode_string(r
->value
.symref
, s
);
343 string_view_consume(&s
, n
);
345 case REFTABLE_REF_VAL2
:
346 if (s
.len
< 2 * hash_size
) {
349 memcpy(s
.buf
, r
->value
.val2
.value
, hash_size
);
350 string_view_consume(&s
, hash_size
);
351 memcpy(s
.buf
, r
->value
.val2
.target_value
, hash_size
);
352 string_view_consume(&s
, hash_size
);
354 case REFTABLE_REF_VAL1
:
355 if (s
.len
< hash_size
) {
358 memcpy(s
.buf
, r
->value
.val1
, hash_size
);
359 string_view_consume(&s
, hash_size
);
361 case REFTABLE_REF_DELETION
:
367 return start
.len
- s
.len
;
370 static int reftable_ref_record_decode(void *rec
, struct strbuf key
,
371 uint8_t val_type
, struct string_view in
,
374 struct reftable_ref_record
*r
= rec
;
375 struct string_view start
= in
;
376 uint64_t update_index
= 0;
377 int n
= get_var_int(&update_index
, &in
);
380 string_view_consume(&in
, n
);
382 reftable_ref_record_release(r
);
384 assert(hash_size
> 0);
386 r
->refname
= reftable_realloc(r
->refname
, key
.len
+ 1);
387 memcpy(r
->refname
, key
.buf
, key
.len
);
388 r
->update_index
= update_index
;
389 r
->refname
[key
.len
] = 0;
390 r
->value_type
= val_type
;
392 case REFTABLE_REF_VAL1
:
393 if (in
.len
< hash_size
) {
397 r
->value
.val1
= reftable_malloc(hash_size
);
398 memcpy(r
->value
.val1
, in
.buf
, hash_size
);
399 string_view_consume(&in
, hash_size
);
402 case REFTABLE_REF_VAL2
:
403 if (in
.len
< 2 * hash_size
) {
407 r
->value
.val2
.value
= reftable_malloc(hash_size
);
408 memcpy(r
->value
.val2
.value
, in
.buf
, hash_size
);
409 string_view_consume(&in
, hash_size
);
411 r
->value
.val2
.target_value
= reftable_malloc(hash_size
);
412 memcpy(r
->value
.val2
.target_value
, in
.buf
, hash_size
);
413 string_view_consume(&in
, hash_size
);
416 case REFTABLE_REF_SYMREF
: {
417 struct strbuf dest
= STRBUF_INIT
;
418 int n
= decode_string(&dest
, in
);
422 string_view_consume(&in
, n
);
423 r
->value
.symref
= dest
.buf
;
426 case REFTABLE_REF_DELETION
:
433 return start
.len
- in
.len
;
436 static int reftable_ref_record_is_deletion_void(const void *p
)
438 return reftable_ref_record_is_deletion(
439 (const struct reftable_ref_record
*)p
);
443 static int reftable_ref_record_equal_void(const void *a
,
444 const void *b
, int hash_size
)
446 struct reftable_ref_record
*ra
= (struct reftable_ref_record
*) a
;
447 struct reftable_ref_record
*rb
= (struct reftable_ref_record
*) b
;
448 return reftable_ref_record_equal(ra
, rb
, hash_size
);
451 static void reftable_ref_record_print_void(const void *rec
,
454 reftable_ref_record_print_sz((struct reftable_ref_record
*) rec
, hash_size
);
457 static struct reftable_record_vtable reftable_ref_record_vtable
= {
458 .key
= &reftable_ref_record_key
,
459 .type
= BLOCK_TYPE_REF
,
460 .copy_from
= &reftable_ref_record_copy_from
,
461 .val_type
= &reftable_ref_record_val_type
,
462 .encode
= &reftable_ref_record_encode
,
463 .decode
= &reftable_ref_record_decode
,
464 .release
= &reftable_ref_record_release_void
,
465 .is_deletion
= &reftable_ref_record_is_deletion_void
,
466 .equal
= &reftable_ref_record_equal_void
,
467 .print
= &reftable_ref_record_print_void
,
470 static void reftable_obj_record_key(const void *r
, struct strbuf
*dest
)
472 const struct reftable_obj_record
*rec
=
473 (const struct reftable_obj_record
*)r
;
475 strbuf_add(dest
, rec
->hash_prefix
, rec
->hash_prefix_len
);
478 static void reftable_obj_record_release(void *rec
)
480 struct reftable_obj_record
*obj
= rec
;
481 FREE_AND_NULL(obj
->hash_prefix
);
482 FREE_AND_NULL(obj
->offsets
);
483 memset(obj
, 0, sizeof(struct reftable_obj_record
));
486 static void reftable_obj_record_print(const void *rec
, int hash_size
)
488 const struct reftable_obj_record
*obj
= rec
;
489 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 };
490 struct strbuf offset_str
= STRBUF_INIT
;
493 for (i
= 0; i
< obj
->offset_len
; i
++)
494 strbuf_addf(&offset_str
, "%" PRIu64
" ", obj
->offsets
[i
]);
495 hex_format(hex
, obj
->hash_prefix
, obj
->hash_prefix_len
);
496 printf("prefix %s (len %d), offsets [%s]\n",
497 hex
, obj
->hash_prefix_len
, offset_str
.buf
);
498 strbuf_release(&offset_str
);
501 static void reftable_obj_record_copy_from(void *rec
, const void *src_rec
,
504 struct reftable_obj_record
*obj
= rec
;
505 const struct reftable_obj_record
*src
=
506 (const struct reftable_obj_record
*)src_rec
;
508 reftable_obj_record_release(obj
);
509 obj
->hash_prefix
= reftable_malloc(src
->hash_prefix_len
);
510 obj
->hash_prefix_len
= src
->hash_prefix_len
;
511 if (src
->hash_prefix_len
)
512 memcpy(obj
->hash_prefix
, src
->hash_prefix
, obj
->hash_prefix_len
);
514 obj
->offsets
= reftable_malloc(src
->offset_len
* sizeof(uint64_t));
515 obj
->offset_len
= src
->offset_len
;
516 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
,
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 strbuf key
,
562 uint8_t val_type
, struct string_view in
,
565 struct string_view start
= in
;
566 struct reftable_obj_record
*r
= rec
;
567 uint64_t count
= val_type
;
571 r
->hash_prefix
= reftable_malloc(key
.len
);
572 memcpy(r
->hash_prefix
, key
.buf
, key
.len
);
573 r
->hash_prefix_len
= key
.len
;
576 n
= get_var_int(&count
, &in
);
581 string_view_consume(&in
, n
);
587 return start
.len
- in
.len
;
589 r
->offsets
= reftable_malloc(count
* sizeof(uint64_t));
590 r
->offset_len
= count
;
592 n
= get_var_int(&r
->offsets
[0], &in
);
595 string_view_consume(&in
, n
);
597 last
= r
->offsets
[0];
601 int n
= get_var_int(&delta
, &in
);
605 string_view_consume(&in
, n
);
607 last
= r
->offsets
[j
] = (delta
+ last
);
610 return start
.len
- in
.len
;
613 static int not_a_deletion(const void *p
)
618 static int reftable_obj_record_equal_void(const void *a
, const void *b
, int hash_size
)
620 struct reftable_obj_record
*ra
= (struct reftable_obj_record
*) a
;
621 struct reftable_obj_record
*rb
= (struct reftable_obj_record
*) b
;
623 if (ra
->hash_prefix_len
!= rb
->hash_prefix_len
624 || ra
->offset_len
!= rb
->offset_len
)
627 if (ra
->hash_prefix_len
&&
628 memcmp(ra
->hash_prefix
, rb
->hash_prefix
, ra
->hash_prefix_len
))
630 if (ra
->offset_len
&&
631 memcmp(ra
->offsets
, rb
->offsets
, ra
->offset_len
* sizeof(uint64_t)))
637 static struct reftable_record_vtable reftable_obj_record_vtable
= {
638 .key
= &reftable_obj_record_key
,
639 .type
= BLOCK_TYPE_OBJ
,
640 .copy_from
= &reftable_obj_record_copy_from
,
641 .val_type
= &reftable_obj_record_val_type
,
642 .encode
= &reftable_obj_record_encode
,
643 .decode
= &reftable_obj_record_decode
,
644 .release
= &reftable_obj_record_release
,
645 .is_deletion
= ¬_a_deletion
,
646 .equal
= &reftable_obj_record_equal_void
,
647 .print
= &reftable_obj_record_print
,
650 static void reftable_log_record_print_sz(struct reftable_log_record
*log
,
653 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 };
655 switch (log
->value_type
) {
656 case REFTABLE_LOG_DELETION
:
657 printf("log{%s(%" PRIu64
") delete\n", log
->refname
,
660 case REFTABLE_LOG_UPDATE
:
661 printf("log{%s(%" PRIu64
") %s <%s> %" PRIu64
" %04d\n",
662 log
->refname
, log
->update_index
,
663 log
->value
.update
.name
? log
->value
.update
.name
: "",
664 log
->value
.update
.email
? log
->value
.update
.email
: "",
665 log
->value
.update
.time
,
666 log
->value
.update
.tz_offset
);
667 hex_format(hex
, log
->value
.update
.old_hash
, hash_size
);
668 printf("%s => ", hex
);
669 hex_format(hex
, log
->value
.update
.new_hash
, hash_size
);
670 printf("%s\n\n%s\n}\n", hex
,
671 log
->value
.update
.message
? log
->value
.update
.message
: "");
676 void reftable_log_record_print(struct reftable_log_record
*log
,
679 reftable_log_record_print_sz(log
, hash_size(hash_id
));
682 static void reftable_log_record_key(const void *r
, struct strbuf
*dest
)
684 const struct reftable_log_record
*rec
=
685 (const struct reftable_log_record
*)r
;
686 int len
= strlen(rec
->refname
);
690 strbuf_add(dest
, (uint8_t *)rec
->refname
, len
+ 1);
692 ts
= (~ts
) - rec
->update_index
;
693 put_be64(&i64
[0], ts
);
694 strbuf_add(dest
, i64
, sizeof(i64
));
697 static void reftable_log_record_copy_from(void *rec
, const void *src_rec
,
700 struct reftable_log_record
*dst
= rec
;
701 const struct reftable_log_record
*src
=
702 (const struct reftable_log_record
*)src_rec
;
704 reftable_log_record_release(dst
);
707 dst
->refname
= xstrdup(dst
->refname
);
709 switch (dst
->value_type
) {
710 case REFTABLE_LOG_DELETION
:
712 case REFTABLE_LOG_UPDATE
:
713 if (dst
->value
.update
.email
) {
714 dst
->value
.update
.email
=
715 xstrdup(dst
->value
.update
.email
);
717 if (dst
->value
.update
.name
) {
718 dst
->value
.update
.name
=
719 xstrdup(dst
->value
.update
.name
);
721 if (dst
->value
.update
.message
) {
722 dst
->value
.update
.message
=
723 xstrdup(dst
->value
.update
.message
);
726 if (dst
->value
.update
.new_hash
) {
727 dst
->value
.update
.new_hash
= reftable_malloc(hash_size
);
728 memcpy(dst
->value
.update
.new_hash
,
729 src
->value
.update
.new_hash
, hash_size
);
731 if (dst
->value
.update
.old_hash
) {
732 dst
->value
.update
.old_hash
= reftable_malloc(hash_size
);
733 memcpy(dst
->value
.update
.old_hash
,
734 src
->value
.update
.old_hash
, hash_size
);
740 static void reftable_log_record_release_void(void *rec
)
742 struct reftable_log_record
*r
= rec
;
743 reftable_log_record_release(r
);
746 void reftable_log_record_release(struct reftable_log_record
*r
)
748 reftable_free(r
->refname
);
749 switch (r
->value_type
) {
750 case REFTABLE_LOG_DELETION
:
752 case REFTABLE_LOG_UPDATE
:
753 reftable_free(r
->value
.update
.new_hash
);
754 reftable_free(r
->value
.update
.old_hash
);
755 reftable_free(r
->value
.update
.name
);
756 reftable_free(r
->value
.update
.email
);
757 reftable_free(r
->value
.update
.message
);
760 memset(r
, 0, sizeof(struct reftable_log_record
));
763 static uint8_t reftable_log_record_val_type(const void *rec
)
765 const struct reftable_log_record
*log
=
766 (const struct reftable_log_record
*)rec
;
768 return reftable_log_record_is_deletion(log
) ? 0 : 1;
771 static uint8_t zero
[GIT_SHA256_RAWSZ
] = { 0 };
773 static int reftable_log_record_encode(const void *rec
, struct string_view s
,
776 const struct reftable_log_record
*r
= rec
;
777 struct string_view start
= s
;
779 uint8_t *oldh
= NULL
;
780 uint8_t *newh
= NULL
;
781 if (reftable_log_record_is_deletion(r
))
784 oldh
= r
->value
.update
.old_hash
;
785 newh
= r
->value
.update
.new_hash
;
793 if (s
.len
< 2 * hash_size
)
796 memcpy(s
.buf
, oldh
, hash_size
);
797 memcpy(s
.buf
+ hash_size
, newh
, hash_size
);
798 string_view_consume(&s
, 2 * hash_size
);
800 n
= encode_string(r
->value
.update
.name
? r
->value
.update
.name
: "", s
);
803 string_view_consume(&s
, n
);
805 n
= encode_string(r
->value
.update
.email
? r
->value
.update
.email
: "",
809 string_view_consume(&s
, n
);
811 n
= put_var_int(&s
, r
->value
.update
.time
);
814 string_view_consume(&s
, n
);
819 put_be16(s
.buf
, r
->value
.update
.tz_offset
);
820 string_view_consume(&s
, 2);
823 r
->value
.update
.message
? r
->value
.update
.message
: "", s
);
826 string_view_consume(&s
, n
);
828 return start
.len
- s
.len
;
831 static int reftable_log_record_decode(void *rec
, struct strbuf key
,
832 uint8_t val_type
, struct string_view in
,
835 struct string_view start
= in
;
836 struct reftable_log_record
*r
= rec
;
839 struct strbuf dest
= STRBUF_INIT
;
842 if (key
.len
<= 9 || key
.buf
[key
.len
- 9] != 0)
843 return REFTABLE_FORMAT_ERROR
;
845 r
->refname
= reftable_realloc(r
->refname
, key
.len
- 8);
846 memcpy(r
->refname
, key
.buf
, key
.len
- 8);
847 ts
= get_be64(key
.buf
+ key
.len
- 8);
849 r
->update_index
= (~max
) - ts
;
851 if (val_type
!= r
->value_type
) {
852 switch (r
->value_type
) {
853 case REFTABLE_LOG_UPDATE
:
854 FREE_AND_NULL(r
->value
.update
.old_hash
);
855 FREE_AND_NULL(r
->value
.update
.new_hash
);
856 FREE_AND_NULL(r
->value
.update
.message
);
857 FREE_AND_NULL(r
->value
.update
.email
);
858 FREE_AND_NULL(r
->value
.update
.name
);
860 case REFTABLE_LOG_DELETION
:
865 r
->value_type
= val_type
;
866 if (val_type
== REFTABLE_LOG_DELETION
)
869 if (in
.len
< 2 * hash_size
)
870 return REFTABLE_FORMAT_ERROR
;
872 r
->value
.update
.old_hash
=
873 reftable_realloc(r
->value
.update
.old_hash
, hash_size
);
874 r
->value
.update
.new_hash
=
875 reftable_realloc(r
->value
.update
.new_hash
, hash_size
);
877 memcpy(r
->value
.update
.old_hash
, in
.buf
, hash_size
);
878 memcpy(r
->value
.update
.new_hash
, in
.buf
+ hash_size
, hash_size
);
880 string_view_consume(&in
, 2 * hash_size
);
882 n
= decode_string(&dest
, in
);
885 string_view_consume(&in
, n
);
887 r
->value
.update
.name
=
888 reftable_realloc(r
->value
.update
.name
, dest
.len
+ 1);
889 memcpy(r
->value
.update
.name
, dest
.buf
, dest
.len
);
890 r
->value
.update
.name
[dest
.len
] = 0;
893 n
= decode_string(&dest
, in
);
896 string_view_consume(&in
, n
);
898 r
->value
.update
.email
=
899 reftable_realloc(r
->value
.update
.email
, dest
.len
+ 1);
900 memcpy(r
->value
.update
.email
, dest
.buf
, dest
.len
);
901 r
->value
.update
.email
[dest
.len
] = 0;
904 n
= get_var_int(&ts
, &in
);
907 string_view_consume(&in
, n
);
908 r
->value
.update
.time
= ts
;
912 r
->value
.update
.tz_offset
= get_be16(in
.buf
);
913 string_view_consume(&in
, 2);
916 n
= decode_string(&dest
, in
);
919 string_view_consume(&in
, n
);
921 r
->value
.update
.message
=
922 reftable_realloc(r
->value
.update
.message
, dest
.len
+ 1);
923 memcpy(r
->value
.update
.message
, dest
.buf
, dest
.len
);
924 r
->value
.update
.message
[dest
.len
] = 0;
926 strbuf_release(&dest
);
927 return start
.len
- in
.len
;
930 strbuf_release(&dest
);
931 return REFTABLE_FORMAT_ERROR
;
934 static int null_streq(char *a
, char *b
)
943 return 0 == strcmp(a
, b
);
946 static int zero_hash_eq(uint8_t *a
, uint8_t *b
, int sz
)
954 return !memcmp(a
, b
, sz
);
957 static int reftable_log_record_equal_void(const void *a
,
958 const void *b
, int hash_size
)
960 return reftable_log_record_equal((struct reftable_log_record
*) a
,
961 (struct reftable_log_record
*) b
,
965 int reftable_log_record_equal(const struct reftable_log_record
*a
,
966 const struct reftable_log_record
*b
, int hash_size
)
968 if (!(null_streq(a
->refname
, b
->refname
) &&
969 a
->update_index
== b
->update_index
&&
970 a
->value_type
== b
->value_type
))
973 switch (a
->value_type
) {
974 case REFTABLE_LOG_DELETION
:
976 case REFTABLE_LOG_UPDATE
:
977 return null_streq(a
->value
.update
.name
, b
->value
.update
.name
) &&
978 a
->value
.update
.time
== b
->value
.update
.time
&&
979 a
->value
.update
.tz_offset
== b
->value
.update
.tz_offset
&&
980 null_streq(a
->value
.update
.email
,
981 b
->value
.update
.email
) &&
982 null_streq(a
->value
.update
.message
,
983 b
->value
.update
.message
) &&
984 zero_hash_eq(a
->value
.update
.old_hash
,
985 b
->value
.update
.old_hash
, hash_size
) &&
986 zero_hash_eq(a
->value
.update
.new_hash
,
987 b
->value
.update
.new_hash
, hash_size
);
993 static int reftable_log_record_is_deletion_void(const void *p
)
995 return reftable_log_record_is_deletion(
996 (const struct reftable_log_record
*)p
);
999 static void reftable_log_record_print_void(const void *rec
, int hash_size
)
1001 reftable_log_record_print_sz((struct reftable_log_record
*)rec
, hash_size
);
1004 static struct reftable_record_vtable reftable_log_record_vtable
= {
1005 .key
= &reftable_log_record_key
,
1006 .type
= BLOCK_TYPE_LOG
,
1007 .copy_from
= &reftable_log_record_copy_from
,
1008 .val_type
= &reftable_log_record_val_type
,
1009 .encode
= &reftable_log_record_encode
,
1010 .decode
= &reftable_log_record_decode
,
1011 .release
= &reftable_log_record_release_void
,
1012 .is_deletion
= &reftable_log_record_is_deletion_void
,
1013 .equal
= &reftable_log_record_equal_void
,
1014 .print
= &reftable_log_record_print_void
,
1017 static void reftable_index_record_key(const void *r
, struct strbuf
*dest
)
1019 const struct reftable_index_record
*rec
= r
;
1021 strbuf_addbuf(dest
, &rec
->last_key
);
1024 static void reftable_index_record_copy_from(void *rec
, const void *src_rec
,
1027 struct reftable_index_record
*dst
= rec
;
1028 const struct reftable_index_record
*src
= src_rec
;
1030 strbuf_reset(&dst
->last_key
);
1031 strbuf_addbuf(&dst
->last_key
, &src
->last_key
);
1032 dst
->offset
= src
->offset
;
1035 static void reftable_index_record_release(void *rec
)
1037 struct reftable_index_record
*idx
= rec
;
1038 strbuf_release(&idx
->last_key
);
1041 static uint8_t reftable_index_record_val_type(const void *rec
)
1046 static int reftable_index_record_encode(const void *rec
, struct string_view out
,
1049 const struct reftable_index_record
*r
=
1050 (const struct reftable_index_record
*)rec
;
1051 struct string_view start
= out
;
1053 int n
= put_var_int(&out
, r
->offset
);
1057 string_view_consume(&out
, n
);
1059 return start
.len
- out
.len
;
1062 static int reftable_index_record_decode(void *rec
, struct strbuf key
,
1063 uint8_t val_type
, struct string_view in
,
1066 struct string_view start
= in
;
1067 struct reftable_index_record
*r
= rec
;
1070 strbuf_reset(&r
->last_key
);
1071 strbuf_addbuf(&r
->last_key
, &key
);
1073 n
= get_var_int(&r
->offset
, &in
);
1077 string_view_consume(&in
, n
);
1078 return start
.len
- in
.len
;
1081 static int reftable_index_record_equal(const void *a
, const void *b
, int hash_size
)
1083 struct reftable_index_record
*ia
= (struct reftable_index_record
*) a
;
1084 struct reftable_index_record
*ib
= (struct reftable_index_record
*) b
;
1086 return ia
->offset
== ib
->offset
&& !strbuf_cmp(&ia
->last_key
, &ib
->last_key
);
1089 static void reftable_index_record_print(const void *rec
, int hash_size
)
1091 const struct reftable_index_record
*idx
= rec
;
1092 /* TODO: escape null chars? */
1093 printf("\"%s\" %" PRIu64
"\n", idx
->last_key
.buf
, idx
->offset
);
1096 static struct reftable_record_vtable reftable_index_record_vtable
= {
1097 .key
= &reftable_index_record_key
,
1098 .type
= BLOCK_TYPE_INDEX
,
1099 .copy_from
= &reftable_index_record_copy_from
,
1100 .val_type
= &reftable_index_record_val_type
,
1101 .encode
= &reftable_index_record_encode
,
1102 .decode
= &reftable_index_record_decode
,
1103 .release
= &reftable_index_record_release
,
1104 .is_deletion
= ¬_a_deletion
,
1105 .equal
= &reftable_index_record_equal
,
1106 .print
= &reftable_index_record_print
,
1109 void reftable_record_key(struct reftable_record
*rec
, struct strbuf
*dest
)
1111 reftable_record_vtable(rec
)->key(reftable_record_data(rec
), dest
);
1114 uint8_t reftable_record_type(struct reftable_record
*rec
)
1119 int reftable_record_encode(struct reftable_record
*rec
, struct string_view dest
,
1122 return reftable_record_vtable(rec
)->encode(reftable_record_data(rec
),
1126 void reftable_record_copy_from(struct reftable_record
*rec
,
1127 struct reftable_record
*src
, int hash_size
)
1129 assert(src
->type
== rec
->type
);
1131 reftable_record_vtable(rec
)->copy_from(reftable_record_data(rec
),
1132 reftable_record_data(src
),
1136 uint8_t reftable_record_val_type(struct reftable_record
*rec
)
1138 return reftable_record_vtable(rec
)->val_type(reftable_record_data(rec
));
1141 int reftable_record_decode(struct reftable_record
*rec
, struct strbuf key
,
1142 uint8_t extra
, struct string_view src
, int hash_size
)
1144 return reftable_record_vtable(rec
)->decode(reftable_record_data(rec
),
1145 key
, extra
, src
, hash_size
);
1148 void reftable_record_release(struct reftable_record
*rec
)
1150 reftable_record_vtable(rec
)->release(reftable_record_data(rec
));
1153 int reftable_record_is_deletion(struct reftable_record
*rec
)
1155 return reftable_record_vtable(rec
)->is_deletion(
1156 reftable_record_data(rec
));
1159 int reftable_record_equal(struct reftable_record
*a
, struct reftable_record
*b
, int hash_size
)
1161 if (a
->type
!= b
->type
)
1163 return reftable_record_vtable(a
)->equal(
1164 reftable_record_data(a
), reftable_record_data(b
), hash_size
);
1167 static int hash_equal(uint8_t *a
, uint8_t *b
, int hash_size
)
1170 return !memcmp(a
, b
, hash_size
);
1175 int reftable_ref_record_equal(const struct reftable_ref_record
*a
,
1176 const struct reftable_ref_record
*b
, int hash_size
)
1178 assert(hash_size
> 0);
1179 if (!null_streq(a
->refname
, b
->refname
))
1182 if (a
->update_index
!= b
->update_index
||
1183 a
->value_type
!= b
->value_type
)
1186 switch (a
->value_type
) {
1187 case REFTABLE_REF_SYMREF
:
1188 return !strcmp(a
->value
.symref
, b
->value
.symref
);
1189 case REFTABLE_REF_VAL2
:
1190 return hash_equal(a
->value
.val2
.value
, b
->value
.val2
.value
,
1192 hash_equal(a
->value
.val2
.target_value
,
1193 b
->value
.val2
.target_value
, hash_size
);
1194 case REFTABLE_REF_VAL1
:
1195 return hash_equal(a
->value
.val1
, b
->value
.val1
, hash_size
);
1196 case REFTABLE_REF_DELETION
:
1203 int reftable_ref_record_compare_name(const void *a
, const void *b
)
1205 return strcmp(((struct reftable_ref_record
*)a
)->refname
,
1206 ((struct reftable_ref_record
*)b
)->refname
);
1209 int reftable_ref_record_is_deletion(const struct reftable_ref_record
*ref
)
1211 return ref
->value_type
== REFTABLE_REF_DELETION
;
1214 int reftable_log_record_compare_key(const void *a
, const void *b
)
1216 const struct reftable_log_record
*la
= a
;
1217 const struct reftable_log_record
*lb
= b
;
1219 int cmp
= strcmp(la
->refname
, lb
->refname
);
1222 if (la
->update_index
> lb
->update_index
)
1224 return (la
->update_index
< lb
->update_index
) ? 1 : 0;
1227 int reftable_log_record_is_deletion(const struct reftable_log_record
*log
)
1229 return (log
->value_type
== REFTABLE_LOG_DELETION
);
1232 void string_view_consume(struct string_view
*s
, int n
)
1238 static void *reftable_record_data(struct reftable_record
*rec
)
1240 switch (rec
->type
) {
1241 case BLOCK_TYPE_REF
:
1243 case BLOCK_TYPE_LOG
:
1245 case BLOCK_TYPE_INDEX
:
1247 case BLOCK_TYPE_OBJ
:
1253 static struct reftable_record_vtable
*
1254 reftable_record_vtable(struct reftable_record
*rec
)
1256 switch (rec
->type
) {
1257 case BLOCK_TYPE_REF
:
1258 return &reftable_ref_record_vtable
;
1259 case BLOCK_TYPE_LOG
:
1260 return &reftable_log_record_vtable
;
1261 case BLOCK_TYPE_INDEX
:
1262 return &reftable_index_record_vtable
;
1263 case BLOCK_TYPE_OBJ
:
1264 return &reftable_obj_record_vtable
;
1269 struct reftable_record
reftable_new_record(uint8_t typ
)
1271 struct reftable_record clean
= {
1275 /* the following is involved, but the naive solution (just return
1276 * `clean` as is, except for BLOCK_TYPE_INDEX), returns a garbage
1277 * clean.u.obj.offsets pointer on Windows VS CI. Go figure.
1280 case BLOCK_TYPE_OBJ
:
1282 struct reftable_obj_record obj
= { 0 };
1286 case BLOCK_TYPE_INDEX
:
1288 struct reftable_index_record idx
= {
1289 .last_key
= STRBUF_INIT
,
1294 case BLOCK_TYPE_REF
:
1296 struct reftable_ref_record ref
= { 0 };
1300 case BLOCK_TYPE_LOG
:
1302 struct reftable_log_record log
= { 0 };
1310 void reftable_record_print(struct reftable_record
*rec
, int hash_size
)
1312 printf("'%c': ", rec
->type
);
1313 reftable_record_vtable(rec
)->print(reftable_record_data(rec
), hash_size
);