#include "builtin.h"
#include "delta.h"
#include "pack.h"
#include "csum-file.h"
#include "blob.h"
#include "commit.h"
#include "tag.h"
#include "tree.h"
#include "progress.h"
#include "fsck.h"
#include "exec_cmd.h"
static const char index_pack_usage[] =
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
struct object_entry {
struct pack_idx_entry idx;
unsigned long size;
unsigned int hdr_size;
enum object_type type;
enum object_type real_type;
unsigned delta_depth;
int base_object_no;
};
union delta_base {
unsigned char sha1[20];
off_t offset;
};
struct base_data {
struct base_data *base;
struct base_data *child;
struct object_entry *obj;
void *data;
unsigned long size;
};
/*
* Even if sizeof(union delta_base) == 24 on 64-bit archs, we really want
* to memcmp() only the first 20 bytes.
*/
#define UNION_BASE_SZ 20
#define FLAG_LINK (1u<<20)
#define FLAG_CHECKED (1u<<21)
struct delta_entry {
union delta_base base;
int obj_no;
};
static struct object_entry *objects;
static struct delta_entry *deltas;
static struct base_data *base_cache;
static size_t base_cache_used;
static int nr_objects;
static int nr_deltas;
static int nr_resolved_deltas;
static int from_stdin;
static int strict;
static int verbose;
static struct progress *progress;
/* We always read in 4kB chunks. */
static unsigned char input_buffer[4096];
static unsigned int input_offset, input_len;
static off_t consumed_bytes;
static unsigned deepest_delta;
static git_SHA_CTX input_ctx;
static uint32_t input_crc32;
static int input_fd, output_fd, pack_fd;
static int mark_link(struct object *obj, int type, void *data)
{
if (!obj)
return -1;
if (type != OBJ_ANY && obj->type != type)
die("object type mismatch at %s", sha1_to_hex(obj->sha1));
obj->flags |= FLAG_LINK;
return 0;
}
/* The content of each linked object must have been checked
or it must be already present in the object database */
static void check_object(struct object *obj)
{
if (!obj)
return;
if (!(obj->flags & FLAG_LINK))
return;
if (!(obj->flags & FLAG_CHECKED)) {
unsigned long size;
int type = sha1_object_info(obj->sha1, &size);
if (type != obj->type || type <= 0)
die("object of unexpected type");
obj->flags |= FLAG_CHECKED;
return;
}
}
static void check_objects(void)
{
unsigned i, max;
max = get_max_object_index();
for (i = 0; i < max; i++)
check_object(get_indexed_object(i));
}
/* Discard current buffer used content. */
static void flush(void)
{
if (input_offset) {
if (output_fd >= 0)
write_or_die(output_fd, input_buffer, input_offset);
git_SHA1_Update(&input_ctx, input_buffer, input_offset);
memmove(input_buffer, input_buffer + input_offset, input_len);
input_offset = 0;
}
}
/*
* Make sure at least "min" bytes are available in the buffer, and
* return the pointer to the buffer.
*/
static void *fill(int min)
{
if (min <= input_len)
return input_buffer + input_offset;
if (min > sizeof(input_buffer))
die("cannot fill %d bytes", min);
flush();
do {
ssize_t ret = xread(input_fd, input_buffer + input_len,
sizeof(input_buffer) - input_len);
if (ret <= 0) {
if (!ret)
die("early EOF");
die_errno("read error on input");
}
input_len += ret;
if (from_stdin)
display_throughput(progress, consumed_bytes + input_len);
} while (input_len < min);
return input_buffer;
}
static void use(int bytes)
{
if (bytes > input_len)
die("used more bytes than were available"
|