Coverage Report

Created: 2024-09-08 06:23

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