mirror of
https://github.com/git-for-windows/git.git
synced 2026-07-06 21:12:15 -05:00
Many uses of the_repository has been updated to use a more appropriate struct repository instance in setup.c codepath. * ps/setup-wo-the-repository: setup: stop using `the_repository` in `init_db()` setup: stop using `the_repository` in `create_reference_database()` setup: stop using `the_repository` in `initialize_repository_version()` setup: stop using `the_repository` in `check_repository_format()` setup: stop using `the_repository` in `upgrade_repository_format()` setup: stop using `the_repository` in `setup_git_directory()` setup: stop using `the_repository` in `setup_git_directory_gently()` setup: stop using `the_repository` in `setup_git_env()` setup: stop using `the_repository` in `set_git_work_tree()` setup: stop using `the_repository` in `setup_work_tree()` setup: stop using `the_repository` in `enter_repo()` setup: stop using `the_repository` in `verify_non_filename()` setup: stop using `the_repository` in `verify_filename()` setup: stop using `the_repository` in `path_inside_repo()` setup: stop using `the_repository` in `prefix_path()` setup: stop using `the_repository` in `is_inside_work_tree()` setup: stop using `the_repository` in `is_inside_git_dir()` setup: replace use of `the_repository` in static functions
542 lines
18 KiB
C
542 lines
18 KiB
C
#define USE_THE_REPOSITORY_VARIABLE
|
|
|
|
#include "test-tool.h"
|
|
#include "git-compat-util.h"
|
|
#include "git-zlib.h"
|
|
#include "hash.h"
|
|
#include "hex.h"
|
|
#include "object-file.h"
|
|
#include "object.h"
|
|
#include "pack.h"
|
|
#include "parse-options.h"
|
|
#include "parse.h"
|
|
#include "repository.h"
|
|
#include "setup.h"
|
|
#include "strbuf.h"
|
|
#include "write-or-die.h"
|
|
|
|
#define BLOCK_SIZE 0xffff
|
|
static const unsigned char zeros[BLOCK_SIZE];
|
|
|
|
/*
|
|
* Write data as an uncompressed zlib stream.
|
|
* For data larger than 64KB, writes multiple uncompressed blocks.
|
|
* If data is NULL, writes zeros.
|
|
* Updates the pack checksum context.
|
|
*/
|
|
static void write_uncompressed_zlib(FILE *f, struct git_hash_ctx *pack_ctx,
|
|
const void *data, size_t len,
|
|
const struct git_hash_algo *algo)
|
|
{
|
|
unsigned char zlib_header[2] = { 0x78, 0x01 }; /* CMF, FLG */
|
|
unsigned char block_header[5];
|
|
const unsigned char *p = data;
|
|
size_t remaining = len;
|
|
uint32_t adler = 1L; /* adler32 initial value */
|
|
unsigned char adler_buf[4];
|
|
|
|
/* Write zlib header */
|
|
fwrite_or_die(f, zlib_header, sizeof(zlib_header));
|
|
algo->update_fn(pack_ctx, zlib_header, 2);
|
|
|
|
/* Write uncompressed blocks (max 64KB each) */
|
|
do {
|
|
size_t block_len = remaining > BLOCK_SIZE ? BLOCK_SIZE : remaining;
|
|
int is_final = (block_len == remaining);
|
|
const unsigned char *block_data = data ? p : zeros;
|
|
|
|
block_header[0] = is_final ? 0x01 : 0x00;
|
|
block_header[1] = block_len & 0xff;
|
|
block_header[2] = (block_len >> 8) & 0xff;
|
|
block_header[3] = block_header[1] ^ 0xff;
|
|
block_header[4] = block_header[2] ^ 0xff;
|
|
|
|
fwrite_or_die(f, block_header, sizeof(block_header));
|
|
algo->update_fn(pack_ctx, block_header, 5);
|
|
|
|
if (block_len) {
|
|
fwrite_or_die(f, block_data, block_len);
|
|
algo->update_fn(pack_ctx, block_data, block_len);
|
|
adler = adler32(adler, block_data, block_len);
|
|
}
|
|
|
|
if (data)
|
|
p += block_len;
|
|
remaining -= block_len;
|
|
} while (remaining > 0);
|
|
|
|
/* Write adler32 checksum */
|
|
put_be32(adler_buf, adler);
|
|
fwrite_or_die(f, adler_buf, sizeof(adler_buf));
|
|
algo->update_fn(pack_ctx, adler_buf, 4);
|
|
}
|
|
|
|
/*
|
|
* Write an uncompressed object to the pack file.
|
|
* If `data == NULL`, it is treated like a buffer to NUL bytes.
|
|
* Updates the pack checksum context.
|
|
*/
|
|
static void write_pack_object(FILE *f, struct git_hash_ctx *pack_ctx,
|
|
enum object_type type,
|
|
const void *data, size_t len,
|
|
struct object_id *oid,
|
|
const struct git_hash_algo *algo)
|
|
{
|
|
unsigned char pack_header[MAX_PACK_OBJECT_HEADER];
|
|
char object_header[32];
|
|
int pack_header_len, object_header_len;
|
|
struct git_hash_ctx ctx;
|
|
|
|
/* Write pack object header */
|
|
pack_header_len = encode_in_pack_object_header(pack_header,
|
|
sizeof(pack_header),
|
|
type, len);
|
|
fwrite_or_die(f, pack_header, pack_header_len);
|
|
algo->update_fn(pack_ctx, pack_header, pack_header_len);
|
|
|
|
/* Write the data as uncompressed zlib */
|
|
write_uncompressed_zlib(f, pack_ctx, data, len, algo);
|
|
|
|
algo->init_fn(&ctx);
|
|
object_header_len = format_object_header(object_header,
|
|
sizeof(object_header),
|
|
type, len);
|
|
algo->update_fn(&ctx, object_header, object_header_len);
|
|
if (data)
|
|
algo->update_fn(&ctx, data, len);
|
|
else {
|
|
for (size_t i = len / BLOCK_SIZE; i; i--)
|
|
algo->update_fn(&ctx, zeros, BLOCK_SIZE);
|
|
algo->update_fn(&ctx, zeros, len % BLOCK_SIZE);
|
|
}
|
|
algo->final_oid_fn(oid, &ctx);
|
|
}
|
|
|
|
/*
|
|
* Fast path: precomputed pack data for a 4 GiB + 1 all-NUL blob.
|
|
*
|
|
* The generated pack is almost entirely zeros with a small constant
|
|
* prefix, periodic deflate block headers, and a constant suffix
|
|
* containing the tree, two commits, and the pack checksum. Because
|
|
* every byte is deterministic for a given blob size and hash algorithm,
|
|
* we can write the pack without computing any hashes at all, reducing
|
|
* runtime from minutes of hash computation to seconds of pure I/O.
|
|
*
|
|
* The blob is stored as an uncompressed deflate stream: a two-byte
|
|
* zlib header, then 65538 blocks of up to 0xffff bytes each, followed
|
|
* by an adler32 checksum. The pack header and deflate framing are
|
|
* shared across hash algorithms; only the suffix (which contains OIDs
|
|
* and the pack checksum) differs.
|
|
*
|
|
* Constants were generated by running the generic path and extracting
|
|
* the non-zero bytes from the resulting pack file.
|
|
*/
|
|
|
|
#define FAST_PACK_4G1_BLOB_SIZE ((size_t)4 * 1024 * 1024 * 1024 + 1)
|
|
#define FAST_PACK_4G1_N_FULL_BLOCKS 65537
|
|
|
|
/*
|
|
* Per-hash-algorithm constants for the fast path. The prefix and
|
|
* deflate block structure are identical across algorithms; only the
|
|
* suffix (tree, commits, pack checksum) and the commit OID differ.
|
|
*/
|
|
struct fast_pack {
|
|
uint32_t format_id;
|
|
const unsigned char *suffix;
|
|
size_t suffix_len;
|
|
const char *commit_oid;
|
|
};
|
|
|
|
/* Pack header + pack object header + zlib header + first block header */
|
|
static const unsigned char fast_pack_prefix[] = {
|
|
/* PACK header: signature, version 2, 5 objects */
|
|
0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x02,
|
|
0x00, 0x00, 0x00, 0x05,
|
|
/* pack object header: blob, size = 4294967297 */
|
|
0xb1, 0x80, 0x80, 0x80, 0x80, 0x01,
|
|
/* zlib header: CMF=0x78, FLG=0x01 */
|
|
0x78, 0x01,
|
|
/* first non-final block header: BFINAL=0, LEN=0xffff, NLEN=0x0000 */
|
|
0x00, 0xff, 0xff, 0x00, 0x00
|
|
};
|
|
|
|
/* Every non-final deflate block header is identical */
|
|
static const unsigned char fast_pack_block_header[] = {
|
|
0x00, 0xff, 0xff, 0x00, 0x00
|
|
};
|
|
|
|
/* Final block (2 data bytes) + adler32 of 4294967297 NUL bytes */
|
|
static const unsigned char fast_pack_final_block[] = {
|
|
/* BFINAL=1, LEN=2, NLEN=0xfffd */
|
|
0x01, 0x02, 0x00, 0xfd, 0xff,
|
|
/* 2 NUL data bytes */
|
|
0x00, 0x00,
|
|
/* adler32 */
|
|
0x00, 0xe2, 0x00, 0x01
|
|
};
|
|
|
|
/*
|
|
* SHA-1 suffix: tree, commit, empty tree, final commit, pack checksum.
|
|
*/
|
|
static const unsigned char fast_pack_sha1_suffix[] = {
|
|
0xa0, 0x02, 0x78, 0x01, 0x01, 0x20, 0x00, 0xdf,
|
|
0xff, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20,
|
|
0x66, 0x69, 0x6c, 0x65, 0x00, 0x3e, 0xb7, 0xfe,
|
|
0xb1, 0x41, 0x3c, 0x75, 0x7f, 0x0d, 0x81, 0x81,
|
|
0xde, 0xb2, 0x8d, 0x1d, 0xab, 0x03, 0xd6, 0x48,
|
|
0x46, 0xb4, 0xb4, 0x0c, 0x60, 0x95, 0x0b, 0x78,
|
|
0x01, 0x01, 0xb5, 0x00, 0x4a, 0xff, 0x74, 0x72,
|
|
0x65, 0x65, 0x20, 0x63, 0x36, 0x38, 0x33, 0x66,
|
|
0x63, 0x63, 0x37, 0x64, 0x31, 0x64, 0x38, 0x33,
|
|
0x65, 0x66, 0x32, 0x66, 0x65, 0x31, 0x61, 0x66,
|
|
0x35, 0x35, 0x32, 0x31, 0x35, 0x64, 0x30, 0x31,
|
|
0x36, 0x38, 0x64, 0x62, 0x35, 0x32, 0x61, 0x33,
|
|
0x61, 0x33, 0x62, 0x0a, 0x61, 0x75, 0x74, 0x68,
|
|
0x6f, 0x72, 0x20, 0x41, 0x20, 0x55, 0x20, 0x54,
|
|
0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75, 0x74,
|
|
0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d,
|
|
0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e,
|
|
0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
0x38, 0x39, 0x30, 0x20, 0x2b, 0x30, 0x30, 0x30,
|
|
0x30, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
|
|
0x74, 0x65, 0x72, 0x20, 0x43, 0x20, 0x4f, 0x20,
|
|
0x4d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x3c,
|
|
0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65,
|
|
0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c,
|
|
0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31,
|
|
0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
|
0x30, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a,
|
|
0x0a, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x20, 0x62,
|
|
0x6c, 0x6f, 0x62, 0x20, 0x63, 0x6f, 0x6d, 0x6d,
|
|
0x69, 0x74, 0x0a, 0xc6, 0x55, 0x37, 0x6b, 0x20,
|
|
0x78, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00,
|
|
0x00, 0x00, 0x01, 0x95, 0x0e, 0x78, 0x01, 0x01,
|
|
0xe5, 0x00, 0x1a, 0xff, 0x74, 0x72, 0x65, 0x65,
|
|
0x20, 0x34, 0x62, 0x38, 0x32, 0x35, 0x64, 0x63,
|
|
0x36, 0x34, 0x32, 0x63, 0x62, 0x36, 0x65, 0x62,
|
|
0x39, 0x61, 0x30, 0x36, 0x30, 0x65, 0x35, 0x34,
|
|
0x62, 0x66, 0x38, 0x64, 0x36, 0x39, 0x32, 0x38,
|
|
0x38, 0x66, 0x62, 0x65, 0x65, 0x34, 0x39, 0x30,
|
|
0x34, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
|
|
0x20, 0x63, 0x35, 0x62, 0x32, 0x31, 0x63, 0x36,
|
|
0x31, 0x31, 0x61, 0x61, 0x35, 0x39, 0x34, 0x65,
|
|
0x63, 0x39, 0x66, 0x64, 0x37, 0x65, 0x39, 0x32,
|
|
0x63, 0x66, 0x39, 0x36, 0x34, 0x38, 0x39, 0x31,
|
|
0x34, 0x63, 0x61, 0x34, 0x63, 0x32, 0x34, 0x31,
|
|
0x32, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
|
|
0x20, 0x41, 0x20, 0x55, 0x20, 0x54, 0x68, 0x6f,
|
|
0x72, 0x20, 0x3c, 0x61, 0x75, 0x74, 0x68, 0x6f,
|
|
0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c,
|
|
0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31,
|
|
0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
|
0x30, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a,
|
|
0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65,
|
|
0x72, 0x20, 0x43, 0x20, 0x4f, 0x20, 0x4d, 0x69,
|
|
0x74, 0x74, 0x65, 0x72, 0x20, 0x3c, 0x63, 0x6f,
|
|
0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x40,
|
|
0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e,
|
|
0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x33,
|
|
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x20,
|
|
0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x45,
|
|
0x6d, 0x70, 0x74, 0x79, 0x20, 0x74, 0x72, 0x65,
|
|
0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
|
|
0x0a, 0xaa, 0xb8, 0x45, 0x01, 0x8e, 0xfc, 0xf0,
|
|
0x2f, 0x9c, 0xc5, 0xcc, 0x4f, 0x6a, 0x1a, 0xc9,
|
|
0x2b, 0x23, 0xa9, 0xff, 0x91, 0x06, 0xc2, 0x70,
|
|
0xe3
|
|
};
|
|
|
|
/*
|
|
* SHA-256 suffix: same structure, but with 32-byte OIDs and SHA-256
|
|
* pack checksum (609 bytes vs 513 for SHA-1).
|
|
*/
|
|
static const unsigned char fast_pack_sha256_suffix[] = {
|
|
0xac, 0x02, 0x78, 0x01, 0x01, 0x2c, 0x00, 0xd3,
|
|
0xff, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20,
|
|
0x66, 0x69, 0x6c, 0x65, 0x00, 0x42, 0x53, 0xc1,
|
|
0x8a, 0x9f, 0x5e, 0xc3, 0xbb, 0x47, 0xb0, 0x83,
|
|
0x8a, 0x19, 0xdb, 0x31, 0xbb, 0x7b, 0x0f, 0x3b,
|
|
0x80, 0xa4, 0xbc, 0x2f, 0xaf, 0x72, 0x6b, 0xdb,
|
|
0x62, 0xaa, 0xba, 0xdd, 0xde, 0x77, 0xc6, 0x13,
|
|
0xeb, 0x9d, 0x0c, 0x78, 0x01, 0x01, 0xcd, 0x00,
|
|
0x32, 0xff, 0x74, 0x72, 0x65, 0x65, 0x20, 0x62,
|
|
0x36, 0x30, 0x39, 0x37, 0x37, 0x64, 0x37, 0x63,
|
|
0x34, 0x63, 0x32, 0x64, 0x31, 0x65, 0x63, 0x63,
|
|
0x33, 0x66, 0x62, 0x61, 0x31, 0x64, 0x39, 0x38,
|
|
0x65, 0x65, 0x31, 0x32, 0x30, 0x61, 0x64, 0x63,
|
|
0x32, 0x34, 0x38, 0x33, 0x34, 0x39, 0x35, 0x30,
|
|
0x62, 0x65, 0x34, 0x31, 0x32, 0x64, 0x39, 0x34,
|
|
0x63, 0x38, 0x30, 0x39, 0x34, 0x38, 0x30, 0x66,
|
|
0x35, 0x38, 0x62, 0x61, 0x39, 0x64, 0x61, 0x0a,
|
|
0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x20, 0x41,
|
|
0x20, 0x55, 0x20, 0x54, 0x68, 0x6f, 0x72, 0x20,
|
|
0x3c, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x40,
|
|
0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e,
|
|
0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x33,
|
|
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x20,
|
|
0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x63, 0x6f,
|
|
0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20,
|
|
0x43, 0x20, 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74,
|
|
0x65, 0x72, 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d,
|
|
0x69, 0x74, 0x74, 0x65, 0x72, 0x40, 0x65, 0x78,
|
|
0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
|
|
0x6d, 0x3e, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35,
|
|
0x36, 0x37, 0x38, 0x39, 0x30, 0x20, 0x2b, 0x30,
|
|
0x30, 0x30, 0x30, 0x0a, 0x0a, 0x4c, 0x61, 0x72,
|
|
0x67, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x62, 0x20,
|
|
0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0xb7,
|
|
0x80, 0x3d, 0xd7, 0x20, 0x78, 0x01, 0x01, 0x00,
|
|
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x95,
|
|
0x11, 0x78, 0x01, 0x01, 0x15, 0x01, 0xea, 0xfe,
|
|
0x74, 0x72, 0x65, 0x65, 0x20, 0x36, 0x65, 0x66,
|
|
0x31, 0x39, 0x62, 0x34, 0x31, 0x32, 0x32, 0x35,
|
|
0x63, 0x35, 0x33, 0x36, 0x39, 0x66, 0x31, 0x63,
|
|
0x31, 0x30, 0x34, 0x64, 0x34, 0x35, 0x64, 0x38,
|
|
0x64, 0x38, 0x35, 0x65, 0x66, 0x61, 0x39, 0x62,
|
|
0x30, 0x35, 0x37, 0x62, 0x35, 0x33, 0x62, 0x31,
|
|
0x34, 0x62, 0x34, 0x62, 0x39, 0x62, 0x39, 0x33,
|
|
0x39, 0x64, 0x64, 0x37, 0x34, 0x64, 0x65, 0x63,
|
|
0x63, 0x35, 0x33, 0x32, 0x31, 0x0a, 0x70, 0x61,
|
|
0x72, 0x65, 0x6e, 0x74, 0x20, 0x37, 0x35, 0x62,
|
|
0x66, 0x30, 0x63, 0x34, 0x37, 0x61, 0x65, 0x34,
|
|
0x62, 0x62, 0x33, 0x30, 0x38, 0x65, 0x37, 0x63,
|
|
0x63, 0x32, 0x34, 0x38, 0x32, 0x65, 0x32, 0x32,
|
|
0x65, 0x66, 0x61, 0x65, 0x33, 0x37, 0x38, 0x37,
|
|
0x61, 0x39, 0x36, 0x38, 0x34, 0x38, 0x62, 0x64,
|
|
0x31, 0x37, 0x34, 0x39, 0x35, 0x36, 0x37, 0x31,
|
|
0x34, 0x37, 0x31, 0x35, 0x32, 0x34, 0x36, 0x64,
|
|
0x64, 0x62, 0x64, 0x35, 0x34, 0x0a, 0x61, 0x75,
|
|
0x74, 0x68, 0x6f, 0x72, 0x20, 0x41, 0x20, 0x55,
|
|
0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61,
|
|
0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78,
|
|
0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
|
|
0x6d, 0x3e, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35,
|
|
0x36, 0x37, 0x38, 0x39, 0x30, 0x20, 0x2b, 0x30,
|
|
0x30, 0x30, 0x30, 0x0a, 0x63, 0x6f, 0x6d, 0x6d,
|
|
0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x43, 0x20,
|
|
0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72,
|
|
0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
|
|
0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d,
|
|
0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e,
|
|
0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
0x38, 0x39, 0x30, 0x20, 0x2b, 0x30, 0x30, 0x30,
|
|
0x30, 0x0a, 0x0a, 0x45, 0x6d, 0x70, 0x74, 0x79,
|
|
0x20, 0x74, 0x72, 0x65, 0x65, 0x20, 0x63, 0x6f,
|
|
0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x6d, 0x6d, 0x51,
|
|
0x9a, 0xc9, 0x11, 0x76, 0x61, 0xa3, 0x89, 0x49,
|
|
0xb7, 0xa1, 0x58, 0xc6, 0x1d, 0x8c, 0x33, 0x75,
|
|
0x8d, 0x7e, 0x4d, 0x8e, 0x58, 0x91, 0xf8, 0x5c,
|
|
0x57, 0xd9, 0x89, 0x9e, 0xb8, 0xd2, 0x9a, 0xd8,
|
|
0xc9
|
|
};
|
|
|
|
static const struct fast_pack fast_packs[] = {
|
|
{
|
|
.format_id = GIT_SHA1_FORMAT_ID,
|
|
.suffix = fast_pack_sha1_suffix,
|
|
.suffix_len = sizeof(fast_pack_sha1_suffix),
|
|
.commit_oid = "aac43daf40d0377af31aa9c798a4ae8a31b55c1d",
|
|
},
|
|
{
|
|
.format_id = GIT_SHA256_FORMAT_ID,
|
|
.suffix = fast_pack_sha256_suffix,
|
|
.suffix_len = sizeof(fast_pack_sha256_suffix),
|
|
.commit_oid = "63c46ca51267b1d45be69a044bb84b4bf0559f09"
|
|
"d727f861d2ae94ddebdddbc9",
|
|
},
|
|
};
|
|
|
|
/*
|
|
* Try the fast path for known blob sizes. Returns 1 if the pack was
|
|
* written from precomputed constants, 0 if the caller should fall
|
|
* through to the generic path.
|
|
*/
|
|
static int generate_fast_pack(const char *path, size_t blob_size,
|
|
const struct git_hash_algo *algo)
|
|
{
|
|
const struct fast_pack *fp = NULL;
|
|
FILE *f;
|
|
size_t i;
|
|
|
|
if (blob_size != FAST_PACK_4G1_BLOB_SIZE)
|
|
return 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fast_packs); i++) {
|
|
if (fast_packs[i].format_id == algo->format_id) {
|
|
fp = &fast_packs[i];
|
|
break;
|
|
}
|
|
}
|
|
if (!fp)
|
|
return 0;
|
|
|
|
f = xfopen(path, "wb");
|
|
|
|
fwrite_or_die(f, fast_pack_prefix, sizeof(fast_pack_prefix));
|
|
|
|
/* First full block: 0xffff zero bytes (header already in prefix) */
|
|
fwrite_or_die(f, zeros, BLOCK_SIZE);
|
|
|
|
/* Remaining non-final full blocks */
|
|
for (i = 1; i < FAST_PACK_4G1_N_FULL_BLOCKS; i++) {
|
|
fwrite_or_die(f, fast_pack_block_header,
|
|
sizeof(fast_pack_block_header));
|
|
fwrite_or_die(f, zeros, BLOCK_SIZE);
|
|
}
|
|
|
|
/* Final block (2 data bytes) + adler32 */
|
|
fwrite_or_die(f, fast_pack_final_block,
|
|
sizeof(fast_pack_final_block));
|
|
|
|
/* Tree, commits, and pack checksum */
|
|
fwrite_or_die(f, fp->suffix, fp->suffix_len);
|
|
|
|
if (fclose(f))
|
|
die_errno(_("could not close '%s'"), path);
|
|
|
|
printf("%s\n", fp->commit_oid);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Generate a pack file with a single large (>4GB) reachable object.
|
|
*
|
|
* Creates:
|
|
* 1. A large blob (all NUL bytes)
|
|
* 2. A tree containing that blob as "file"
|
|
* 3. A commit using that tree
|
|
* 4. The empty tree
|
|
* 5. A child commit using the empty tree
|
|
*
|
|
* This is useful for testing that Git can handle objects larger than 4GB.
|
|
*/
|
|
static int generate_pack_with_large_object(const char *path, size_t blob_size,
|
|
const struct git_hash_algo *algo)
|
|
{
|
|
FILE *f;
|
|
struct git_hash_ctx pack_ctx;
|
|
unsigned char pack_hash[GIT_MAX_RAWSZ];
|
|
struct object_id blob_oid, tree_oid, commit_oid, empty_tree_oid, final_commit_oid;
|
|
struct strbuf buf = STRBUF_INIT;
|
|
const uint32_t object_count = 5;
|
|
struct pack_header pack_header = {
|
|
.hdr_signature = htonl(PACK_SIGNATURE),
|
|
.hdr_version = htonl(PACK_VERSION),
|
|
.hdr_entries = htonl(object_count),
|
|
};
|
|
|
|
if (generate_fast_pack(path, blob_size, algo))
|
|
return 0;
|
|
|
|
f = xfopen(path, "wb");
|
|
|
|
algo->init_fn(&pack_ctx);
|
|
|
|
/* Write pack header */
|
|
fwrite_or_die(f, &pack_header, sizeof(pack_header));
|
|
algo->update_fn(&pack_ctx, &pack_header, sizeof(pack_header));
|
|
|
|
/* 1. Write the large blob */
|
|
write_pack_object(f, &pack_ctx, OBJ_BLOB, NULL, blob_size, &blob_oid, algo);
|
|
|
|
/* 2. Write tree containing the blob as "file" */
|
|
strbuf_addf(&buf, "100644 file%c", '\0');
|
|
strbuf_add(&buf, blob_oid.hash, algo->rawsz);
|
|
write_pack_object(f, &pack_ctx, OBJ_TREE, buf.buf, buf.len, &tree_oid, algo);
|
|
|
|
/* 3. Write commit using that tree */
|
|
strbuf_reset(&buf);
|
|
strbuf_addf(&buf,
|
|
"tree %s\n"
|
|
"author A U Thor <author@example.com> 1234567890 +0000\n"
|
|
"committer C O Mitter <committer@example.com> 1234567890 +0000\n"
|
|
"\n"
|
|
"Large blob commit\n",
|
|
oid_to_hex(&tree_oid));
|
|
write_pack_object(f, &pack_ctx, OBJ_COMMIT, buf.buf, buf.len, &commit_oid, algo);
|
|
|
|
/* 4. Write the empty tree */
|
|
write_pack_object(f, &pack_ctx, OBJ_TREE, "", 0, &empty_tree_oid, algo);
|
|
|
|
/* 5. Write final commit using empty tree, with previous commit as parent */
|
|
strbuf_reset(&buf);
|
|
strbuf_addf(&buf,
|
|
"tree %s\n"
|
|
"parent %s\n"
|
|
"author A U Thor <author@example.com> 1234567890 +0000\n"
|
|
"committer C O Mitter <committer@example.com> 1234567890 +0000\n"
|
|
"\n"
|
|
"Empty tree commit\n",
|
|
oid_to_hex(&empty_tree_oid),
|
|
oid_to_hex(&commit_oid));
|
|
write_pack_object(f, &pack_ctx, OBJ_COMMIT, buf.buf, buf.len, &final_commit_oid, algo);
|
|
|
|
/* Write pack trailer (checksum) */
|
|
algo->final_fn(pack_hash, &pack_ctx);
|
|
fwrite_or_die(f, pack_hash, algo->rawsz);
|
|
if (fclose(f))
|
|
die_errno(_("could not close '%s'"), path);
|
|
|
|
strbuf_release(&buf);
|
|
|
|
/* Print the final commit OID so caller can set up refs */
|
|
printf("%s\n", oid_to_hex(&final_commit_oid));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd__synthesize__pack(int argc, const char **argv,
|
|
const char *prefix UNUSED,
|
|
struct repository *repo)
|
|
{
|
|
int non_git;
|
|
int reachable_large = 0;
|
|
const struct git_hash_algo *algo;
|
|
size_t blob_size;
|
|
uintmax_t blob_size_u;
|
|
const char *path;
|
|
const char * const usage[] = {
|
|
"test-tool synthesize pack "
|
|
"--reachable-large <blob-size> <filename>",
|
|
NULL
|
|
};
|
|
struct option options[] = {
|
|
OPT_BOOL(0, "reachable-large", &reachable_large,
|
|
N_("write a pack with a single reachable large blob")),
|
|
OPT_END()
|
|
};
|
|
|
|
setup_git_directory_gently(the_repository, &non_git);
|
|
repo = the_repository;
|
|
algo = unsafe_hash_algo(repo->hash_algo);
|
|
|
|
argc = parse_options(argc, argv, NULL, options, usage,
|
|
PARSE_OPT_KEEP_ARGV0);
|
|
if (argc != 3 || !reachable_large)
|
|
usage_with_options(usage, options);
|
|
|
|
if (!git_parse_unsigned(argv[1], &blob_size_u,
|
|
maximum_unsigned_value_of_type(size_t)))
|
|
die(_("'%s' is not a valid blob size"), argv[1]);
|
|
blob_size = blob_size_u;
|
|
path = argv[2];
|
|
|
|
return !!generate_pack_with_large_object(path, blob_size, algo);
|
|
}
|
|
|
|
int cmd__synthesize(int argc, const char **argv)
|
|
{
|
|
const char *prefix = NULL;
|
|
char const * const synthesize_usage[] = {
|
|
"test-tool synthesize pack <options>",
|
|
NULL,
|
|
};
|
|
parse_opt_subcommand_fn *fn = NULL;
|
|
struct option options[] = {
|
|
OPT_SUBCOMMAND("pack", &fn, cmd__synthesize__pack),
|
|
OPT_END()
|
|
};
|
|
argc = parse_options(argc, argv, prefix, options, synthesize_usage, 0);
|
|
return !!fn(argc, argv, prefix, NULL);
|
|
}
|