|
12 | 12 | #include "strbuf.h"
|
13 | 13 | #include "parse-options.h"
|
14 | 14 | #include "strmap.h"
|
| 15 | +#include "hash.h" |
15 | 16 |
|
16 | 17 | /*
|
17 | 18 | * This helper generates artificial repositories. To do so, it uses a
|
@@ -477,16 +478,93 @@ static int cmd__synthesize__commits(int argc, const char **argv, const char *pre
|
477 | 478 | return 0;
|
478 | 479 | }
|
479 | 480 |
|
| 481 | +static int generate_pack(const char *path, size_t object_count, const struct git_hash_algo *algo) |
| 482 | +{ |
| 483 | + FILE *f = fopen_for_writing(path); |
| 484 | + git_hash_ctx ctx; |
| 485 | + size_t i, bytes_needed = 0; |
| 486 | + unsigned char *counter = (void *)&i; |
| 487 | + char buf[1024]; |
| 488 | + |
| 489 | + for (i = object_count; i; i >>= 8) |
| 490 | + bytes_needed++; |
| 491 | + |
| 492 | + /* Let `counter` point at the relevant bytes of the variable `i` */ |
| 493 | + i = 1; |
| 494 | + if (!*counter) |
| 495 | + counter += sizeof(i) - bytes_needed; |
| 496 | + |
| 497 | + algo->init_fn(&ctx); |
| 498 | + |
| 499 | + memcpy(buf, "PACK", 4); |
| 500 | + put_be32(buf + 4, 2); |
| 501 | + put_be32(buf + 8, object_count); |
| 502 | + fwrite(buf, 1, 12, f); |
| 503 | + algo->update_fn(&ctx, buf, 12); |
| 504 | + |
| 505 | + buf[0] = 0x30 + bytes_needed; /* always a blob */ |
| 506 | + /* |
| 507 | + * Uncompressed zlib always starts with 0x78 0x01 0x01, followed by two |
| 508 | + * bytes encoding the size, little endian, then two bytes with the |
| 509 | + * bitwise-complement of that size, then the payload, and then the |
| 510 | + * Adler32 checksum. |
| 511 | + */ |
| 512 | + buf[1] = 0x78; |
| 513 | + buf[2] = 0x01; |
| 514 | + buf[3] = 0x01; |
| 515 | + |
| 516 | + buf[4] = bytes_needed & 0xff; |
| 517 | + buf[5] = (bytes_needed >> 8) & 0xff; |
| 518 | + buf[6] = buf[4] ^ 0xff; |
| 519 | + buf[7] = buf[5] ^ 0xff; |
| 520 | + |
| 521 | + for (i = 0; i < object_count; i++) { |
| 522 | + /* write a non-compressed entry */ |
| 523 | + memcpy(buf + 8, counter, bytes_needed); |
| 524 | + put_be32(buf + 8 + bytes_needed, adler32(1l, counter, bytes_needed)); |
| 525 | + |
| 526 | + fwrite(buf, 1, 12 + bytes_needed, f); |
| 527 | + algo->update_fn(&ctx, buf, 12 + bytes_needed); |
| 528 | + } |
| 529 | + |
| 530 | + algo->final_fn((unsigned char *)buf, &ctx); |
| 531 | + fwrite(buf, 1, algo->rawsz, f); |
| 532 | + |
| 533 | + fclose(f); |
| 534 | + |
| 535 | + return 0; |
| 536 | +} |
| 537 | + |
| 538 | +static int cmd__synthesize__pack(int argc, const char **argv, const char *prefix UNUSED) |
| 539 | +{ |
| 540 | + const struct git_hash_algo *algo = hash_algos + GIT_HASH_SHA1; |
| 541 | + size_t object_count; |
| 542 | + const char *path; |
| 543 | + int ret; |
| 544 | + |
| 545 | + if (argc != 3) |
| 546 | + die("usage: test-tool synthesize pack <object-count> <filename>"); |
| 547 | + |
| 548 | + object_count = strtoumax(argv[1], NULL, 10); |
| 549 | + path = argv[2]; |
| 550 | + |
| 551 | + ret = !!generate_pack(path, object_count, algo); |
| 552 | + |
| 553 | + return ret; |
| 554 | +} |
| 555 | + |
480 | 556 | int cmd__synthesize(int argc, const char **argv)
|
481 | 557 | {
|
482 | 558 | const char *prefix = NULL;
|
483 | 559 | char const * const synthesize_usage[] = {
|
484 | 560 | "test-tool synthesize commits <options>",
|
| 561 | + "test-tool synthesize pack <options>", |
485 | 562 | NULL,
|
486 | 563 | };
|
487 | 564 | parse_opt_subcommand_fn *fn = NULL;
|
488 | 565 | struct option options[] = {
|
489 | 566 | OPT_SUBCOMMAND("commits", &fn, cmd__synthesize__commits),
|
| 567 | + OPT_SUBCOMMAND("pack", &fn, cmd__synthesize__pack), |
490 | 568 | OPT_END()
|
491 | 569 | };
|
492 | 570 | argc = parse_options(argc, argv, prefix, options, synthesize_usage, 0);
|
|
0 commit comments