Coverage Report

Created: 2020-05-07 18:36

/proc/self/cwd/c/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
15
#include "constants.h"
16
#include "reftable.h"
17
18
int get_var_int(uint64_t *dest, struct slice in)
19
37.1k
{
20
37.1k
  int ptr = 0;
21
37.1k
  uint64_t val;
22
37.1k
23
37.1k
  if (in.len == 0) {
24
0
    return -1;
25
0
  }
26
37.1k
  val = in.buf[ptr] & 0x7f;
27
37.1k
28
38.3k
  while (in.buf[ptr] & 0x80) {
29
1.25k
    ptr++;
30
1.25k
    if (ptr > in.len) {
31
0
      return -1;
32
0
    }
33
1.25k
    val = (val + 1) << 7 | (uint64_t)(in.buf[ptr] & 0x7f);
34
1.25k
  }
35
37.1k
36
37.1k
  *dest = val;
37
37.1k
  return ptr + 1;
38
37.1k
}
39
40
int put_var_int(struct slice dest, uint64_t val)
41
7.37k
{
42
7.37k
  byte buf[10] = { 0 };
43
7.37k
  int i = 9;
44
7.37k
  buf[i] = (byte)(val & 0x7f);
45
7.37k
  i--;
46
8.23k
  while (true) {
47
8.23k
    val >>= 7;
48
8.23k
    if (!val) {
49
7.37k
      break;
50
7.37k
    }
51
860
    val--;
52
860
    buf[i] = 0x80 | (byte)(val & 0x7f);
53
860
    i--;
54
860
  }
55
7.37k
56
7.37k
  {
57
7.37k
    int n = sizeof(buf) - i - 1;
58
7.37k
    if (dest.len < n) {
59
0
      return -1;
60
0
    }
61
7.37k
    memcpy(dest.buf, &buf[i + 1], n);
62
7.37k
    return n;
63
7.37k
  }
64
7.37k
}
65
66
int is_block_type(byte typ)
67
3.25k
{
68
3.25k
  switch (typ) {
69
3.25k
  case BLOCK_TYPE_REF:
70
3.25k
  case BLOCK_TYPE_LOG:
71
3.25k
  case BLOCK_TYPE_OBJ:
72
3.25k
  case BLOCK_TYPE_INDEX:
73
3.25k
    return true;
74
0
  }
75
0
  return false;
76
0
}
77
78
static int decode_string(struct slice *dest, struct slice in)
79
6.98k
{
80
6.98k
  int start_len = in.len;
81
6.98k
  uint64_t tsize = 0;
82
6.98k
  int n = get_var_int(&tsize, in);
83
6.98k
  if (n <= 0) {
84
0
    return -1;
85
0
  }
86
6.98k
  slice_consume(&in, n);
87
6.98k
  if (in.len < tsize) {
88
0
    return -1;
89
0
  }
90
6.98k
91
6.98k
  slice_resize(dest, tsize + 1);
92
6.98k
  dest->buf[tsize] = 0;
93
6.98k
  memcpy(dest->buf, in.buf, tsize);
94
6.98k
  slice_consume(&in, tsize);
95
6.98k
96
6.98k
  return start_len - in.len;
97
6.98k
}
98
99
static int encode_string(char *str, struct slice s)
100
1.65k
{
101
1.65k
  struct slice start = s;
102
1.65k
  int l = strlen(str);
103
1.65k
  int n = put_var_int(s, l);
104
1.65k
  if (n < 0) {
105
0
    return -1;
106
0
  }
107
1.65k
  slice_consume(&s, n);
108
1.65k
  if (s.len < l) {
109
0
    return -1;
110
0
  }
111
1.65k
  memcpy(s.buf, str, l);
112
1.65k
  slice_consume(&s, l);
113
1.65k
114
1.65k
  return start.len - s.len;
115
1.65k
}
116
117
int encode_key(bool *restart, struct slice dest, struct slice prev_key,
118
         struct slice key, byte extra)
119
1.91k
{
120
1.91k
  struct slice start = dest;
121
1.91k
  int prefix_len = common_prefix_size(prev_key, key);
122
1.91k
  uint64_t suffix_len = key.len - prefix_len;
123
1.91k
  int n = put_var_int(dest, (uint64_t)prefix_len);
124
1.91k
  if (n < 0) {
125
0
    return -1;
126
0
  }
127
1.91k
  slice_consume(&dest, n);
128
1.91k
129
1.91k
  *restart = (prefix_len == 0);
130
1.91k
131
1.91k
  n = put_var_int(dest, suffix_len << 3 | (uint64_t)extra);
132
1.91k
  if (n < 0) {
133
0
    return -1;
134
0
  }
135
1.91k
  slice_consume(&dest, n);
136
1.91k
137
1.91k
  if (dest.len < suffix_len) {
138
43
    return -1;
139
43
  }
140
1.87k
  memcpy(dest.buf, key.buf + prefix_len, suffix_len);
141
1.87k
  slice_consume(&dest, suffix_len);
142
1.87k
143
1.87k
  return start.len - dest.len;
144
1.87k
}
145
146
int decode_key(struct slice *key, byte *extra, struct slice last_key,
147
         struct slice in)
