| 518 | } |
| 519 | |
| 520 | int reftable_table_new(struct reftable_table **out, |
| 521 | struct reftable_block_source *source, char const *name) |
| 522 | { |
| 523 | struct reftable_block_data footer = { 0 }; |
| 524 | struct reftable_block_data header = { 0 }; |
| 525 | struct reftable_table *t; |
| 526 | uint64_t file_size = block_source_size(source); |
| 527 | uint32_t read_size; |
| 528 | ssize_t bytes_read; |
| 529 | int err; |
| 530 | |
| 531 | REFTABLE_CALLOC_ARRAY(t, 1); |
| 532 | if (!t) { |
| 533 | err = REFTABLE_OUT_OF_MEMORY_ERROR; |
| 534 | goto done; |
| 535 | } |
| 536 | |
| 537 | /* |
| 538 | * We need one extra byte to read the type of first block. We also |
| 539 | * pretend to always be reading v2 of the format because it is larger. |
| 540 | */ |
| 541 | read_size = header_size(2) + 1; |
| 542 | if (read_size > file_size) { |
| 543 | err = REFTABLE_FORMAT_ERROR; |
| 544 | goto done; |
| 545 | } |
| 546 | |
| 547 | bytes_read = block_source_read_data(source, &header, 0, read_size); |
| 548 | if (bytes_read < 0 || (size_t)bytes_read != read_size) { |
| 549 | err = REFTABLE_IO_ERROR; |
| 550 | goto done; |
| 551 | } |
| 552 | |
| 553 | if (memcmp(header.data, "REFT", 4)) { |
| 554 | err = REFTABLE_FORMAT_ERROR; |
| 555 | goto done; |
| 556 | } |
| 557 | t->version = header.data[4]; |
| 558 | if (t->version != 1 && t->version != 2) { |
| 559 | err = REFTABLE_FORMAT_ERROR; |
| 560 | goto done; |
| 561 | } |
| 562 | |
| 563 | t->size = file_size - footer_size(t->version); |
| 564 | t->source = *source; |
| 565 | t->name = reftable_strdup(name); |
| 566 | if (!t->name) { |
| 567 | err = REFTABLE_OUT_OF_MEMORY_ERROR; |
| 568 | goto done; |
| 569 | } |
| 570 | t->hash_id = 0; |
| 571 | t->refcount = 1; |
| 572 | |
| 573 | bytes_read = block_source_read_data(source, &footer, t->size, |
| 574 | footer_size(t->version)); |
| 575 | if (bytes_read < 0 || (size_t)bytes_read != footer_size(t->version)) { |
| 576 | err = REFTABLE_IO_ERROR; |
| 577 | goto done; |