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
*last_key
, uint8_t *extra
,
163 struct string_view in
)
165 int start_len
= in
.len
;
166 uint64_t prefix_len
= 0;
167 uint64_t suffix_len
= 0;
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 if (in
.len
< suffix_len
||
184 prefix_len
> last_key
->len
)
187 strbuf_setlen(last_key
, prefix_len
);
188 strbuf_add(last_key
, in
.buf
, suffix_len
);
189 string_view_consume(&in
, suffix_len
);
191 return start_len
- in
.len
;
194 static void reftable_ref_record_key(const void *r
, struct strbuf
*dest
)
196 const struct reftable_ref_record
*rec
=
197 (const struct reftable_ref_record
*)r
;
199 strbuf_addstr(dest
, rec
->refname
);
202 static void reftable_ref_record_copy_from(void *rec
, const void *src_rec
,
205 struct reftable_ref_record
*ref
= rec
;
206 const struct reftable_ref_record
*src
= src_rec
;
207 char *refname
= NULL
;
208 size_t refname_cap
= 0;
210 assert(hash_size
> 0);
212 SWAP(refname
, ref
->refname
);
213 SWAP(refname_cap
, ref
->refname_cap
);
214 reftable_ref_record_release(ref
);
215 SWAP(ref
->refname
, refname
);
216 SWAP(ref
->refname_cap
, refname_cap
);
219 size_t refname_len
= strlen(src
->refname
);
221 REFTABLE_ALLOC_GROW(ref
->refname
, refname_len
+ 1,
223 memcpy(ref
->refname
, src
->refname
, refname_len
);
224 ref
->refname
[refname_len
] = 0;
227 ref
->update_index
= src
->update_index
;
228 ref
->value_type
= src
->value_type
;
229 switch (src
->value_type
) {
230 case REFTABLE_REF_DELETION
:
232 case REFTABLE_REF_VAL1
:
233 memcpy(ref
->value
.val1
, src
->value
.val1
, hash_size
);
235 case REFTABLE_REF_VAL2
:
236 memcpy(ref
->value
.val2
.value
, src
->value
.val2
.value
, hash_size
);
237 memcpy(ref
->value
.val2
.target_value
,
238 src
->value
.val2
.target_value
, hash_size
);
240 case REFTABLE_REF_SYMREF
:
241 ref
->value
.symref
= xstrdup(src
->value
.symref
);
246 static char hexdigit(int c
)
250 return 'a' + (c
- 10);
253 static void hex_format(char *dest
, const unsigned char *src
, int hash_size
)
255 assert(hash_size
> 0);
258 for (i
= 0; i
< hash_size
; i
++) {
259 dest
[2 * i
] = hexdigit(src
[i
] >> 4);
260 dest
[2 * i
+ 1] = hexdigit(src
[i
] & 0xf);
262 dest
[2 * hash_size
] = 0;
266 static void reftable_ref_record_print_sz(const struct reftable_ref_record
*ref
,
269 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 }; /* BUG */
270 printf("ref{%s(%" PRIu64
") ", ref
->refname
, ref
->update_index
);
271 switch (ref
->value_type
) {
272 case REFTABLE_REF_SYMREF
:
273 printf("=> %s", ref
->value
.symref
);
275 case REFTABLE_REF_VAL2
:
276 hex_format(hex
, ref
->value
.val2
.value
, hash_size
);
277 printf("val 2 %s", hex
);
278 hex_format(hex
, ref
->value
.val2
.target_value
,
280 printf("(T %s)", hex
);
282 case REFTABLE_REF_VAL1
:
283 hex_format(hex
, ref
->value
.val1
, hash_size
);
284 printf("val 1 %s", hex
);
286 case REFTABLE_REF_DELETION
:
293 void reftable_ref_record_print(const struct reftable_ref_record
*ref
,
295 reftable_ref_record_print_sz(ref
, hash_size(hash_id
));
298 static void reftable_ref_record_release_void(void *rec
)
300 reftable_ref_record_release(rec
);
303 void reftable_ref_record_release(struct reftable_ref_record
*ref
)
305 switch (ref
->value_type
) {
306 case REFTABLE_REF_SYMREF
:
307 reftable_free(ref
->value
.symref
);
309 case REFTABLE_REF_VAL2
:
311 case REFTABLE_REF_VAL1
:
313 case REFTABLE_REF_DELETION
:
319 reftable_free(ref
->refname
);
320 memset(ref
, 0, sizeof(struct reftable_ref_record
));
323 static uint8_t reftable_ref_record_val_type(const void *rec
)
325 const struct reftable_ref_record
*r
=
326 (const struct reftable_ref_record
*)rec
;
327 return r
->value_type
;
330 static int reftable_ref_record_encode(const void *rec
, struct string_view s
,
333 const struct reftable_ref_record
*r
=
334 (const struct reftable_ref_record
*)rec
;
335 struct string_view start
= s
;
336 int n
= put_var_int(&s
, r
->update_index
);
337 assert(hash_size
> 0);
340 string_view_consume(&s
, n
);
342 switch (r
->value_type
) {
343 case REFTABLE_REF_SYMREF
:
344 n
= encode_string(r
->value
.symref
, s
);
348 string_view_consume(&s
, n
);
350 case REFTABLE_REF_VAL2
:
351 if (s
.len
< 2 * hash_size
) {
354 memcpy(s
.buf
, r
->value
.val2
.value
, hash_size
);
355 string_view_consume(&s
, hash_size
);
356 memcpy(s
.buf
, r
->value
.val2
.target_value
, hash_size
);
357 string_view_consume(&s
, hash_size
);
359 case REFTABLE_REF_VAL1
:
360 if (s
.len
< hash_size
) {
363 memcpy(s
.buf
, r
->value
.val1
, hash_size
);
364 string_view_consume(&s
, hash_size
);
366 case REFTABLE_REF_DELETION
:
372 return start
.len
- s
.len
;
375 static int reftable_ref_record_decode(void *rec
, struct strbuf key
,
376 uint8_t val_type
, struct string_view in
,
379 struct reftable_ref_record
*r
= rec
;
380 struct string_view start
= in
;
381 uint64_t update_index
= 0;
382 const char *refname
= NULL
;
383 size_t refname_cap
= 0;
386 assert(hash_size
> 0);
388 n
= get_var_int(&update_index
, &in
);
391 string_view_consume(&in
, n
);
393 SWAP(refname
, r
->refname
);
394 SWAP(refname_cap
, r
->refname_cap
);
395 reftable_ref_record_release(r
);
396 SWAP(r
->refname
, refname
);
397 SWAP(r
->refname_cap
, refname_cap
);
399 REFTABLE_ALLOC_GROW(r
->refname
, key
.len
+ 1, r
->refname_cap
);
400 memcpy(r
->refname
, key
.buf
, key
.len
);
401 r
->refname
[key
.len
] = 0;
403 r
->update_index
= update_index
;
404 r
->value_type
= val_type
;
406 case REFTABLE_REF_VAL1
:
407 if (in
.len
< hash_size
) {
411 memcpy(r
->value
.val1
, in
.buf
, hash_size
);
412 string_view_consume(&in
, hash_size
);
415 case REFTABLE_REF_VAL2
:
416 if (in
.len
< 2 * hash_size
) {
420 memcpy(r
->value
.val2
.value
, in
.buf
, hash_size
);
421 string_view_consume(&in
, hash_size
);
423 memcpy(r
->value
.val2
.target_value
, in
.buf
, hash_size
);
424 string_view_consume(&in
, hash_size
);
427 case REFTABLE_REF_SYMREF
: {
428 struct strbuf dest
= STRBUF_INIT
;
429 int n
= decode_string(&dest
, in
);
433 string_view_consume(&in
, n
);
434 r
->value
.symref
= dest
.buf
;
437 case REFTABLE_REF_DELETION
:
444 return start
.len
- in
.len
;
447 static int reftable_ref_record_is_deletion_void(const void *p
)
449 return reftable_ref_record_is_deletion(
450 (const struct reftable_ref_record
*)p
);
453 static int reftable_ref_record_equal_void(const void *a
,
454 const void *b
, int hash_size
)
456 struct reftable_ref_record
*ra
= (struct reftable_ref_record
*) a
;
457 struct reftable_ref_record
*rb
= (struct reftable_ref_record
*) b
;
458 return reftable_ref_record_equal(ra
, rb
, hash_size
);
461 static int reftable_ref_record_cmp_void(const void *_a
, const void *_b
)
463 const struct reftable_ref_record
*a
= _a
;
464 const struct reftable_ref_record
*b
= _b
;
465 return strcmp(a
->refname
, b
->refname
);
468 static void reftable_ref_record_print_void(const void *rec
,
471 reftable_ref_record_print_sz((struct reftable_ref_record
*) rec
, hash_size
);
474 static struct reftable_record_vtable reftable_ref_record_vtable
= {
475 .key
= &reftable_ref_record_key
,
476 .type
= BLOCK_TYPE_REF
,
477 .copy_from
= &reftable_ref_record_copy_from
,
478 .val_type
= &reftable_ref_record_val_type
,
479 .encode
= &reftable_ref_record_encode
,
480 .decode
= &reftable_ref_record_decode
,
481 .release
= &reftable_ref_record_release_void
,
482 .is_deletion
= &reftable_ref_record_is_deletion_void
,
483 .equal
= &reftable_ref_record_equal_void
,
484 .cmp
= &reftable_ref_record_cmp_void
,
485 .print
= &reftable_ref_record_print_void
,
488 static void reftable_obj_record_key(const void *r
, struct strbuf
*dest
)
490 const struct reftable_obj_record
*rec
=
491 (const struct reftable_obj_record
*)r
;
493 strbuf_add(dest
, rec
->hash_prefix
, rec
->hash_prefix_len
);
496 static void reftable_obj_record_release(void *rec
)
498 struct reftable_obj_record
*obj
= rec
;
499 FREE_AND_NULL(obj
->hash_prefix
);
500 FREE_AND_NULL(obj
->offsets
);
501 memset(obj
, 0, sizeof(struct reftable_obj_record
));
504 static void reftable_obj_record_print(const void *rec
, int hash_size
)
506 const struct reftable_obj_record
*obj
= rec
;
507 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 };
508 struct strbuf offset_str
= STRBUF_INIT
;
511 for (i
= 0; i
< obj
->offset_len
; i
++)
512 strbuf_addf(&offset_str
, "%" PRIu64
" ", obj
->offsets
[i
]);
513 hex_format(hex
, obj
->hash_prefix
, obj
->hash_prefix_len
);
514 printf("prefix %s (len %d), offsets [%s]\n",
515 hex
, obj
->hash_prefix_len
, offset_str
.buf
);
516 strbuf_release(&offset_str
);
519 static void reftable_obj_record_copy_from(void *rec
, const void *src_rec
,
522 struct reftable_obj_record
*obj
= rec
;
523 const struct reftable_obj_record
*src
=
524 (const struct reftable_obj_record
*)src_rec
;
526 reftable_obj_record_release(obj
);
528 REFTABLE_ALLOC_ARRAY(obj
->hash_prefix
, src
->hash_prefix_len
);
529 obj
->hash_prefix_len
= src
->hash_prefix_len
;
530 if (src
->hash_prefix_len
)
531 memcpy(obj
->hash_prefix
, src
->hash_prefix
, obj
->hash_prefix_len
);
533 REFTABLE_ALLOC_ARRAY(obj
->offsets
, src
->offset_len
);
534 obj
->offset_len
= src
->offset_len
;
535 COPY_ARRAY(obj
->offsets
, src
->offsets
, src
->offset_len
);
538 static uint8_t reftable_obj_record_val_type(const void *rec
)
540 const struct reftable_obj_record
*r
= rec
;
541 if (r
->offset_len
> 0 && r
->offset_len
< 8)
542 return r
->offset_len
;
546 static int reftable_obj_record_encode(const void *rec
, struct string_view s
,
549 const struct reftable_obj_record
*r
= rec
;
550 struct string_view start
= s
;
554 if (r
->offset_len
== 0 || r
->offset_len
>= 8) {
555 n
= put_var_int(&s
, r
->offset_len
);
559 string_view_consume(&s
, n
);
561 if (r
->offset_len
== 0)
562 return start
.len
- s
.len
;
563 n
= put_var_int(&s
, r
->offsets
[0]);
566 string_view_consume(&s
, n
);
568 last
= r
->offsets
[0];
569 for (i
= 1; i
< r
->offset_len
; i
++) {
570 int n
= put_var_int(&s
, r
->offsets
[i
] - last
);
574 string_view_consume(&s
, n
);
575 last
= r
->offsets
[i
];
577 return start
.len
- s
.len
;
580 static int reftable_obj_record_decode(void *rec
, struct strbuf key
,
581 uint8_t val_type
, struct string_view in
,
584 struct string_view start
= in
;
585 struct reftable_obj_record
*r
= rec
;
586 uint64_t count
= val_type
;
591 reftable_obj_record_release(r
);
593 REFTABLE_ALLOC_ARRAY(r
->hash_prefix
, key
.len
);
594 memcpy(r
->hash_prefix
, key
.buf
, key
.len
);
595 r
->hash_prefix_len
= key
.len
;
598 n
= get_var_int(&count
, &in
);
603 string_view_consume(&in
, n
);
609 return start
.len
- in
.len
;
611 REFTABLE_ALLOC_ARRAY(r
->offsets
, count
);
612 r
->offset_len
= count
;
614 n
= get_var_int(&r
->offsets
[0], &in
);
617 string_view_consume(&in
, n
);
619 last
= r
->offsets
[0];
623 int n
= get_var_int(&delta
, &in
);
627 string_view_consume(&in
, n
);
629 last
= r
->offsets
[j
] = (delta
+ last
);
632 return start
.len
- in
.len
;
635 static int not_a_deletion(const void *p
)
640 static int reftable_obj_record_equal_void(const void *a
, const void *b
, int hash_size
)
642 struct reftable_obj_record
*ra
= (struct reftable_obj_record
*) a
;
643 struct reftable_obj_record
*rb
= (struct reftable_obj_record
*) b
;
645 if (ra
->hash_prefix_len
!= rb
->hash_prefix_len
646 || ra
->offset_len
!= rb
->offset_len
)
649 if (ra
->hash_prefix_len
&&
650 memcmp(ra
->hash_prefix
, rb
->hash_prefix
, ra
->hash_prefix_len
))
652 if (ra
->offset_len
&&
653 memcmp(ra
->offsets
, rb
->offsets
, ra
->offset_len
* sizeof(uint64_t)))
659 static int reftable_obj_record_cmp_void(const void *_a
, const void *_b
)
661 const struct reftable_obj_record
*a
= _a
;
662 const struct reftable_obj_record
*b
= _b
;
665 cmp
= memcmp(a
->hash_prefix
, b
->hash_prefix
,
666 a
->hash_prefix_len
> b
->hash_prefix_len
?
667 a
->hash_prefix_len
: b
->hash_prefix_len
);
672 * When the prefix is the same then the object record that is longer is
673 * considered to be bigger.
675 return a
->hash_prefix_len
- b
->hash_prefix_len
;
678 static struct reftable_record_vtable reftable_obj_record_vtable
= {
679 .key
= &reftable_obj_record_key
,
680 .type
= BLOCK_TYPE_OBJ
,
681 .copy_from
= &reftable_obj_record_copy_from
,
682 .val_type
= &reftable_obj_record_val_type
,
683 .encode
= &reftable_obj_record_encode
,
684 .decode
= &reftable_obj_record_decode
,
685 .release
= &reftable_obj_record_release
,
686 .is_deletion
= ¬_a_deletion
,
687 .equal
= &reftable_obj_record_equal_void
,
688 .cmp
= &reftable_obj_record_cmp_void
,
689 .print
= &reftable_obj_record_print
,
692 static void reftable_log_record_print_sz(struct reftable_log_record
*log
,
695 char hex
[GIT_MAX_HEXSZ
+ 1] = { 0 };
697 switch (log
->value_type
) {
698 case REFTABLE_LOG_DELETION
:
699 printf("log{%s(%" PRIu64
") delete\n", log
->refname
,
702 case REFTABLE_LOG_UPDATE
:
703 printf("log{%s(%" PRIu64
") %s <%s> %" PRIu64
" %04d\n",
704 log
->refname
, log
->update_index
,
705 log
->value
.update
.name
? log
->value
.update
.name
: "",
706 log
->value
.update
.email
? log
->value
.update
.email
: "",
707 log
->value
.update
.time
,
708 log
->value
.update
.tz_offset
);
709 hex_format(hex
, log
->value
.update
.old_hash
, hash_size
);
710 printf("%s => ", hex
);
711 hex_format(hex
, log
->value
.update
.new_hash
, hash_size
);
712 printf("%s\n\n%s\n}\n", hex
,
713 log
->value
.update
.message
? log
->value
.update
.message
: "");
718 void reftable_log_record_print(struct reftable_log_record
*log
,
721 reftable_log_record_print_sz(log
, hash_size(hash_id
));
724 static void reftable_log_record_key(const void *r
, struct strbuf
*dest
)
726 const struct reftable_log_record
*rec
=
727 (const struct reftable_log_record
*)r
;
728 int len
= strlen(rec
->refname
);
732 strbuf_add(dest
, (uint8_t *)rec
->refname
, len
+ 1);
734 ts
= (~ts
) - rec
->update_index
;
735 put_be64(&i64
[0], ts
);
736 strbuf_add(dest
, i64
, sizeof(i64
));
739 static void reftable_log_record_copy_from(void *rec
, const void *src_rec
,
742 struct reftable_log_record
*dst
= rec
;
743 const struct reftable_log_record
*src
=
744 (const struct reftable_log_record
*)src_rec
;
746 reftable_log_record_release(dst
);
749 dst
->refname
= xstrdup(dst
->refname
);
751 switch (dst
->value_type
) {
752 case REFTABLE_LOG_DELETION
:
754 case REFTABLE_LOG_UPDATE
:
755 if (dst
->value
.update
.email
) {
756 dst
->value
.update
.email
=
757 xstrdup(dst
->value
.update
.email
);
759 if (dst
->value
.update
.name
) {
760 dst
->value
.update
.name
=
761 xstrdup(dst
->value
.update
.name
);
763 if (dst
->value
.update
.message
) {
764 dst
->value
.update
.message
=
765 xstrdup(dst
->value
.update
.message
);
768 if (dst
->value
.update
.new_hash
) {
769 REFTABLE_ALLOC_ARRAY(dst
->value
.update
.new_hash
, hash_size
);
770 memcpy(dst
->value
.update
.new_hash
,
771 src
->value
.update
.new_hash
, hash_size
);
773 if (dst
->value
.update
.old_hash
) {
774 REFTABLE_ALLOC_ARRAY(dst
->value
.update
.old_hash
, hash_size
);
775 memcpy(dst
->value
.update
.old_hash
,
776 src
->value
.update
.old_hash
, hash_size
);
782 static void reftable_log_record_release_void(void *rec
)
784 struct reftable_log_record
*r
= rec
;
785 reftable_log_record_release(r
);
788 void reftable_log_record_release(struct reftable_log_record
*r
)
790 reftable_free(r
->refname
);
791 switch (r
->value_type
) {
792 case REFTABLE_LOG_DELETION
:
794 case REFTABLE_LOG_UPDATE
:
795 reftable_free(r
->value
.update
.new_hash
);
796 reftable_free(r
->value
.update
.old_hash
);
797 reftable_free(r
->value
.update
.name
);
798 reftable_free(r
->value
.update
.email
);
799 reftable_free(r
->value
.update
.message
);
802 memset(r
, 0, sizeof(struct reftable_log_record
));
805 static uint8_t reftable_log_record_val_type(const void *rec
)
807 const struct reftable_log_record
*log
=
808 (const struct reftable_log_record
*)rec
;
810 return reftable_log_record_is_deletion(log
) ? 0 : 1;
813 static uint8_t zero
[GIT_SHA256_RAWSZ
] = { 0 };
815 static int reftable_log_record_encode(const void *rec
, struct string_view s
,
818 const struct reftable_log_record
*r
= rec
;
819 struct string_view start
= s
;
821 uint8_t *oldh
= NULL
;
822 uint8_t *newh
= NULL
;
823 if (reftable_log_record_is_deletion(r
))
826 oldh
= r
->value
.update
.old_hash
;
827 newh
= r
->value
.update
.new_hash
;
835 if (s
.len
< 2 * hash_size
)
838 memcpy(s
.buf
, oldh
, hash_size
);
839 memcpy(s
.buf
+ hash_size
, newh
, hash_size
);
840 string_view_consume(&s
, 2 * hash_size
);
842 n
= encode_string(r
->value
.update
.name
? r
->value
.update
.name
: "", s
);
845 string_view_consume(&s
, n
);
847 n
= encode_string(r
->value
.update
.email
? r
->value
.update
.email
: "",
851 string_view_consume(&s
, n
);
853 n
= put_var_int(&s
, r
->value
.update
.time
);
856 string_view_consume(&s
, n
);
861 put_be16(s
.buf
, r
->value
.update
.tz_offset
);
862 string_view_consume(&s
, 2);
865 r
->value
.update
.message
? r
->value
.update
.message
: "", s
);
868 string_view_consume(&s
, n
);
870 return start
.len
- s
.len
;
873 static int reftable_log_record_decode(void *rec
, struct strbuf key
,
874 uint8_t val_type
, struct string_view in
,
877 struct string_view start
= in
;
878 struct reftable_log_record
*r
= rec
;
881 struct strbuf dest
= STRBUF_INIT
;
884 if (key
.len
<= 9 || key
.buf
[key
.len
- 9] != 0)
885 return REFTABLE_FORMAT_ERROR
;
887 r
->refname
= reftable_realloc(r
->refname
, key
.len
- 8);
888 memcpy(r
->refname
, key
.buf
, key
.len
- 8);
889 ts
= get_be64(key
.buf
+ key
.len
- 8);
891 r
->update_index
= (~max
) - ts
;
893 if (val_type
!= r
->value_type
) {
894 switch (r
->value_type
) {
895 case REFTABLE_LOG_UPDATE
:
896 FREE_AND_NULL(r
->value
.update
.old_hash
);
897 FREE_AND_NULL(r
->value
.update
.new_hash
);
898 FREE_AND_NULL(r
->value
.update
.message
);
899 FREE_AND_NULL(r
->value
.update
.email
);
900 FREE_AND_NULL(r
->value
.update
.name
);
902 case REFTABLE_LOG_DELETION
:
907 r
->value_type
= val_type
;
908 if (val_type
== REFTABLE_LOG_DELETION
)
911 if (in
.len
< 2 * hash_size
)
912 return REFTABLE_FORMAT_ERROR
;
914 r
->value
.update
.old_hash
=
915 reftable_realloc(r
->value
.update
.old_hash
, hash_size
);
916 r
->value
.update
.new_hash
=
917 reftable_realloc(r
->value
.update
.new_hash
, hash_size
);
919 memcpy(r
->value
.update
.old_hash
, in
.buf
, hash_size
);
920 memcpy(r
->value
.update
.new_hash
, in
.buf
+ hash_size
, hash_size
);
922 string_view_consume(&in
, 2 * hash_size
);
924 n
= decode_string(&dest
, in
);
927 string_view_consume(&in
, n
);
929 r
->value
.update
.name
=
930 reftable_realloc(r
->value
.update
.name
, dest
.len
+ 1);
931 memcpy(r
->value
.update
.name
, dest
.buf
, dest
.len
);
932 r
->value
.update
.name
[dest
.len
] = 0;
935 n
= decode_string(&dest
, in
);
938 string_view_consume(&in
, n
);
940 r
->value
.update
.email
=
941 reftable_realloc(r
->value
.update
.email
, dest
.len
+ 1);
942 memcpy(r
->value
.update
.email
, dest
.buf
, dest
.len
);
943 r
->value
.update
.email
[dest
.len
] = 0;
946 n
= get_var_int(&ts
, &in
);
949 string_view_consume(&in
, n
);
950 r
->value
.update
.time
= ts
;
954 r
->value
.update
.tz_offset
= get_be16(in
.buf
);
955 string_view_consume(&in
, 2);
958 n
= decode_string(&dest
, in
);
961 string_view_consume(&in
, n
);
963 r
->value
.update
.message
=
964 reftable_realloc(r
->value
.update
.message
, dest
.len
+ 1);
965 memcpy(r
->value
.update
.message
, dest
.buf
, dest
.len
);
966 r
->value
.update
.message
[dest
.len
] = 0;
968 strbuf_release(&dest
);
969 return start
.len
- in
.len
;
972 strbuf_release(&dest
);
973 return REFTABLE_FORMAT_ERROR
;
976 static int null_streq(char *a
, char *b
)
985 return 0 == strcmp(a
, b
);
988 static int zero_hash_eq(uint8_t *a
, uint8_t *b
, int sz
)
996 return !memcmp(a
, b
, sz
);
999 static int reftable_log_record_equal_void(const void *a
,
1000 const void *b
, int hash_size
)
1002 return reftable_log_record_equal((struct reftable_log_record
*) a
,
1003 (struct reftable_log_record
*) b
,
1007 static int reftable_log_record_cmp_void(const void *_a
, const void *_b
)
1009 const struct reftable_log_record
*a
= _a
;
1010 const struct reftable_log_record
*b
= _b
;
1011 int cmp
= strcmp(a
->refname
, b
->refname
);
1016 * Note that the comparison here is reversed. This is because the
1017 * update index is reversed when comparing keys. For reference, see how
1018 * we handle this in reftable_log_record_key()`.
1020 return b
->update_index
- a
->update_index
;
1023 int reftable_log_record_equal(const struct reftable_log_record
*a
,
1024 const struct reftable_log_record
*b
, int hash_size
)
1026 if (!(null_streq(a
->refname
, b
->refname
) &&
1027 a
->update_index
== b
->update_index
&&
1028 a
->value_type
== b
->value_type
))
1031 switch (a
->value_type
) {
1032 case REFTABLE_LOG_DELETION
:
1034 case REFTABLE_LOG_UPDATE
:
1035 return null_streq(a
->value
.update
.name
, b
->value
.update
.name
) &&
1036 a
->value
.update
.time
== b
->value
.update
.time
&&
1037 a
->value
.update
.tz_offset
== b
->value
.update
.tz_offset
&&
1038 null_streq(a
->value
.update
.email
,
1039 b
->value
.update
.email
) &&
1040 null_streq(a
->value
.update
.message
,
1041 b
->value
.update
.message
) &&
1042 zero_hash_eq(a
->value
.update
.old_hash
,
1043 b
->value
.update
.old_hash
, hash_size
) &&
1044 zero_hash_eq(a
->value
.update
.new_hash
,
1045 b
->value
.update
.new_hash
, hash_size
);
1051 static int reftable_log_record_is_deletion_void(const void *p
)
1053 return reftable_log_record_is_deletion(
1054 (const struct reftable_log_record
*)p
);
1057 static void reftable_log_record_print_void(const void *rec
, int hash_size
)
1059 reftable_log_record_print_sz((struct reftable_log_record
*)rec
, hash_size
);
1062 static struct reftable_record_vtable reftable_log_record_vtable
= {
1063 .key
= &reftable_log_record_key
,
1064 .type
= BLOCK_TYPE_LOG
,
1065 .copy_from
= &reftable_log_record_copy_from
,
1066 .val_type
= &reftable_log_record_val_type
,
1067 .encode
= &reftable_log_record_encode
,
1068 .decode
= &reftable_log_record_decode
,
1069 .release
= &reftable_log_record_release_void
,
1070 .is_deletion
= &reftable_log_record_is_deletion_void
,
1071 .equal
= &reftable_log_record_equal_void
,
1072 .cmp
= &reftable_log_record_cmp_void
,
1073 .print
= &reftable_log_record_print_void
,
1076 static void reftable_index_record_key(const void *r
, struct strbuf
*dest
)
1078 const struct reftable_index_record
*rec
= r
;
1080 strbuf_addbuf(dest
, &rec
->last_key
);
1083 static void reftable_index_record_copy_from(void *rec
, const void *src_rec
,
1086 struct reftable_index_record
*dst
= rec
;
1087 const struct reftable_index_record
*src
= src_rec
;
1089 strbuf_reset(&dst
->last_key
);
1090 strbuf_addbuf(&dst
->last_key
, &src
->last_key
);
1091 dst
->offset
= src
->offset
;
1094 static void reftable_index_record_release(void *rec
)
1096 struct reftable_index_record
*idx
= rec
;
1097 strbuf_release(&idx
->last_key
);
1100 static uint8_t reftable_index_record_val_type(const void *rec
)
1105 static int reftable_index_record_encode(const void *rec
, struct string_view out
,
1108 const struct reftable_index_record
*r
=
1109 (const struct reftable_index_record
*)rec
;
1110 struct string_view start
= out
;
1112 int n
= put_var_int(&out
, r
->offset
);
1116 string_view_consume(&out
, n
);
1118 return start
.len
- out
.len
;
1121 static int reftable_index_record_decode(void *rec
, struct strbuf key
,
1122 uint8_t val_type
, struct string_view in
,
1125 struct string_view start
= in
;
1126 struct reftable_index_record
*r
= rec
;
1129 strbuf_reset(&r
->last_key
);
1130 strbuf_addbuf(&r
->last_key
, &key
);
1132 n
= get_var_int(&r
->offset
, &in
);
1136 string_view_consume(&in
, n
);
1137 return start
.len
- in
.len
;
1140 static int reftable_index_record_equal(const void *a
, const void *b
, int hash_size
)
1142 struct reftable_index_record
*ia
= (struct reftable_index_record
*) a
;
1143 struct reftable_index_record
*ib
= (struct reftable_index_record
*) b
;
1145 return ia
->offset
== ib
->offset
&& !strbuf_cmp(&ia
->last_key
, &ib
->last_key
);
1148 static int reftable_index_record_cmp(const void *_a
, const void *_b
)
1150 const struct reftable_index_record
*a
= _a
;
1151 const struct reftable_index_record
*b
= _b
;
1152 return strbuf_cmp(&a
->last_key
, &b
->last_key
);
1155 static void reftable_index_record_print(const void *rec
, int hash_size
)
1157 const struct reftable_index_record
*idx
= rec
;
1158 /* TODO: escape null chars? */
1159 printf("\"%s\" %" PRIu64
"\n", idx
->last_key
.buf
, idx
->offset
);
1162 static struct reftable_record_vtable reftable_index_record_vtable
= {
1163 .key
= &reftable_index_record_key
,
1164 .type
= BLOCK_TYPE_INDEX
,
1165 .copy_from
= &reftable_index_record_copy_from
,
1166 .val_type
= &reftable_index_record_val_type
,
1167 .encode
= &reftable_index_record_encode
,
1168 .decode
= &reftable_index_record_decode
,
1169 .release
= &reftable_index_record_release
,
1170 .is_deletion
= ¬_a_deletion
,
1171 .equal
= &reftable_index_record_equal
,
1172 .cmp
= &reftable_index_record_cmp
,
1173 .print
= &reftable_index_record_print
,
1176 void reftable_record_key(struct reftable_record
*rec
, struct strbuf
*dest
)
1178 reftable_record_vtable(rec
)->key(reftable_record_data(rec
), dest
);
1181 int reftable_record_encode(struct reftable_record
*rec
, struct string_view dest
,
1184 return reftable_record_vtable(rec
)->encode(reftable_record_data(rec
),
1188 void reftable_record_copy_from(struct reftable_record
*rec
,
1189 struct reftable_record
*src
, int hash_size
)
1191 assert(src
->type
== rec
->type
);
1193 reftable_record_vtable(rec
)->copy_from(reftable_record_data(rec
),
1194 reftable_record_data(src
),
1198 uint8_t reftable_record_val_type(struct reftable_record
*rec
)
1200 return reftable_record_vtable(rec
)->val_type(reftable_record_data(rec
));
1203 int reftable_record_decode(struct reftable_record
*rec
, struct strbuf key
,
1204 uint8_t extra
, struct string_view src
, int hash_size
)
1206 return reftable_record_vtable(rec
)->decode(reftable_record_data(rec
),
1207 key
, extra
, src
, hash_size
);
1210 void reftable_record_release(struct reftable_record
*rec
)
1212 reftable_record_vtable(rec
)->release(reftable_record_data(rec
));
1215 int reftable_record_is_deletion(struct reftable_record
*rec
)
1217 return reftable_record_vtable(rec
)->is_deletion(
1218 reftable_record_data(rec
));
1221 int reftable_record_cmp(struct reftable_record
*a
, struct reftable_record
*b
)
1223 if (a
->type
!= b
->type
)
1224 BUG("cannot compare reftable records of different type");
1225 return reftable_record_vtable(a
)->cmp(
1226 reftable_record_data(a
), reftable_record_data(b
));
1229 int reftable_record_equal(struct reftable_record
*a
, struct reftable_record
*b
, int hash_size
)
1231 if (a
->type
!= b
->type
)
1233 return reftable_record_vtable(a
)->equal(
1234 reftable_record_data(a
), reftable_record_data(b
), hash_size
);
1237 static int hash_equal(const unsigned char *a
, const unsigned char *b
, int hash_size
)
1240 return !memcmp(a
, b
, hash_size
);
1245 int reftable_ref_record_equal(const struct reftable_ref_record
*a
,
1246 const struct reftable_ref_record
*b
, int hash_size
)
1248 assert(hash_size
> 0);
1249 if (!null_streq(a
->refname
, b
->refname
))
1252 if (a
->update_index
!= b
->update_index
||
1253 a
->value_type
!= b
->value_type
)
1256 switch (a
->value_type
) {
1257 case REFTABLE_REF_SYMREF
:
1258 return !strcmp(a
->value
.symref
, b
->value
.symref
);
1259 case REFTABLE_REF_VAL2
:
1260 return hash_equal(a
->value
.val2
.value
, b
->value
.val2
.value
,
1262 hash_equal(a
->value
.val2
.target_value
,
1263 b
->value
.val2
.target_value
, hash_size
);
1264 case REFTABLE_REF_VAL1
:
1265 return hash_equal(a
->value
.val1
, b
->value
.val1
, hash_size
);
1266 case REFTABLE_REF_DELETION
:
1273 int reftable_ref_record_compare_name(const void *a
, const void *b
)
1275 return strcmp(((struct reftable_ref_record
*)a
)->refname
,
1276 ((struct reftable_ref_record
*)b
)->refname
);
1279 int reftable_ref_record_is_deletion(const struct reftable_ref_record
*ref
)
1281 return ref
->value_type
== REFTABLE_REF_DELETION
;
1284 int reftable_log_record_compare_key(const void *a
, const void *b
)
1286 const struct reftable_log_record
*la
= a
;
1287 const struct reftable_log_record
*lb
= b
;
1289 int cmp
= strcmp(la
->refname
, lb
->refname
);
1292 if (la
->update_index
> lb
->update_index
)
1294 return (la
->update_index
< lb
->update_index
) ? 1 : 0;
1297 int reftable_log_record_is_deletion(const struct reftable_log_record
*log
)
1299 return (log
->value_type
== REFTABLE_LOG_DELETION
);
1302 static void *reftable_record_data(struct reftable_record
*rec
)
1304 switch (rec
->type
) {
1305 case BLOCK_TYPE_REF
:
1307 case BLOCK_TYPE_LOG
:
1309 case BLOCK_TYPE_INDEX
:
1311 case BLOCK_TYPE_OBJ
:
1317 static struct reftable_record_vtable
*
1318 reftable_record_vtable(struct reftable_record
*rec
)
1320 switch (rec
->type
) {
1321 case BLOCK_TYPE_REF
:
1322 return &reftable_ref_record_vtable
;
1323 case BLOCK_TYPE_LOG
:
1324 return &reftable_log_record_vtable
;
1325 case BLOCK_TYPE_INDEX
:
1326 return &reftable_index_record_vtable
;
1327 case BLOCK_TYPE_OBJ
:
1328 return &reftable_obj_record_vtable
;
1333 void reftable_record_init(struct reftable_record
*rec
, uint8_t typ
)
1335 memset(rec
, 0, sizeof(*rec
));
1339 case BLOCK_TYPE_REF
:
1340 case BLOCK_TYPE_LOG
:
1341 case BLOCK_TYPE_OBJ
:
1343 case BLOCK_TYPE_INDEX
:
1344 strbuf_init(&rec
->u
.idx
.last_key
, 0);
1347 BUG("unhandled record type");
1351 void reftable_record_print(struct reftable_record
*rec
, int hash_size
)
1353 printf("'%c': ", rec
->type
);
1354 reftable_record_vtable(rec
)->print(reftable_record_data(rec
), hash_size
);