148
10.7k
{
149
10.7k
  int start_len = in.len;
150
10.7k
  uint64_t prefix_len = 0;
151
10.7k
  uint64_t suffix_len = 0;
152
10.7k
  int n = get_var_int(&prefix_len, in);
153
10.7k
  if (n < 0) {
154
0
    return -1;
155
0
  }
156
10.7k
  slice_consume(&in, n);
157
10.7k
158
10.7k
  if (prefix_len > last_key.len) {
159
0
    return -1;
160
0
  }
161
10.7k
162
10.7k
  n = get_var_int(&suffix_len, in);
163
10.7k
  if (n <= 0) {
164
0
    return -1;
165
0
  }
166
10.7k
  slice_consume(&in, n);
167
10.7k
168
10.7k
  *extra = (byte)(suffix_len & 0x7);
169
10.7k
  suffix_len >>= 3;
170
10.7k
171
10.7k
  if (in.len < suffix_len) {
172
0
    return -1;
173
0
  }
174
10.7k
175
10.7k
  slice_resize(key, suffix_len + prefix_len);
176
10.7k
  memcpy(key->buf, last_key.buf, prefix_len);
177
10.7k
178
10.7k
  memcpy(key->buf + prefix_len, in.buf, suffix_len);
179
10.7k
  slice_consume(&in, suffix_len);
180
10.7k
181
10.7k
  return start_len - in.len;
182
10.7k
}
183
184
static void reftable_ref_record_key(const void *r, struct slice *dest)
185
16.3k
{
186
16.3k
  const struct reftable_ref_record *rec =
187
16.3k
    (const struct reftable_ref_record *)r;
188
16.3k
  slice_set_string(dest, rec->ref_name);
189
16.3k
}
190
191
static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
192
            int hash_size)
193
554
{
194
554
  struct reftable_ref_record *ref = (struct reftable_ref_record *)rec;
195
554
  struct reftable_ref_record *src = (struct reftable_ref_record *)src_rec;
196
554
  assert(hash_size > 0);
197
554
198
554
  /* This is simple and correct, but we could probably reuse the hash
199
554
     fields. */
200
554
  reftable_ref_record_clear(ref);
201
554
  if (src->ref_name != NULL) {
202
554
    ref->ref_name = xstrdup(src->ref_name);
203
554
  }
204
554
205
554
  if (src->target != NULL) {
206
536
    ref->target = xstrdup(src->target);
207
536
  }
208
554
209
554
  if (src->target_value != NULL) {
210
2
    ref->target_value = reftable_malloc(hash_size);
211
2
    memcpy(ref->target_value, src->target_value, hash_size);
212
2
  }
213
554
214
554
  if (src->value != NULL) {
215
12
    ref->value = reftable_malloc(hash_size);
216
12
    memcpy(ref->value, src->value, hash_size);
217
12
  }
218
554
  ref->update_index = src->update_index;
219
554
}
220
221
static char hexdigit(int c)
222
0
{
223
0
  if (c <= 9) {
224
0
    return '0' + c;
225
0
  }
226
0
  return 'a' + (c - 10);
227
0
}
228
229
static void hex_format(char *dest, byte *src, int hash_size)
230
0
{
231
0
  assert(hash_size > 0);
232
0
  if (src != NULL) {
233
0
    int i = 0;
234
0
    for (i = 0; i < hash_size; i++) {
235
0
      dest[2 * i] = hexdigit(src[i] >> 4);
236
0
      dest[2 * i + 1] = hexdigit(src[i] & 0xf);
237
0
    }
238
0
    dest[2 * hash_size] = 0;
239
0
  }
240
0
}
241
242
void reftable_ref_record_print(struct reftable_ref_record *ref,
243
             uint32_t hash_id)
244
0
{
245
0
  char hex[SHA256_SIZE + 1] = { 0 };
246
0
  printf("ref{%s(%" PRIu64 ") ", ref->ref_name, ref->update_index);
247
0
  if (ref->value != NULL) {
248
0
    hex_format(hex, ref->value, hash_size(hash_id));
249
0
    printf("%s", hex);
250
0
  }
251
0
  if (ref->target_value != NULL) {
252
0
    hex_format(hex, ref->target_value, hash_size(hash_id));
253
0
    printf(" (T %s)", hex);
254
0
  }
255
0
  if (ref->target != NULL) {
256
0
    printf("=> %s", ref->target);
257
0
  }
258
0
  printf("}\n");
259
0
}
260
261
static void reftable_ref_record_clear_void(void *rec)
262
3.46k
{
263
3.46k
  reftable_ref_record_clear((struct reftable_ref_record *)rec);
264
3.46k
}
265
266
void reftable_ref_record_clear(struct reftable_ref_record *ref)
267
4.76k
{
268
4.76k
  reftable_free(ref->ref_name);
269
4.76k
  reftable_free(ref->target);
270
4.76k
  reftable_free(ref->target_value);
271
4.76k
  reftable_free(ref->value);
272
4.76k
  memset(ref, 0, sizeof(struct reftable_ref_record));
273
4.76k
}
274
275
static byte reftable_ref_record_val_type(const void *rec)
276
1.00k
{
277
1.00k
  const struct reftable_ref_record *r =
278
1.00k
    (const struct reftable_ref_record *)rec;
279
1.00k
  if (r->value != NULL) {
280
454
    if (r->target_value != NULL) {
281
133
      return 2;
282
321
    } else {
283
321
      return 1;
284
321
    }
285
547
  } else if (r->target != NULL) {
286
539
    return 3;
287
539
  }
288
8
  return 0;
289
8
}
290
291
static int reftable_ref_record_encode(const void *rec, struct slice s,
292
              int hash_size)
