]> git.ipfire.org Git - thirdparty/git.git/blob - reftable/record.c
date: make "iso-strict" conforming for the UTC timezone
[thirdparty/git.git] / reftable / record.c
1 /*
2 Copyright 2020 Google LLC
3
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
7 */
8
9 /* record.c - methods for different types of records. */
10
11 #include "record.h"
12
13 #include "system.h"
14 #include "constants.h"
15 #include "reftable-error.h"
16 #include "basics.h"
17
18 static struct reftable_record_vtable *
19 reftable_record_vtable(struct reftable_record *rec);
20 static void *reftable_record_data(struct reftable_record *rec);
21
22 int get_var_int(uint64_t *dest, struct string_view *in)
23 {
24 int ptr = 0;
25 uint64_t val;
26
27 if (in->len == 0)
28 return -1;
29 val = in->buf[ptr] & 0x7f;
30
31 while (in->buf[ptr] & 0x80) {
32 ptr++;
33 if (ptr > in->len) {
34 return -1;
35 }
36 val = (val + 1) << 7 | (uint64_t)(in->buf[ptr] & 0x7f);
37 }
38
39 *dest = val;
40 return ptr + 1;
41 }
42
43 int put_var_int(struct string_view *dest, uint64_t val)
44 {
45 uint8_t buf[10] = { 0 };
46 int i = 9;
47 int n = 0;
48 buf[i] = (uint8_t)(val & 0x7f);
49 i--;
50 while (1) {
51 val >>= 7;
52 if (!val) {
53 break;
54 }
55 val--;
56 buf[i] = 0x80 | (uint8_t)(val & 0x7f);
57 i--;
58 }
59
60 n = sizeof(buf) - i - 1;
61 if (dest->len < n)
62 return -1;
63 memcpy(dest->buf, &buf[i + 1], n);
64 return n;
65 }
66
67 int reftable_is_block_type(uint8_t typ)
68 {
69 switch (typ) {
70 case BLOCK_TYPE_REF:
71 case BLOCK_TYPE_LOG:
72 case BLOCK_TYPE_OBJ:
73 case BLOCK_TYPE_INDEX:
74 return 1;
75 }
76 return 0;
77 }
78
79 const unsigned char *reftable_ref_record_val1(const struct reftable_ref_record *rec)
80 {
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;
86 default:
87 return NULL;
88 }
89 }
90
91 const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record *rec)
92 {
93 switch (rec->value_type) {
94 case REFTABLE_REF_VAL2:
95 return rec->value.val2.target_value;
96 default:
97 return NULL;
98 }
99 }
100
101 static int decode_string(struct strbuf *dest, struct string_view in)
102 {
103 int start_len = in.len;
104 uint64_t tsize = 0;
105 int n = get_var_int(&tsize, &in);
106 if (n <= 0)
107 return -1;
108 string_view_consume(&in, n);
109 if (in.len < tsize)
110 return -1;
111
112 strbuf_reset(dest);
113 strbuf_add(dest, in.buf, tsize);
114 string_view_consume(&in, tsize);
115
116 return start_len - in.len;
117 }
118
119 static int encode_string(char *str, struct string_view s)
120 {
121 struct string_view start = s;
122 int l = strlen(str);
123 int n = put_var_int(&s, l);
124 if (n < 0)
125 return -1;
126 string_view_consume(&s, n);
127 if (s.len < l)
128 return -1;
129 memcpy(s.buf, str, l);
130 string_view_consume(&s, l);
131
132 return start.len - s.len;
133 }
134
135 int reftable_encode_key(int *restart, struct string_view dest,
136 struct strbuf prev_key, struct strbuf key,
137 uint8_t extra)
138 {
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);
143 if (n < 0)
144 return -1;
145 string_view_consume(&dest, n);
146
147 *restart = (prefix_len == 0);
148
149 n = put_var_int(&dest, suffix_len << 3 | (uint64_t)extra);
150 if (n < 0)
151 return -1;
152 string_view_consume(&dest, n);
153
154 if (dest.len < suffix_len)
155 return -1;
156 memcpy(dest.buf, key.buf + prefix_len, suffix_len);
157 string_view_consume(&dest, suffix_len);
158
159 return start.len - dest.len;
160 }
161
162 int reftable_decode_key(struct strbuf *key, uint8_t *extra,
163 struct strbuf last_key, struct string_view in)
164 {
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);
169 if (n < 0)
170 return -1;
171 string_view_consume(&in, n);
172
173 if (prefix_len > last_key.len)
174 return -1;
175
176 n = get_var_int(&suffix_len, &in);
177 if (n <= 0)
178 return -1;
179 string_view_consume(&in, n);
180
181 *extra = (uint8_t)(suffix_len & 0x7);
182 suffix_len >>= 3;
183
184 if (in.len < suffix_len)
185 return -1;
186
187 strbuf_reset(key);
188 strbuf_add(key, last_key.buf, prefix_len);
189 strbuf_add(key, in.buf, suffix_len);
190 string_view_consume(&in, suffix_len);
191
192 return start_len - in.len;
193 }
194
195 static void reftable_ref_record_key(const void *r, struct strbuf *dest)
196 {
197 const struct reftable_ref_record *rec =
198 (const struct reftable_ref_record *)r;
199 strbuf_reset(dest);
200 strbuf_addstr(dest, rec->refname);
201 }
202
203 static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
204 int hash_size)
205 {
206 struct reftable_ref_record *ref = rec;
207 const struct reftable_ref_record *src = src_rec;
208 assert(hash_size > 0);
209
210 /* This is simple and correct, but we could probably reuse the hash
211 * fields. */
212 reftable_ref_record_release(ref);
213 if (src->refname) {
214 ref->refname = xstrdup(src->refname);
215 }
216 ref->update_index = src->update_index;
217 ref->value_type = src->value_type;
218 switch (src->value_type) {
219 case REFTABLE_REF_DELETION:
220 break;
221 case REFTABLE_REF_VAL1:
222 memcpy(ref->value.val1, src->value.val1, hash_size);
223 break;
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);
228 break;
229 case REFTABLE_REF_SYMREF:
230 ref->value.symref = xstrdup(src->value.symref);
231 break;
232 }
233 }
234
235 static char hexdigit(int c)
236 {
237 if (c <= 9)
238 return '0' + c;
239 return 'a' + (c - 10);
240 }
241
242 static void hex_format(char *dest, const unsigned char *src, int hash_size)
243 {
244 assert(hash_size > 0);
245 if (src) {
246 int i = 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);
250 }
251 dest[2 * hash_size] = 0;
252 }
253 }
254
255 static void reftable_ref_record_print_sz(const struct reftable_ref_record *ref,
256 int hash_size)
257 {
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);
263 break;
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,
268 hash_size);
269 printf("(T %s)", hex);
270 break;
271 case REFTABLE_REF_VAL1:
272 hex_format(hex, ref->value.val1, hash_size);
273 printf("val 1 %s", hex);
274 break;
275 case REFTABLE_REF_DELETION:
276 printf("delete");
277 break;
278 }
279 printf("}\n");
280 }
281
282 void reftable_ref_record_print(const struct reftable_ref_record *ref,
283 uint32_t hash_id) {
284 reftable_ref_record_print_sz(ref, hash_size(hash_id));
285 }
286
287 static void reftable_ref_record_release_void(void *rec)
288 {
289 reftable_ref_record_release(rec);
290 }
291
292 void reftable_ref_record_release(struct reftable_ref_record *ref)
293 {
294 switch (ref->value_type) {
295 case REFTABLE_REF_SYMREF:
296 reftable_free(ref->value.symref);
297 break;
298 case REFTABLE_REF_VAL2:
299 break;
300 case REFTABLE_REF_VAL1:
301 break;
302 case REFTABLE_REF_DELETION:
303 break;
304 default:
305 abort();
306 }
307
308 reftable_free(ref->refname);
309 memset(ref, 0, sizeof(struct reftable_ref_record));
310 }
311
312 static uint8_t reftable_ref_record_val_type(const void *rec)
313 {
314 const struct reftable_ref_record *r =
315 (const struct reftable_ref_record *)rec;
316 return r->value_type;
317 }
318
319 static int reftable_ref_record_encode(const void *rec, struct string_view s,
320 int hash_size)
321 {
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);
327 if (n < 0)
328 return -1;
329 string_view_consume(&s, n);
330
331 switch (r->value_type) {
332 case REFTABLE_REF_SYMREF:
333 n = encode_string(r->value.symref, s);
334 if (n < 0) {
335 return -1;
336 }
337 string_view_consume(&s, n);
338 break;
339 case REFTABLE_REF_VAL2:
340 if (s.len < 2 * hash_size) {
341 return -1;
342 }
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);
347 break;
348 case REFTABLE_REF_VAL1:
349 if (s.len < hash_size) {
350 return -1;
351 }
352 memcpy(s.buf, r->value.val1, hash_size);
353 string_view_consume(&s, hash_size);
354 break;
355 case REFTABLE_REF_DELETION:
356 break;
357 default:
358 abort();
359 }
360
361 return start.len - s.len;
362 }
363
364 static int reftable_ref_record_decode(void *rec, struct strbuf key,
365 uint8_t val_type, struct string_view in,
366 int hash_size)
367 {
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);
372 if (n < 0)
373 return n;
374 string_view_consume(&in, n);
375
376 reftable_ref_record_release(r);
377
378 assert(hash_size > 0);
379
380 r->refname = reftable_malloc(key.len + 1);
381 memcpy(r->refname, key.buf, key.len);
382 r->refname[key.len] = 0;
383
384 r->update_index = update_index;
385 r->value_type = val_type;
386 switch (val_type) {
387 case REFTABLE_REF_VAL1:
388 if (in.len < hash_size) {
389 return -1;
390 }
391
392 memcpy(r->value.val1, in.buf, hash_size);
393 string_view_consume(&in, hash_size);
394 break;
395
396 case REFTABLE_REF_VAL2:
397 if (in.len < 2 * hash_size) {
398 return -1;
399 }
400
401 memcpy(r->value.val2.value, in.buf, hash_size);
402 string_view_consume(&in, hash_size);
403
404 memcpy(r->value.val2.target_value, in.buf, hash_size);
405 string_view_consume(&in, hash_size);
406 break;
407
408 case REFTABLE_REF_SYMREF: {
409 struct strbuf dest = STRBUF_INIT;
410 int n = decode_string(&dest, in);
411 if (n < 0) {
412 return -1;
413 }
414 string_view_consume(&in, n);
415 r->value.symref = dest.buf;
416 } break;
417
418 case REFTABLE_REF_DELETION:
419 break;
420 default:
421 abort();
422 break;
423 }
424
425 return start.len - in.len;
426 }
427
428 static int reftable_ref_record_is_deletion_void(const void *p)
429 {
430 return reftable_ref_record_is_deletion(
431 (const struct reftable_ref_record *)p);
432 }
433
434 static int reftable_ref_record_equal_void(const void *a,
435 const void *b, int hash_size)
436 {
437 struct reftable_ref_record *ra = (struct reftable_ref_record *) a;
438 struct reftable_ref_record *rb = (struct reftable_ref_record *) b;
439 return reftable_ref_record_equal(ra, rb, hash_size);
440 }
441
442 static int reftable_ref_record_cmp_void(const void *_a, const void *_b)
443 {
444 const struct reftable_ref_record *a = _a;
445 const struct reftable_ref_record *b = _b;
446 return strcmp(a->refname, b->refname);
447 }
448
449 static void reftable_ref_record_print_void(const void *rec,
450 int hash_size)
451 {
452 reftable_ref_record_print_sz((struct reftable_ref_record *) rec, hash_size);
453 }
454
455 static struct reftable_record_vtable reftable_ref_record_vtable = {
456 .key = &reftable_ref_record_key,
457 .type = BLOCK_TYPE_REF,
458 .copy_from = &reftable_ref_record_copy_from,
459 .val_type = &reftable_ref_record_val_type,
460 .encode = &reftable_ref_record_encode,
461 .decode = &reftable_ref_record_decode,
462 .release = &reftable_ref_record_release_void,
463 .is_deletion = &reftable_ref_record_is_deletion_void,
464 .equal = &reftable_ref_record_equal_void,
465 .cmp = &reftable_ref_record_cmp_void,
466 .print = &reftable_ref_record_print_void,
467 };
468
469 static void reftable_obj_record_key(const void *r, struct strbuf *dest)
470 {
471 const struct reftable_obj_record *rec =
472 (const struct reftable_obj_record *)r;
473 strbuf_reset(dest);
474 strbuf_add(dest, rec->hash_prefix, rec->hash_prefix_len);
475 }
476
477 static void reftable_obj_record_release(void *rec)
478 {
479 struct reftable_obj_record *obj = rec;
480 FREE_AND_NULL(obj->hash_prefix);
481 FREE_AND_NULL(obj->offsets);
482 memset(obj, 0, sizeof(struct reftable_obj_record));
483 }
484
485 static void reftable_obj_record_print(const void *rec, int hash_size)
486 {
487 const struct reftable_obj_record *obj = rec;
488 char hex[GIT_MAX_HEXSZ + 1] = { 0 };
489 struct strbuf offset_str = STRBUF_INIT;
490 int i;
491
492 for (i = 0; i < obj->offset_len; i++)
493 strbuf_addf(&offset_str, "%" PRIu64 " ", obj->offsets[i]);
494 hex_format(hex, obj->hash_prefix, obj->hash_prefix_len);
495 printf("prefix %s (len %d), offsets [%s]\n",
496 hex, obj->hash_prefix_len, offset_str.buf);
497 strbuf_release(&offset_str);
498 }
499
500 static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
501 int hash_size)
502 {
503 struct reftable_obj_record *obj = rec;
504 const struct reftable_obj_record *src =
505 (const struct reftable_obj_record *)src_rec;
506
507 reftable_obj_record_release(obj);
508
509 REFTABLE_ALLOC_ARRAY(obj->hash_prefix, 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);
513
514 REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len);
515 obj->offset_len = src->offset_len;
516 COPY_ARRAY(obj->offsets, src->offsets, src->offset_len);
517 }
518
519 static uint8_t reftable_obj_record_val_type(const void *rec)
520 {
521 const struct reftable_obj_record *r = rec;
522 if (r->offset_len > 0 && r->offset_len < 8)
523 return r->offset_len;
524 return 0;
525 }
526
527 static int reftable_obj_record_encode(const void *rec, struct string_view s,
528 int hash_size)
529 {
530 const struct reftable_obj_record *r = rec;
531 struct string_view start = s;
532 int i = 0;
533 int n = 0;
534 uint64_t last = 0;
535 if (r->offset_len == 0 || r->offset_len >= 8) {
536 n = put_var_int(&s, r->offset_len);
537 if (n < 0) {
538 return -1;
539 }
540 string_view_consume(&s, n);
541 }
542 if (r->offset_len == 0)
543 return start.len - s.len;
544 n = put_var_int(&s, r->offsets[0]);
545 if (n < 0)
546 return -1;
547 string_view_consume(&s, n);
548
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);
552 if (n < 0) {
553 return -1;
554 }
555 string_view_consume(&s, n);
556 last = r->offsets[i];
557 }
558 return start.len - s.len;
559 }
560
561 static int reftable_obj_record_decode(void *rec, struct strbuf key,
562 uint8_t val_type, struct string_view in,
563 int hash_size)
564 {
565 struct string_view start = in;
566 struct reftable_obj_record *r = rec;
567 uint64_t count = val_type;
568 int n = 0;
569 uint64_t last;
570 int j;
571
572 REFTABLE_ALLOC_ARRAY(r->hash_prefix, key.len);
573 memcpy(r->hash_prefix, key.buf, key.len);
574 r->hash_prefix_len = key.len;
575
576 if (val_type == 0) {
577 n = get_var_int(&count, &in);
578 if (n < 0) {
579 return n;
580 }
581
582 string_view_consume(&in, n);
583 }
584
585 r->offsets = NULL;
586 r->offset_len = 0;
587 if (count == 0)
588 return start.len - in.len;
589
590 REFTABLE_ALLOC_ARRAY(r->offsets, count);
591 r->offset_len = count;
592
593 n = get_var_int(&r->offsets[0], &in);
594 if (n < 0)
595 return n;
596 string_view_consume(&in, n);
597
598 last = r->offsets[0];
599 j = 1;
600 while (j < count) {
601 uint64_t delta = 0;
602 int n = get_var_int(&delta, &in);
603 if (n < 0) {
604 return n;
605 }
606 string_view_consume(&in, n);
607
608 last = r->offsets[j] = (delta + last);
609 j++;
610 }
611 return start.len - in.len;
612 }
613
614 static int not_a_deletion(const void *p)
615 {
616 return 0;
617 }
618
619 static int reftable_obj_record_equal_void(const void *a, const void *b, int hash_size)
620 {
621 struct reftable_obj_record *ra = (struct reftable_obj_record *) a;
622 struct reftable_obj_record *rb = (struct reftable_obj_record *) b;
623
624 if (ra->hash_prefix_len != rb->hash_prefix_len
625 || ra->offset_len != rb->offset_len)
626 return 0;
627
628 if (ra->hash_prefix_len &&
629 memcmp(ra->hash_prefix, rb->hash_prefix, ra->hash_prefix_len))
630 return 0;
631 if (ra->offset_len &&
632 memcmp(ra->offsets, rb->offsets, ra->offset_len * sizeof(uint64_t)))
633 return 0;
634
635 return 1;
636 }
637
638 static int reftable_obj_record_cmp_void(const void *_a, const void *_b)
639 {
640 const struct reftable_obj_record *a = _a;
641 const struct reftable_obj_record *b = _b;
642 int cmp;
643
644 cmp = memcmp(a->hash_prefix, b->hash_prefix,
645 a->hash_prefix_len > b->hash_prefix_len ?
646 a->hash_prefix_len : b->hash_prefix_len);
647 if (cmp)
648 return cmp;
649
650 /*
651 * When the prefix is the same then the object record that is longer is
652 * considered to be bigger.
653 */
654 return a->hash_prefix_len - b->hash_prefix_len;
655 }
656
657 static struct reftable_record_vtable reftable_obj_record_vtable = {
658 .key = &reftable_obj_record_key,
659 .type = BLOCK_TYPE_OBJ,
660 .copy_from = &reftable_obj_record_copy_from,
661 .val_type = &reftable_obj_record_val_type,
662 .encode = &reftable_obj_record_encode,
663 .decode = &reftable_obj_record_decode,
664 .release = &reftable_obj_record_release,
665 .is_deletion = &not_a_deletion,
666 .equal = &reftable_obj_record_equal_void,
667 .cmp = &reftable_obj_record_cmp_void,
668 .print = &reftable_obj_record_print,
669 };
670
671 static void reftable_log_record_print_sz(struct reftable_log_record *log,
672 int hash_size)
673 {
674 char hex[GIT_MAX_HEXSZ + 1] = { 0 };
675
676 switch (log->value_type) {
677 case REFTABLE_LOG_DELETION:
678 printf("log{%s(%" PRIu64 ") delete\n", log->refname,
679 log->update_index);
680 break;
681 case REFTABLE_LOG_UPDATE:
682 printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n",
683 log->refname, log->update_index,
684 log->value.update.name ? log->value.update.name : "",
685 log->value.update.email ? log->value.update.email : "",
686 log->value.update.time,
687 log->value.update.tz_offset);
688 hex_format(hex, log->value.update.old_hash, hash_size);
689 printf("%s => ", hex);
690 hex_format(hex, log->value.update.new_hash, hash_size);
691 printf("%s\n\n%s\n}\n", hex,
692 log->value.update.message ? log->value.update.message : "");
693 break;
694 }
695 }
696
697 void reftable_log_record_print(struct reftable_log_record *log,
698 uint32_t hash_id)
699 {
700 reftable_log_record_print_sz(log, hash_size(hash_id));
701 }
702
703 static void reftable_log_record_key(const void *r, struct strbuf *dest)
704 {
705 const struct reftable_log_record *rec =
706 (const struct reftable_log_record *)r;
707 int len = strlen(rec->refname);
708 uint8_t i64[8];
709 uint64_t ts = 0;
710 strbuf_reset(dest);
711 strbuf_add(dest, (uint8_t *)rec->refname, len + 1);
712
713 ts = (~ts) - rec->update_index;
714 put_be64(&i64[0], ts);
715 strbuf_add(dest, i64, sizeof(i64));
716 }
717
718 static void reftable_log_record_copy_from(void *rec, const void *src_rec,
719 int hash_size)
720 {
721 struct reftable_log_record *dst = rec;
722 const struct reftable_log_record *src =
723 (const struct reftable_log_record *)src_rec;
724
725 reftable_log_record_release(dst);
726 *dst = *src;
727 if (dst->refname) {
728 dst->refname = xstrdup(dst->refname);
729 }
730 switch (dst->value_type) {
731 case REFTABLE_LOG_DELETION:
732 break;
733 case REFTABLE_LOG_UPDATE:
734 if (dst->value.update.email) {
735 dst->value.update.email =
736 xstrdup(dst->value.update.email);
737 }
738 if (dst->value.update.name) {
739 dst->value.update.name =
740 xstrdup(dst->value.update.name);
741 }
742 if (dst->value.update.message) {
743 dst->value.update.message =
744 xstrdup(dst->value.update.message);
745 }
746
747 if (dst->value.update.new_hash) {
748 REFTABLE_ALLOC_ARRAY(dst->value.update.new_hash, hash_size);
749 memcpy(dst->value.update.new_hash,
750 src->value.update.new_hash, hash_size);
751 }
752 if (dst->value.update.old_hash) {
753 REFTABLE_ALLOC_ARRAY(dst->value.update.old_hash, hash_size);
754 memcpy(dst->value.update.old_hash,
755 src->value.update.old_hash, hash_size);
756 }
757 break;
758 }
759 }
760
761 static void reftable_log_record_release_void(void *rec)
762 {
763 struct reftable_log_record *r = rec;
764 reftable_log_record_release(r);
765 }
766
767 void reftable_log_record_release(struct reftable_log_record *r)
768 {
769 reftable_free(r->refname);
770 switch (r->value_type) {
771 case REFTABLE_LOG_DELETION:
772 break;
773 case REFTABLE_LOG_UPDATE:
774 reftable_free(r->value.update.new_hash);
775 reftable_free(r->value.update.old_hash);
776 reftable_free(r->value.update.name);
777 reftable_free(r->value.update.email);
778 reftable_free(r->value.update.message);
779 break;
780 }
781 memset(r, 0, sizeof(struct reftable_log_record));
782 }
783
784 static uint8_t reftable_log_record_val_type(const void *rec)
785 {
786 const struct reftable_log_record *log =
787 (const struct reftable_log_record *)rec;
788
789 return reftable_log_record_is_deletion(log) ? 0 : 1;
790 }
791
792 static uint8_t zero[GIT_SHA256_RAWSZ] = { 0 };
793
794 static int reftable_log_record_encode(const void *rec, struct string_view s,
795 int hash_size)
796 {
797 const struct reftable_log_record *r = rec;
798 struct string_view start = s;
799 int n = 0;
800 uint8_t *oldh = NULL;
801 uint8_t *newh = NULL;
802 if (reftable_log_record_is_deletion(r))
803 return 0;
804
805 oldh = r->value.update.old_hash;
806 newh = r->value.update.new_hash;
807 if (!oldh) {
808 oldh = zero;
809 }
810 if (!newh) {
811 newh = zero;
812 }
813
814 if (s.len < 2 * hash_size)
815 return -1;
816
817 memcpy(s.buf, oldh, hash_size);
818 memcpy(s.buf + hash_size, newh, hash_size);
819 string_view_consume(&s, 2 * hash_size);
820
821 n = encode_string(r->value.update.name ? r->value.update.name : "", s);
822 if (n < 0)
823 return -1;
824 string_view_consume(&s, n);
825
826 n = encode_string(r->value.update.email ? r->value.update.email : "",
827 s);
828 if (n < 0)
829 return -1;
830 string_view_consume(&s, n);
831
832 n = put_var_int(&s, r->value.update.time);
833 if (n < 0)
834 return -1;
835 string_view_consume(&s, n);
836
837 if (s.len < 2)
838 return -1;
839
840 put_be16(s.buf, r->value.update.tz_offset);
841 string_view_consume(&s, 2);
842
843 n = encode_string(
844 r->value.update.message ? r->value.update.message : "", s);
845 if (n < 0)
846 return -1;
847 string_view_consume(&s, n);
848
849 return start.len - s.len;
850 }
851
852 static int reftable_log_record_decode(void *rec, struct strbuf key,
853 uint8_t val_type, struct string_view in,
854 int hash_size)
855 {
856 struct string_view start = in;
857 struct reftable_log_record *r = rec;
858 uint64_t max = 0;
859 uint64_t ts = 0;
860 struct strbuf dest = STRBUF_INIT;
861 int n;
862
863 if (key.len <= 9 || key.buf[key.len - 9] != 0)
864 return REFTABLE_FORMAT_ERROR;
865
866 r->refname = reftable_realloc(r->refname, key.len - 8);
867 memcpy(r->refname, key.buf, key.len - 8);
868 ts = get_be64(key.buf + key.len - 8);
869
870 r->update_index = (~max) - ts;
871
872 if (val_type != r->value_type) {
873 switch (r->value_type) {
874 case REFTABLE_LOG_UPDATE:
875 FREE_AND_NULL(r->value.update.old_hash);
876 FREE_AND_NULL(r->value.update.new_hash);
877 FREE_AND_NULL(r->value.update.message);
878 FREE_AND_NULL(r->value.update.email);
879 FREE_AND_NULL(r->value.update.name);
880 break;
881 case REFTABLE_LOG_DELETION:
882 break;
883 }
884 }
885
886 r->value_type = val_type;
887 if (val_type == REFTABLE_LOG_DELETION)
888 return 0;
889
890 if (in.len < 2 * hash_size)
891 return REFTABLE_FORMAT_ERROR;
892
893 r->value.update.old_hash =
894 reftable_realloc(r->value.update.old_hash, hash_size);
895 r->value.update.new_hash =
896 reftable_realloc(r->value.update.new_hash, hash_size);
897
898 memcpy(r->value.update.old_hash, in.buf, hash_size);
899 memcpy(r->value.update.new_hash, in.buf + hash_size, hash_size);
900
901 string_view_consume(&in, 2 * hash_size);
902
903 n = decode_string(&dest, in);
904 if (n < 0)
905 goto done;
906 string_view_consume(&in, n);
907
908 r->value.update.name =
909 reftable_realloc(r->value.update.name, dest.len + 1);
910 memcpy(r->value.update.name, dest.buf, dest.len);
911 r->value.update.name[dest.len] = 0;
912
913 strbuf_reset(&dest);
914 n = decode_string(&dest, in);
915 if (n < 0)
916 goto done;
917 string_view_consume(&in, n);
918
919 r->value.update.email =
920 reftable_realloc(r->value.update.email, dest.len + 1);
921 memcpy(r->value.update.email, dest.buf, dest.len);
922 r->value.update.email[dest.len] = 0;
923
924 ts = 0;
925 n = get_var_int(&ts, &in);
926 if (n < 0)
927 goto done;
928 string_view_consume(&in, n);
929 r->value.update.time = ts;
930 if (in.len < 2)
931 goto done;
932
933 r->value.update.tz_offset = get_be16(in.buf);
934 string_view_consume(&in, 2);
935
936 strbuf_reset(&dest);
937 n = decode_string(&dest, in);
938 if (n < 0)
939 goto done;
940 string_view_consume(&in, n);
941
942 r->value.update.message =
943 reftable_realloc(r->value.update.message, dest.len + 1);
944 memcpy(r->value.update.message, dest.buf, dest.len);
945 r->value.update.message[dest.len] = 0;
946
947 strbuf_release(&dest);
948 return start.len - in.len;
949
950 done:
951 strbuf_release(&dest);
952 return REFTABLE_FORMAT_ERROR;
953 }
954
955 static int null_streq(char *a, char *b)
956 {
957 char *empty = "";
958 if (!a)
959 a = empty;
960
961 if (!b)
962 b = empty;
963
964 return 0 == strcmp(a, b);
965 }
966
967 static int zero_hash_eq(uint8_t *a, uint8_t *b, int sz)
968 {
969 if (!a)
970 a = zero;
971
972 if (!b)
973 b = zero;
974
975 return !memcmp(a, b, sz);
976 }
977
978 static int reftable_log_record_equal_void(const void *a,
979 const void *b, int hash_size)
980 {
981 return reftable_log_record_equal((struct reftable_log_record *) a,
982 (struct reftable_log_record *) b,
983 hash_size);
984 }
985
986 static int reftable_log_record_cmp_void(const void *_a, const void *_b)
987 {
988 const struct reftable_log_record *a = _a;
989 const struct reftable_log_record *b = _b;
990 int cmp = strcmp(a->refname, b->refname);
991 if (cmp)
992 return cmp;
993
994 /*
995 * Note that the comparison here is reversed. This is because the
996 * update index is reversed when comparing keys. For reference, see how
997 * we handle this in reftable_log_record_key()`.
998 */
999 return b->update_index - a->update_index;
1000 }
1001
1002 int reftable_log_record_equal(const struct reftable_log_record *a,
1003 const struct reftable_log_record *b, int hash_size)
1004 {
1005 if (!(null_streq(a->refname, b->refname) &&
1006 a->update_index == b->update_index &&
1007 a->value_type == b->value_type))
1008 return 0;
1009
1010 switch (a->value_type) {
1011 case REFTABLE_LOG_DELETION:
1012 return 1;
1013 case REFTABLE_LOG_UPDATE:
1014 return null_streq(a->value.update.name, b->value.update.name) &&
1015 a->value.update.time == b->value.update.time &&
1016 a->value.update.tz_offset == b->value.update.tz_offset &&
1017 null_streq(a->value.update.email,
1018 b->value.update.email) &&
1019 null_streq(a->value.update.message,
1020 b->value.update.message) &&
1021 zero_hash_eq(a->value.update.old_hash,
1022 b->value.update.old_hash, hash_size) &&
1023 zero_hash_eq(a->value.update.new_hash,
1024 b->value.update.new_hash, hash_size);
1025 }
1026
1027 abort();
1028 }
1029
1030 static int reftable_log_record_is_deletion_void(const void *p)
1031 {
1032 return reftable_log_record_is_deletion(
1033 (const struct reftable_log_record *)p);
1034 }
1035
1036 static void reftable_log_record_print_void(const void *rec, int hash_size)
1037 {
1038 reftable_log_record_print_sz((struct reftable_log_record*)rec, hash_size);
1039 }
1040
1041 static struct reftable_record_vtable reftable_log_record_vtable = {
1042 .key = &reftable_log_record_key,
1043 .type = BLOCK_TYPE_LOG,
1044 .copy_from = &reftable_log_record_copy_from,
1045 .val_type = &reftable_log_record_val_type,
1046 .encode = &reftable_log_record_encode,
1047 .decode = &reftable_log_record_decode,
1048 .release = &reftable_log_record_release_void,
1049 .is_deletion = &reftable_log_record_is_deletion_void,
1050 .equal = &reftable_log_record_equal_void,
1051 .cmp = &reftable_log_record_cmp_void,
1052 .print = &reftable_log_record_print_void,
1053 };
1054
1055 static void reftable_index_record_key(const void *r, struct strbuf *dest)
1056 {
1057 const struct reftable_index_record *rec = r;
1058 strbuf_reset(dest);
1059 strbuf_addbuf(dest, &rec->last_key);
1060 }
1061
1062 static void reftable_index_record_copy_from(void *rec, const void *src_rec,
1063 int hash_size)
1064 {
1065 struct reftable_index_record *dst = rec;
1066 const struct reftable_index_record *src = src_rec;
1067
1068 strbuf_reset(&dst->last_key);
1069 strbuf_addbuf(&dst->last_key, &src->last_key);
1070 dst->offset = src->offset;
1071 }
1072
1073 static void reftable_index_record_release(void *rec)
1074 {
1075 struct reftable_index_record *idx = rec;
1076 strbuf_release(&idx->last_key);
1077 }
1078
1079 static uint8_t reftable_index_record_val_type(const void *rec)
1080 {
1081 return 0;
1082 }
1083
1084 static int reftable_index_record_encode(const void *rec, struct string_view out,
1085 int hash_size)
1086 {
1087 const struct reftable_index_record *r =
1088 (const struct reftable_index_record *)rec;
1089 struct string_view start = out;
1090
1091 int n = put_var_int(&out, r->offset);
1092 if (n < 0)
1093 return n;
1094
1095 string_view_consume(&out, n);
1096
1097 return start.len - out.len;
1098 }
1099
1100 static int reftable_index_record_decode(void *rec, struct strbuf key,
1101 uint8_t val_type, struct string_view in,
1102 int hash_size)
1103 {
1104 struct string_view start = in;
1105 struct reftable_index_record *r = rec;
1106 int n = 0;
1107
1108 strbuf_reset(&r->last_key);
1109 strbuf_addbuf(&r->last_key, &key);
1110
1111 n = get_var_int(&r->offset, &in);
1112 if (n < 0)
1113 return n;
1114
1115 string_view_consume(&in, n);
1116 return start.len - in.len;
1117 }
1118
1119 static int reftable_index_record_equal(const void *a, const void *b, int hash_size)
1120 {
1121 struct reftable_index_record *ia = (struct reftable_index_record *) a;
1122 struct reftable_index_record *ib = (struct reftable_index_record *) b;
1123
1124 return ia->offset == ib->offset && !strbuf_cmp(&ia->last_key, &ib->last_key);
1125 }
1126
1127 static int reftable_index_record_cmp(const void *_a, const void *_b)
1128 {
1129 const struct reftable_index_record *a = _a;
1130 const struct reftable_index_record *b = _b;
1131 return strbuf_cmp(&a->last_key, &b->last_key);
1132 }
1133
1134 static void reftable_index_record_print(const void *rec, int hash_size)
1135 {
1136 const struct reftable_index_record *idx = rec;
1137 /* TODO: escape null chars? */
1138 printf("\"%s\" %" PRIu64 "\n", idx->last_key.buf, idx->offset);
1139 }
1140
1141 static struct reftable_record_vtable reftable_index_record_vtable = {
1142 .key = &reftable_index_record_key,
1143 .type = BLOCK_TYPE_INDEX,
1144 .copy_from = &reftable_index_record_copy_from,
1145 .val_type = &reftable_index_record_val_type,
1146 .encode = &reftable_index_record_encode,
1147 .decode = &reftable_index_record_decode,
1148 .release = &reftable_index_record_release,
1149 .is_deletion = &not_a_deletion,
1150 .equal = &reftable_index_record_equal,
1151 .cmp = &reftable_index_record_cmp,
1152 .print = &reftable_index_record_print,
1153 };
1154
1155 void reftable_record_key(struct reftable_record *rec, struct strbuf *dest)
1156 {
1157 reftable_record_vtable(rec)->key(reftable_record_data(rec), dest);
1158 }
1159
1160 uint8_t reftable_record_type(struct reftable_record *rec)
1161 {
1162 return rec->type;
1163 }
1164
1165 int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
1166 int hash_size)
1167 {
1168 return reftable_record_vtable(rec)->encode(reftable_record_data(rec),
1169 dest, hash_size);
1170 }
1171
1172 void reftable_record_copy_from(struct reftable_record *rec,
1173 struct reftable_record *src, int hash_size)
1174 {
1175 assert(src->type == rec->type);
1176
1177 reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
1178 reftable_record_data(src),
1179 hash_size);
1180 }
1181
1182 uint8_t reftable_record_val_type(struct reftable_record *rec)
1183 {
1184 return reftable_record_vtable(rec)->val_type(reftable_record_data(rec));
1185 }
1186
1187 int reftable_record_decode(struct reftable_record *rec, struct strbuf key,
1188 uint8_t extra, struct string_view src, int hash_size)
1189 {
1190 return reftable_record_vtable(rec)->decode(reftable_record_data(rec),
1191 key, extra, src, hash_size);
1192 }
1193
1194 void reftable_record_release(struct reftable_record *rec)
1195 {
1196 reftable_record_vtable(rec)->release(reftable_record_data(rec));
1197 }
1198
1199 int reftable_record_is_deletion(struct reftable_record *rec)
1200 {
1201 return reftable_record_vtable(rec)->is_deletion(
1202 reftable_record_data(rec));
1203 }
1204
1205 int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b)
1206 {
1207 if (a->type != b->type)
1208 BUG("cannot compare reftable records of different type");
1209 return reftable_record_vtable(a)->cmp(
1210 reftable_record_data(a), reftable_record_data(b));
1211 }
1212
1213 int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size)
1214 {
1215 if (a->type != b->type)
1216 return 0;
1217 return reftable_record_vtable(a)->equal(
1218 reftable_record_data(a), reftable_record_data(b), hash_size);
1219 }
1220
1221 static int hash_equal(const unsigned char *a, const unsigned char *b, int hash_size)
1222 {
1223 if (a && b)
1224 return !memcmp(a, b, hash_size);
1225
1226 return a == b;
1227 }
1228
1229 int reftable_ref_record_equal(const struct reftable_ref_record *a,
1230 const struct reftable_ref_record *b, int hash_size)
1231 {
1232 assert(hash_size > 0);
1233 if (!null_streq(a->refname, b->refname))
1234 return 0;
1235
1236 if (a->update_index != b->update_index ||
1237 a->value_type != b->value_type)
1238 return 0;
1239
1240 switch (a->value_type) {
1241 case REFTABLE_REF_SYMREF:
1242 return !strcmp(a->value.symref, b->value.symref);
1243 case REFTABLE_REF_VAL2:
1244 return hash_equal(a->value.val2.value, b->value.val2.value,
1245 hash_size) &&
1246 hash_equal(a->value.val2.target_value,
1247 b->value.val2.target_value, hash_size);
1248 case REFTABLE_REF_VAL1:
1249 return hash_equal(a->value.val1, b->value.val1, hash_size);
1250 case REFTABLE_REF_DELETION:
1251 return 1;
1252 default:
1253 abort();
1254 }
1255 }
1256
1257 int reftable_ref_record_compare_name(const void *a, const void *b)
1258 {
1259 return strcmp(((struct reftable_ref_record *)a)->refname,
1260 ((struct reftable_ref_record *)b)->refname);
1261 }
1262
1263 int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref)
1264 {
1265 return ref->value_type == REFTABLE_REF_DELETION;
1266 }
1267
1268 int reftable_log_record_compare_key(const void *a, const void *b)
1269 {
1270 const struct reftable_log_record *la = a;
1271 const struct reftable_log_record *lb = b;
1272
1273 int cmp = strcmp(la->refname, lb->refname);
1274 if (cmp)
1275 return cmp;
1276 if (la->update_index > lb->update_index)
1277 return -1;
1278 return (la->update_index < lb->update_index) ? 1 : 0;
1279 }
1280
1281 int reftable_log_record_is_deletion(const struct reftable_log_record *log)
1282 {
1283 return (log->value_type == REFTABLE_LOG_DELETION);
1284 }
1285
1286 void string_view_consume(struct string_view *s, int n)
1287 {
1288 s->buf += n;
1289 s->len -= n;
1290 }
1291
1292 static void *reftable_record_data(struct reftable_record *rec)
1293 {
1294 switch (rec->type) {
1295 case BLOCK_TYPE_REF:
1296 return &rec->u.ref;
1297 case BLOCK_TYPE_LOG:
1298 return &rec->u.log;
1299 case BLOCK_TYPE_INDEX:
1300 return &rec->u.idx;
1301 case BLOCK_TYPE_OBJ:
1302 return &rec->u.obj;
1303 }
1304 abort();
1305 }
1306
1307 static struct reftable_record_vtable *
1308 reftable_record_vtable(struct reftable_record *rec)
1309 {
1310 switch (rec->type) {
1311 case BLOCK_TYPE_REF:
1312 return &reftable_ref_record_vtable;
1313 case BLOCK_TYPE_LOG:
1314 return &reftable_log_record_vtable;
1315 case BLOCK_TYPE_INDEX:
1316 return &reftable_index_record_vtable;
1317 case BLOCK_TYPE_OBJ:
1318 return &reftable_obj_record_vtable;
1319 }
1320 abort();
1321 }
1322
1323 void reftable_record_init(struct reftable_record *rec, uint8_t typ)
1324 {
1325 memset(rec, 0, sizeof(*rec));
1326 rec->type = typ;
1327
1328 switch (typ) {
1329 case BLOCK_TYPE_REF:
1330 case BLOCK_TYPE_LOG:
1331 case BLOCK_TYPE_OBJ:
1332 return;
1333 case BLOCK_TYPE_INDEX:
1334 strbuf_init(&rec->u.idx.last_key, 0);
1335 return;
1336 default:
1337 BUG("unhandled record type");
1338 }
1339 }
1340
1341 void reftable_record_print(struct reftable_record *rec, int hash_size)
1342 {
1343 printf("'%c': ", rec->type);
1344 reftable_record_vtable(rec)->print(reftable_record_data(rec), hash_size);
1345 }