293
970
{
294
970
  const struct reftable_ref_record *r =
295
970
    (const struct reftable_ref_record *)rec;
296
970
  struct slice start = s;
297
970
  int n = put_var_int(s, r->update_index);
298
970
  assert(hash_size > 0);
299
970
  if (n < 0) {
300
0
    return -1;
301
0
  }
302
970
  slice_consume(&s, n);
303
970
304
970
  if (r->value != NULL) {
305
424
    if (s.len < hash_size) {
306
28
      return -1;
307
28
    }
308
396
    memcpy(s.buf, r->value, hash_size);
309
396
    slice_consume(&s, hash_size);
310
396
  }
311
970
312
970
  if (r->target_value != NULL) {
313
103
    if (s.len < hash_size) {
314
2
      return -1;
315
2
    }
316
101
    memcpy(s.buf, r->target_value, hash_size);
317
101
    slice_consume(&s, hash_size);
318
101
  }
319
942
320
942
  if (r->target != NULL) {
321
539
    int n = encode_string(r->target, s);
322
539
    if (n < 0) {
323
0
      return -1;
324
0
    }
325
539
    slice_consume(&s, n);
326
539
  }
327
940
328
940
  return start.len - s.len;
329
940
}
330
331
static int reftable_ref_record_decode(void *rec, struct slice key,
332
              byte val_type, struct slice in,
333
              int hash_size)
334
8.29k
{
335
8.29k
  struct reftable_ref_record *r = (struct reftable_ref_record *)rec;
336
8.29k
  struct slice start = in;
337
8.29k
  bool seen_value = false;
338
8.29k
  bool seen_target_value = false;
339
8.29k
  bool seen_target = false;
340
8.29k
341
8.29k
  int n = get_var_int(&r->update_index, in);
342
8.29k
  if (n < 0) {
343
0
    return n;
344
0
  }
345
8.29k
  assert(hash_size > 0);
346
8.29k
347
8.29k
  slice_consume(&in, n);
348
8.29k
349
8.29k
  r->ref_name = reftable_realloc(r->ref_name, key.len + 1);
350
8.29k
  memcpy(r->ref_name, key.buf, key.len);
351
8.29k
  r->ref_name[key.len] = 0;
352
8.29k
353
8.29k
  switch (val_type) {
354
8.29k
  case 1:
355
1.81k
  case 2:
356
1.81k
    if (in.len < hash_size) {
357
0
      return -1;
358
0
    }
359
1.81k
360
1.81k
    if (r->value == NULL) {
361
460
      r->value = reftable_malloc(hash_size);
362
460
    }
363
1.81k
    seen_value = true;
364
1.81k
    memcpy(r->value, in.buf, hash_size);
365
1.81k
    slice_consume(&in, hash_size);
366
1.81k
    if (val_type == 1) {
367
1.74k
      break;
368
1.74k
    }
369
65
    if (r->target_value == NULL) {
370
19
      r->target_value = reftable_malloc(hash_size);
371
19
    }
372
65
    seen_target_value = true;
373
65
    memcpy(r->target_value, in.buf, hash_size);
374
65
    slice_consume(&in, hash_size);
375
65
    break;
376
6.47k
  case 3: {
377
6.47k
    struct slice dest = { 0 };
378
6.47k
    int n = decode_string(&dest, in);
379
6.47k
    if (n < 0) {
380
0
      return -1;
381
0
    }
382
6.47k
    slice_consume(&in, n);
383
6.47k
    seen_target = true;
384
6.47k
    if (r->target != NULL) {
385
4.65k
      reftable_free(r->target);
386
4.65k
    }
387
6.47k
    r->target = (char *)slice_as_string(&dest);
388
6.47k
  } break;
389
6.47k
390
6.47k
  case 0:
391
13
    break;
392
6.47k
  default:
393
0
    abort();
394
6.47k
    break;
395
8.29k
  }
396
8.29k
397
8.29k
  if (!seen_target && r->target != NULL) {
398
3
    FREE_AND_NULL(r->target);
399
3
  }
400
8.29k
  if (!seen_target_value && r->target_value != NULL) {
401
3
    FREE_AND_NULL(r->target_value);
402
3
  }
403
8.29k
  if (!seen_value && r->value != NULL) {
404
2
    FREE_AND_NULL(r->value);
405
2
  }
406
8.29k
407
8.29k
  return start.len - in.len;
408
8.29k
}
409
410
static bool reftable_ref_record_is_deletion_void(const void *p)
411
108
{
412
108
  return reftable_ref_record_is_deletion(
413
108
    (const struct reftable_ref_record *)p);
414
108
}
415
416
struct record_vtable reftable_ref_record_vtable = {
417
  .key = &reftable_ref_record_key,
418
  .type = BLOCK_TYPE_REF,
419
  .copy_from = &reftable_ref_record_copy_from,
420
  .val_type = &reftable_ref_record_val_type,
421
  .encode = &reftable_ref_record_encode,
422
  .decode = &reftable_ref_record_decode,
423
  .clear = &reftable_ref_record_clear_void,
424
  .is_deletion = &reftable_ref_record_is_deletion_void,
425
};
426
427
static void obj_record_key(const void *r, struct slice *dest)
428
292
{
429
292
  const struct obj_record *rec = (const struct obj_record *)r;
430
292
  slice_resize(dest, rec->hash_prefix_len);
431
292
  memcpy(dest->buf, rec->hash_prefix, rec->hash_prefix_len);
432
292
}
433
434
static void obj_record_clear(void *rec)
435
15
{
436
15
  struct obj_record *obj = (struct obj_record *)rec;
437
15
  FREE_AND_NULL(obj->hash_prefix);
438
15
  FREE_AND_NULL(obj->offsets);
439
15
  memset(obj, 0, sizeof(struct obj_record));
440
15
}
441
442
static void obj_record_copy_from(void *rec, const void *src_rec, int hash_size)
443
6
{
444
6
  struct obj_record *obj = (struct obj_record *)rec;
445
6
  const struct obj_record *src = (const struct obj_record *)src_rec;
446
6
447
6
  obj_record_clear(obj);
448
6
  *obj = *src;
449
6
  obj->hash_prefix = reftable_malloc(obj->hash_prefix_len);
450
6
  memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
451
6
452
6
  {
453
6
    int olen = obj->offset_len * sizeof(uint64_t);
454
6
    obj->offsets = reftable_malloc(olen);
455
6
    memcpy(obj->offsets, src->offsets, olen);
456
6
  }
457
6
}
458
459
static byte obj_record_val_type(const void *rec)
460
290
{
461
290
  struct obj_record *r = (struct obj_record *)rec;
462
290
  if (r->offset_len > 0 && r->offset_len < 8) {
463
288
    return r->offset_len;
464
288
  }
465
2
  return 0;
466
2
}
467
468
static int obj_record_encode(const void *rec, struct slice s, int hash_size)
469
290
{
470
290
  struct obj_record *r = (struct obj_record *)rec;
471
290
  struct slice start = s;
472
290
  int n = 0;
473
290
  if (r->offset_len == 0 || r->offset_len >= 8) {
474
2
    n = put_var_int(s, r->offset_len);
475
2
    if (n < 0) {
476
0
      return -1;
477
0
    }
478
2
    slice_consume(&s, n);
479
2
  }
480
290
  if (r->offset_len == 0) {
481
1
    return start.len - s.len;
482
1
  }
483
289
  n = put_var_int(s, r->offsets[0]);
484
289
  if (n < 0) {
485
0
    return -1;
486
0
  }
487
289
  slice_consume(&s, n);
488
289
489
289
  {
490
289
    uint64_t last = r->offsets[0];
491
289
    int i = 0;
492
367
    for (i = 1; i < r->offset_len; i++) {
493
78
      int n = put_var_int(s, r->offsets[i] - last);
494
78
      if (n < 0) {
495
0
        return -1;
496
0
      }
497
78
      slice_consume(&s, n);
498
78
      last = r->offsets[i];
499
78
    }
500
289
  }
501
289
  return start.len - s.len;
502
289
}
503
504
static int obj_record_decode(void *rec, struct slice key, byte val_type,
505
           struct slice in, int hash_size)
506
5
{
507
5
  struct slice start = in;
508
5
  struct obj_record *r = (struct obj_record *)rec;
509
5
  uint64_t count = val_type;
510
5
  int n = 0;
511
5
  r->hash_prefix = reftable_malloc(key.len);
512
5
  memcpy(r->hash_prefix, key.buf, key.len);
513
5
  r->hash_prefix_len = key.len;
514
5
515
5
  if (val_type == 0) {
516
2
    n = get_var_int(&count, in);
517
2
    if (n < 0) {
518
0
      return n;
519
0
    }
520
2
521
2
    slice_consume(&in, n);
522
2
  }
523
5
524
5
  r->offsets = NULL;
525
5
  r->offset_len = 0;
526
5
  if (count == 0) {
527
1
    return start.len - in.len;
528
1
  }
529
4
530
4
  r->offsets = reftable_malloc(count * sizeof(uint64_t));
531
4
  r->offset_len = count;
532
4
533
4
  n = get_var_int(&r->offsets[0], in);
534
4
  if (n < 0) {
535
0
    return n;
536
0
  }
537
4
  slice_consume(&in, n);
538
4
539
4
  {
540
4
    uint64_t last = r->offsets[0];
541
4
    int j = 1;
542
20
    while (j < count) {
543
16
      uint64_t delta = 0;
544
16
      int n = get_var_int(&delta, in);
545
16
      if (n < 0) {
546
0
        return n;
547
0
      }
548
16
      slice_consume(&in, n);
549
16
550
16
      last = r->offsets[j] = (delta + last);
551
16
      j++;
552
16
    }
553
4
  }
554
4
  return start.len - in.len;
555
4
}
556
557
static bool not_a_deletion(const void *p)
558
0
{
559
0
  return false;
560
0
}
561
562
struct record_vtable obj_record_vtable = {
563
  .key = &obj_record_key,
564
  .type = BLOCK_TYPE_OBJ,
565
  .copy_from = &obj_record_copy_from,
566
  .val_type = &obj_record_val_type,
567
  .encode = &obj_record_encode,
568
  .decode = &obj_record_decode,
569
  .clear = &obj_record_clear,
570
  .is_deletion = not_a_deletion,
571
};
572
573
void reftable_log_record_print(struct reftable_log_record *log,
574
             uint32_t hash_id)
575
0
{
576
0
  char hex[SHA256_SIZE + 1] = { 0 };
577
0
578
0
  printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n", log->ref_name,
579
0
         log->update_index, log->name, log->email, log->time,
580
0
         log->tz_offset);
581
0
  hex_format(hex, log->old_hash, hash_size(hash_id));
582
0
  printf("%s => ", hex);
583
0
  hex_format(hex, log->new_hash, hash_size(hash_id));
584
0
  printf("%s\n\n%s\n}\n", hex, log->message);
585
0
}
586
587
static void reftable_log_record_key(const void *r, struct slice *dest)
588
1.49k
{
589
1.49k
  const struct reftable_log_record *rec =
590
1.49k
    (const struct reftable_log_record *)r;
591
1.49k
  int len = strlen(rec->ref_name);
592
1.49k
  uint64_t ts = 0;
593
1.49k
  slice_resize(dest, len + 9);
594
1.49k
  memcpy(dest->buf, rec->ref_name, len + 1);
595
1.49k
  ts = (~ts) - rec->update_index;
596
1.49k
  put_be64(dest->buf + 1 + len, ts);
597
1.49k
}
598
599
static void reftable_log_record_copy_from(void *rec, const void *src_rec,
600
            int hash_size)
601
122
{
602
122
  struct reftable_log_record *dst = (struct reftable_log_record *)rec;
603
122
  const struct reftable_log_record *src =
604
122
    (const struct reftable_log_record *)src_rec;
605
122
606
122
  reftable_log_record_clear(dst);
607
122
  *dst = *src;
608
122
  if (dst->ref_name != NULL) {
609
122
    dst->ref_name = xstrdup(dst->ref_name);
610
122
  }
611
122
  if (dst->email != NULL) {
612
118
    dst->email = xstrdup(dst->email);
613
118
  }
614
122
  if (dst->name != NULL) {
615
118
    dst->name = xstrdup(dst->name);
616
118
  }
617
122
  if (dst->message != NULL) {
618
118
    dst->message = xstrdup(dst->message);
619
118
  }
620
122
621
122
  if (dst->new_hash != NULL) {
622
118
    dst->new_hash = reftable_malloc(hash_size);
623
118
    memcpy(dst->new_hash, src->new_hash, hash_size);
624
118
  }
625
122
  if (dst->old_hash != NULL) {
626
118
    dst->old_hash = reftable_malloc(hash_size);
627
118
    memcpy(dst->old_hash, src->old_hash, hash_size);
628
118
  }
629
122
}
630
631
static void reftable_log_record_clear_void(void *rec)
632
407
{
633
407
  struct reftable_log_record *r = (struct reftable_log_record *)rec;
634
407
  reftable_log_record_clear(r);
635
407
}
636
637
void reftable_log_record_clear(struct reftable_log_record *r)
638
632
{
639
632
  reftable_free(r->ref_name);
640
632
  reftable_free(r->new_hash);
641
632
  reftable_free(r->old_hash);
642
632
  reftable_free(r->name);
643
632
  reftable_free(r->email);
644
632
  reftable_free(r->message);
645
632
  memset(r, 0, sizeof(struct reftable_log_record));
646
632
}
647
648
static byte reftable_log_record_val_type(const void *rec)
649
464
{
650
464
  const struct reftable_log_record *log =
651
464
    (const struct reftable_log_record *)rec;
652
464
653
464
  return reftable_log_record_is_deletion(log) ? 0 : 1;
654
464
}
655
656
static byte zero[SHA256_SIZE] = { 0 };
657
658
static int reftable_log_record_encode(const void *rec, struct slice s,
659
              int hash_size)
660
463
{
661
463
  struct reftable_log_record *r = (struct reftable_log_record *)rec;
662
463
  struct slice start = s;
663
463
  int n = 0;
664
463
  byte *oldh = r->old_hash;
665
463
  byte *newh = r->new_hash;
666
463
  if (reftable_log_record_is_deletion(r)) {
667
2
    return 0;
668
2
  }
669
461
670
461
  if (oldh == NULL) {
671
361
    oldh = zero;
672
361
  }
673
461
  if (newh == NULL) {
674
0
    newh = zero;
675
0
  }
676
461
677
461
  if (s.len < 2 * hash_size) {
678
88
    return -1;
679
88
  }
680
373
681
373
  memcpy(s.buf, oldh, hash_size);
682
373
  memcpy(s.buf + hash_size, newh, hash_size);
683
373
  slice_consume(&s, 2 * hash_size);
684
373
685
373
  n = encode_string(r->name ? r->name : "", s);
686
373
  if (n < 0) {
687
0
    return -1;
688
0
  }
689
373
  slice_consume(&s, n);
690
373
691
373
  n = encode_string(r->email ? r->email : "", s);
692
373
  if (n < 0) {
693
0
    return -1;
694
0
  }
695
373
  slice_consume(&s, n);
696
373
697
373
  n = put_var_int(s, r->time);
698
373
  if (n < 0) {
699
0
    return -1;
700
0
  }
701
373
  slice_consume(&s, n);
702
373
703
373
  if (s.len < 2) {
704
0
    return -1;
705
0
  }
706
373
707
373
  put_be16(s.buf, r->tz_offset);
708
373
  slice_consume(&s, 2);
709
373
710
373
  n = encode_string(r->message ? r->message : "", s);
711
373
  if (n < 0) {
712
0
    return -1;
713
0
  }
714
373
  slice_consume(&s, n);
715
373
716
373
  return start.len - s.len;
717
373
}
718
719
static int reftable_log_record_decode(void *rec, struct slice key,
720
              byte val_type, struct slice in,
721
              int hash_size)
722
175
{
723
175
  struct slice start = in;
724
175
  struct reftable_log_record *r = (struct reftable_log_record *)rec;
725
175
  uint64_t max = 0;
726
175
  uint64_t ts = 0;
727
175
  struct slice dest = { 0 };
728
175
  int n;
729
175
730
175
  if (key.len <= 9 || key.buf[key.len - 9] != 0) {
731
0
    return REFTABLE_FORMAT_ERROR;
732
0
  }
733
175
734
175
  r->ref_name = reftable_realloc(r->ref_name, key.len - 8);
735
175
  memcpy(r->ref_name, key.buf, key.len - 8);
736
175
  ts = get_be64(key.buf + key.len - 8);
737
175
738
175
  r->update_index = (~max) - ts;
739
175
740
175
  if (val_type == 0) {
741
5
    FREE_AND_NULL(r->old_hash);
742
5
    FREE_AND_NULL(r->new_hash);
743
5
    FREE_AND_NULL(r->message);
744
5
    FREE_AND_NULL(r->email);
745
5
    FREE_AND_NULL(r->name);
746
5
    return 0;
747
5
  }
748
170
749
170
  if (in.len < 2 * hash_size) {
750
0
    return REFTABLE_FORMAT_ERROR;
751
0
  }
752
170
753
170
  r->old_hash = reftable_realloc(r->old_hash, hash_size);
754
170
  r->new_hash = reftable_realloc(r->new_hash, hash_size);
755
170
756
170
  memcpy(r->old_hash, in.buf, hash_size);
757
170
  memcpy(r->new_hash, in.buf + hash_size, hash_size);
758
170
759
170
  slice_consume(&in, 2 * hash_size);
760
170
761
170
  n = decode_string(&dest, in);
762
170
  if (n < 0) {
763
0
    goto error;
764
0
  }
765
170
  slice_consume(&in, n);
766
170
767
170
  r->name = reftable_realloc(r->name, dest.len + 1);
768
170
  memcpy(r->name, dest.buf, dest.len);
769
170
  r->name[dest.len] = 0;
770
170
771
170
  slice_resize(&dest, 0);
772
170
  n = decode_string(&dest, in);
773
170
  if (n < 0) {
774
0
    goto error;
775
0
  }
776
170
  slice_consume(&in, n);
777
170
778
170
  r->email = reftable_realloc(r->email, dest.len + 1);
779
170
  memcpy(r->email, dest.buf, dest.len);
780
170
  r->email[dest.len] = 0;
781
170
782
170
  ts = 0;
783
170
  n = get_var_int(&ts, in);
784
170
  if (n < 0) {
785
0
    goto error;
786
0
  }
787
170
  slice_consume(&in, n);
788
170
  r->time = ts;
789
170
  if (in.len < 2) {
790
0
    goto error;
791
0
  }
792
170
793
170
  r->tz_offset = get_be16(in.buf);
794
170
  slice_consume(&in, 2);
795
170
796
170
  slice_resize(&dest, 0);
797
170
  n = decode_string(&dest, in);
798
170
  if (n < 0) {
799
0
    goto error;
800
0
  }
801
170
  slice_consume(&in, n);
802
170
803
170
  r->message = reftable_realloc(r->message, dest.len + 1);
804
170
  memcpy(r->message, dest.buf, dest.len);
805
170
  r->message[dest.len] = 0;
806
170
807
170
  slice_clear(&dest);
808
170
  return start.len - in.len;
809
0
810
0
error:
811
0
  slice_clear(&dest);
812
0
  return REFTABLE_FORMAT_ERROR;
813
170
}
814
815
static bool null_streq(char *a, char *b)
816
24
{
817
24
  char *empty = "";
818
24
  if (a == NULL) {
819
12
    a = empty;
820
12
  }
821
24
  if (b == NULL) {
822
16
    b = empty;
823
16
  }
824
24
  return 0 == strcmp(a, b);
825
24
}
826
827
static bool zero_hash_eq(byte *a, byte *b, int sz)
828
16
{
829
16
  if (a == NULL) {
830
8
    a = zero;
831
8
  }
832
16
  if (b == NULL) {
833
10
    b = zero;
834
10
  }
835
16
  return !memcmp(a, b, sz);
836
16
}
837
838
bool reftable_log_record_equal(struct reftable_log_record *a,
839
             struct reftable_log_record *b, int hash_size)
840
8
{
841
8
  return null_streq(a->name, b->name) && null_streq(a->email, b->email) &&
842
8
         null_streq(a->message, b->message) &&
843
8
         zero_hash_eq(a->old_hash, b->old_hash, hash_size) &&
844
8
         zero_hash_eq(a->new_hash, b->new_hash, hash_size) &&
845
8
         a->time == b->time && a->tz_offset == b->tz_offset &&
846
8
         a->update_index == b->update_index;
847
8
}
848
849
static bool reftable_log_record_is_deletion_void(const void *p)
850
7
{
851
7
  return reftable_log_record_is_deletion(
852
7
    (const struct reftable_log_record *)p);
853
7
}
854
855
struct record_vtable reftable_log_record_vtable = {
856
  .key = &reftable_log_record_key,
857
  .type = BLOCK_TYPE_LOG,
858
  .copy_from = &reftable_log_record_copy_from,
859
  .val_type = &reftable_log_record_val_type,
860
  .encode = &reftable_log_record_encode,
861
  .decode = &reftable_log_record_decode,
862
  .clear = &reftable_log_record_clear_void,
863
  .is_deletion = &reftable_log_record_is_deletion_void,
864
};
865
866
struct record new_record(byte typ)
867
4.00k
{
868
4.00k
  struct record rec = { NULL };
869
4.00k
  switch (typ) {
870
4.00k
  case BLOCK_TYPE_REF: {
871
3.48k
    struct reftable_ref_record *r =
872
3.48k
      reftable_calloc(sizeof(struct reftable_ref_record));
873
3.48k
    record_from_ref(&rec, r);
874
3.48k
    return rec;
875
4.00k
  }
876
4.00k
877
4.00k
  case BLOCK_TYPE_OBJ: {
878
5
    struct obj_record *r =
879
5
      reftable_calloc(sizeof(struct obj_record));
880
5
    record_from_obj(&rec, r);
881
5
    return rec;
882
4.00k
  }
883
4.00k
  case BLOCK_TYPE_LOG: {
884
405
    struct reftable_log_record *r =
885
405
      reftable_calloc(sizeof(struct reftable_log_record));
886
405
    record_from_log(&rec, r);
887
405
    return rec;
888
4.00k
  }
889
4.00k
  case BLOCK_TYPE_INDEX: {
890
109
    struct index_record *r =
891
109
      reftable_calloc(sizeof(struct index_record));
892
109
    record_from_index(&rec, r);
893
109
    return rec;
894
0
  }
895
0
  }
896
0
  abort();
897
0
  return rec;
898
0
}
899
900
void *record_yield(struct record *rec)
901
3.97k
{
902
3.97k
  void *p = rec->data;
903
3.97k
  rec->data = NULL;
904
3.97k
  return p;
905
3.97k
}
906
907
void record_destroy(struct record *rec)
908
3.97k
{
909
3.97k
  record_clear(*rec);
910
3.97k
  reftable_free(record_yield(rec));
911
3.97k
}
912
913
static void index_record_key(const void *r, struct slice *dest)
914
406
{
915
406
  struct index_record *rec = (struct index_record *)r;
916
406
  slice_copy(dest, rec->last_key);
917
406
}
918
919
static void index_record_copy_from(void *rec, const void *src_rec,
920
           int hash_size)
921
2
{
922
2
  struct index_record *dst = (struct index_record *)rec;
923
2
  struct index_record *src = (struct index_record *)src_rec;
924
2
925
2
  slice_copy(&dst->last_key, src->last_key);
926
2
  dst->offset = src->offset;
927
2
}
928
929
static void index_record_clear(void *rec)
930
218
{
931
218
  struct index_record *idx = (struct index_record *)rec;
932
218
  slice_clear(&idx->last_key);
933
218
}
934
935
static byte index_record_val_type(const void *rec)
936
172
{
937
172
  return 0;
938
172
}
939
940
static int index_record_encode(const void *rec, struct slice out, int hash_size)
941
161
{
942
161
  const struct index_record *r = (const struct index_record *)rec;
943
161
  struct slice start = out;
944
161
945
161
  int n = put_var_int(out, r->offset);
946
161
  if (n < 0) {
947
0
    return n;
948
0
  }
949
161
950
161
  slice_consume(&out, n);
951
161
952
161
  return start.len - out.len;
953
161
}
954
955
static int index_record_decode(void *rec, struct slice key, byte val_type,
956
             struct slice in, int hash_size)
957
233
{
958
233
  struct slice start = in;
959
233
  struct index_record *r = (struct index_record *)rec;
960
233
  int n = 0;
961
233
962
233
  slice_copy(&r->last_key, key);
963
233
964
233
  n = get_var_int(&r->offset, in);
965
233
  if (n < 0) {
966
0
    return n;
967
0
  }
968
233
969
233
  slice_consume(&in, n);
970
233
  return start.len - in.len;
971
233
}
972
973
struct record_vtable index_record_vtable = {
974
  .key = &index_record_key,
975
  .type = BLOCK_TYPE_INDEX,
976
  .copy_from = &index_record_copy_from,
977
  .val_type = &index_record_val_type,
978
  .encode = &index_record_encode,
979
  .decode = &index_record_decode,
980
  .clear = &index_record_clear,
981
  .is_deletion = &not_a_deletion,
982
};
983
984
void record_key(struct record rec, struct slice *dest)
985
18.5k
{
986
18.5k
  rec.ops->key(rec.data, dest);
987
18.5k
}
988
989
byte record_type(struct record rec)
990
9.97k
{
991
9.97k
  return rec.ops->type;
992
9.97k
}
993
994
int record_encode(struct record rec, struct slice dest, int hash_size)
995
1.88k
{
996
1.88k
  return rec.ops->encode(rec.data, dest, hash_size);
997
1.88k
}
998
999
void record_copy_from(struct record rec, struct record src, int hash_size)
1000
684
{
1001
684
  assert(src.ops->type == rec.ops->type);
1002
684
1003
684
  rec.ops->copy_from(rec.data, src.data, hash_size);
1004
684
}
1005
1006
byte record_val_type(struct record rec)
1007
1.92k
{
1008
1.92k
  return rec.ops->val_type(rec.data);
1009
1.92k
}
1010
1011
int record_decode(struct record rec, struct slice key, byte extra,
1012
      struct slice src, int hash_size)
1013
8.71k
{
1014
8.71k
  return rec.ops->decode(rec.data, key, extra, src, hash_size);
1015
8.71k
}
1016
1017
void record_clear(struct record rec)
1018
4.10k
{
1019
4.10k
  rec.ops->clear(rec.data);
1020
4.10k
}
1021
1022
bool record_is_deletion(struct record rec)
1023
115
{
1024
115
  return rec.ops->is_deletion(rec.data);
1025
115
}
1026
1027
void record_from_ref(struct record *rec, struct reftable_ref_record *ref_rec)
1028
6.25k
{
1029
6.25k
  assert(rec->ops == NULL);
1030
6.25k
  rec->data = ref_rec;
1031
6.25k
  rec->ops = &reftable_ref_record_vtable;
1032
6.25k
}
1033
1034
void record_from_obj(struct record *rec, struct obj_record *obj_rec)
1035
295
{
1036
295
  assert(rec->ops == NULL);
1037
295
  rec->data = obj_rec;
1038
295
  rec->ops = &obj_record_vtable;
1039
295
}
1040
1041
void record_from_index(struct record *rec, struct index_record *index_rec)
1042
379
{
1043
379
  assert(rec->ops == NULL);
1044
379
  rec->data = index_rec;
1045
379
  rec->ops = &index_record_vtable;
1046
379
}
1047
1048
void record_from_log(struct record *rec, struct reftable_log_record *log_rec)
1049
1.04k
{
1050
1.04k
  assert(rec->ops == NULL);
1051
1.04k
  rec->data = log_rec;
1052
1.04k
  rec->ops = &reftable_log_record_vtable;
1053
1.04k
}
1054
1055
struct reftable_ref_record *record_as_ref(struct record rec)
1056
60
{
1057
60
  assert(record_type(rec) == BLOCK_TYPE_REF);
1058
60
  return (struct reftable_ref_record *)rec.data;
1059
60
}
1060
1061
struct reftable_log_record *record_as_log(struct record rec)
1062
4
{
1063
4
  assert(record_type(rec) == BLOCK_TYPE_LOG);
1064
4
  return (struct reftable_log_record *)rec.data;
1065
4
}
1066
1067
static bool hash_equal(byte *a, byte *b, int hash_size)
1068
20
{
1069
20
  if (a != NULL && b != NULL) {
1070
8
    return !memcmp(a, b, hash_size);
1071
8
  }
1072
12
1073
12
  return a == b;
1074
12
}
1075
1076
static bool str_equal(char *a, char *b)
1077
10
{
1078
10
  if (a != NULL && b != NULL) {
1079
1
    return 0 == strcmp(a, b);
1080
1
  }
1081
9
1082
9
  return a == b;
1083
9
}
1084
1085
bool reftable_ref_record_equal(struct reftable_ref_record *a,
1086
             struct reftable_ref_record *b, int hash_size)
1087
10
{
1088
10
  assert(hash_size > 0);
1089
10
  return 0 == strcmp(a->ref_name, b->ref_name) &&
1090
10
         a->update_index == b->update_index &&
1091
10
         hash_equal(a->value, b->value, hash_size) &&
1092
10
         hash_equal(a->target_value, b->target_value, hash_size) &&
1093
10
         str_equal(a->target, b->target);
1094
10
}
1095
1096
int reftable_ref_record_compare_name(const void *a, const void *b)
1097
0
{
1098
0
  return strcmp(((struct reftable_ref_record *)a)->ref_name,
1099
0
          ((struct reftable_ref_record *)b)->ref_name);
1100
0
}
1101
1102
bool reftable_ref_record_is_deletion(const struct reftable_ref_record *ref)
1103
450
{
1104
450
  return ref->value == NULL && ref->target == NULL &&
1105
450
         ref->target_value == NULL;
1106
450
}
1107
1108
int reftable_log_record_compare_key(const void *a, const void *b)
1109
0
{
1110
0
  struct reftable_log_record *la = (struct reftable_log_record *)a;
1111
0
  struct reftable_log_record *lb = (struct reftable_log_record *)b;
1112
0
1113
0
  int cmp = strcmp(la->ref_name, lb->ref_name);
1114
0
  if (cmp) {
1115
0
    return cmp;
1116
0
  }
1117
0
  if (la->update_index > lb->update_index) {
1118
0
    return -1;
1119
0
  }
1120
0
  return (la->update_index < lb->update_index) ? 1 : 0;
1121
0
}
1122
1123
bool reftable_log_record_is_deletion(const struct reftable_log_record *log)
1124
1.04k
{
1125
1.04k
  return (log->new_hash == NULL && log->old_hash == NULL &&
1126
1.04k
    log->name == NULL && log->email == NULL &&
1127
1.04k
    log->message == NULL && log->time == 0 && log->tz_offset == 0 &&
1128
1.04k
    log->message == NULL);
1129
1.04k
}
1130
1131
int hash_size(uint32_t id)
1132
3.99k
{
1133
3.99k
  switch (id) {
1134
3.99k
  case 0:
1135
3.60k
  case SHA1_ID:
1136
3.60k
    return SHA1_SIZE;
1137
3.60k
  case SHA256_ID:
1138
385
    return SHA256_SIZE;
1139
0
  }
1140
0
  abort();
1141
0
}