#include "diff.h"
#include "revision.h"
#include "list-objects.h"
-#include <sys/time.h>
-#include <signal.h>
-static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--delta-base-offset] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] [--revs [--unpacked | --all]*] [--stdout | base-name] <ref-list | <object-list]";
+static const char pack_usage[] = "\
+git-pack-objects [{ -q | --progress | --all-progress }] \n\
+ [--local] [--incremental] [--window=N] [--depth=N] \n\
+ [--no-reuse-delta] [--delta-base-offset] [--non-empty] \n\
+ [--revs [--unpacked | --all]*] [--reflog] [--stdout | base-name] \n\
+ [<ref-list | <object-list]";
struct object_entry {
unsigned char sha1[20];
* we are going to reuse the existing object data as is. make
* sure it is not corrupt.
*/
-static int check_inflate(unsigned char *data, unsigned long len, unsigned long expect)
+static int check_pack_inflate(struct packed_git *p,
+ struct pack_window **w_curs,
+ unsigned long offset,
+ unsigned long len,
+ unsigned long expect)
+{
+ z_stream stream;
+ unsigned char fakebuf[4096], *in;
+ int st;
+
+ memset(&stream, 0, sizeof(stream));
+ inflateInit(&stream);
+ do {
+ in = use_pack(p, w_curs, offset, &stream.avail_in);
+ stream.next_in = in;
+ stream.next_out = fakebuf;
+ stream.avail_out = sizeof(fakebuf);
+ st = inflate(&stream, Z_FINISH);
+ offset += stream.next_in - in;
+ } while (st == Z_OK || st == Z_BUF_ERROR);
+ inflateEnd(&stream);
+ return (st == Z_STREAM_END &&
+ stream.total_out == expect &&
+ stream.total_in == len) ? 0 : -1;
+}
+
+static void copy_pack_data(struct sha1file *f,
+ struct packed_git *p,
+ struct pack_window **w_curs,
+ unsigned long offset,
+ unsigned long len)
+{
+ unsigned char *in;
+ unsigned int avail;
+
+ while (len) {
+ in = use_pack(p, w_curs, offset, &avail);
+ if (avail > len)
+ avail = len;
+ sha1write(f, in, avail);
+ offset += avail;
+ len -= avail;
+ }
+}
+
+static int check_loose_inflate(unsigned char *data, unsigned long len, unsigned long expect)
{
z_stream stream;
unsigned char fakebuf[4096];
return -1;
map += used;
mapsize -= used;
- return check_inflate(map, mapsize, size);
+ return check_loose_inflate(map, mapsize, size);
}
static unsigned long write_object(struct sha1file *f,
}
else {
struct packed_git *p = entry->in_pack;
+ struct pack_window *w_curs = NULL;
+ unsigned long offset;
if (entry->delta) {
obj_type = (allow_ofs_delta && entry->delta->offset) ?
hdrlen += 20;
}
- use_packed_git(p);
- buf = (char *) p->pack_base
- + entry->in_pack_offset
- + entry->in_pack_header_size;
+ offset = entry->in_pack_offset + entry->in_pack_header_size;
datalen = find_packed_object_size(p, entry->in_pack_offset)
- entry->in_pack_header_size;
- if (!pack_to_stdout && check_inflate(buf, datalen, entry->size))
+ if (!pack_to_stdout && check_pack_inflate(p, &w_curs,
+ offset, datalen, entry->size))
die("corrupt delta in pack %s", sha1_to_hex(entry->sha1));
- sha1write(f, buf, datalen);
- unuse_packed_git(p);
+ copy_pack_data(f, p, &w_curs, offset, datalen);
+ unuse_pack(&w_curs);
reused++;
}
if (entry->delta)
unsigned long offset;
struct pack_header hdr;
unsigned last_percent = 999;
- int do_progress = 0;
+ int do_progress = progress;
- if (!base_name)
+ if (!base_name) {
f = sha1fd(1, "<stdout>");
- else {
+ do_progress >>= 1;
+ }
+ else
f = sha1create("%s-%s.%s", base_name,
sha1_to_hex(object_list_sha1), "pack");
- do_progress = progress;
- }
if (do_progress)
fprintf(stderr, "Writing %d objects.\n", nr_result);
if (do_progress)
fputc('\n', stderr);
done:
+ if (written != nr_result)
+ die("wrote %d objects while expecting %d", written, nr_result);
sha1close(f, pack_file_sha1, 1);
}
sha1_to_hex(object_list_sha1), "idx");
struct object_entry **list = sorted_by_sha;
struct object_entry **last = list + nr_result;
- unsigned int array[256];
+ uint32_t array[256];
/*
* Write the first-level table (the list is sorted,
array[i] = htonl(next - sorted_by_sha);
list = next;
}
- sha1write(f, array, 256 * sizeof(int));
+ sha1write(f, array, 256 * 4);
/*
* Write the actual SHA1 entries..
list = sorted_by_sha;
for (i = 0; i < nr_result; i++) {
struct object_entry *entry = *list++;
- unsigned int offset = htonl(entry->offset);
+ uint32_t offset = htonl(entry->offset);
sha1write(f, &offset, 4);
sha1write(f, entry->sha1, 20);
}
if (entry->in_pack && !entry->preferred_base) {
struct packed_git *p = entry->in_pack;
+ struct pack_window *w_curs = NULL;
unsigned long left = p->pack_size - entry->in_pack_offset;
unsigned long size, used;
unsigned char *buf;
struct object_entry *base_entry = NULL;
- use_packed_git(p);
- buf = p->pack_base;
- buf += entry->in_pack_offset;
+ buf = use_pack(p, &w_curs, entry->in_pack_offset, NULL);
/* We want in_pack_type even if we do not reuse delta.
* There is no point not reusing non-delta representations.
*/
used = unpack_object_header_gently(buf, left,
&entry->in_pack_type, &size);
- if (!used || left - used <= 20)
- die("corrupt pack for %s", sha1_to_hex(entry->sha1));
/* Check if it is delta, and the base is also an object
* we are going to pack. If so we will reuse the existing
if (!no_reuse_delta) {
unsigned char c, *base_name;
unsigned long ofs;
+ unsigned long used_0;
/* there is at least 20 bytes left in the pack */
switch (entry->in_pack_type) {
case OBJ_REF_DELTA:
- base_name = buf + used;
+ base_name = use_pack(p, &w_curs,
+ entry->in_pack_offset + used, NULL);
used += 20;
break;
case OBJ_OFS_DELTA:
- c = buf[used++];
+ buf = use_pack(p, &w_curs,
+ entry->in_pack_offset + used, NULL);
+ used_0 = 0;
+ c = buf[used_0++];
ofs = c & 127;
while (c & 128) {
ofs += 1;
if (!ofs || ofs & ~(~0UL >> 7))
die("delta base offset overflow in pack for %s",
sha1_to_hex(entry->sha1));
- c = buf[used++];
+ c = buf[used_0++];
ofs = (ofs << 7) + (c & 127);
}
if (ofs >= entry->in_pack_offset)
sha1_to_hex(entry->sha1));
ofs = entry->in_pack_offset - ofs;
base_name = find_packed_object_name(p, ofs);
+ used += used_0;
break;
default:
base_name = NULL;
if (base_name)
base_entry = locate_object_entry(base_name);
}
- unuse_packed_git(p);
+ unuse_pack(&w_curs);
entry->in_pack_header_size = used;
if (base_entry) {
* on an earlier try, but only when reusing delta data.
*/
if (!no_reuse_delta && trg_entry->in_pack &&
- trg_entry->in_pack == src_entry->in_pack)
+ trg_entry->in_pack == src_entry->in_pack &&
+ trg_entry->in_pack_type != OBJ_REF_DELTA &&
+ trg_entry->in_pack_type != OBJ_OFS_DELTA)
return 0;
/*
local = 1;
continue;
}
- if (!strcmp("--progress", arg)) {
- progress = 1;
- continue;
- }
if (!strcmp("--incremental", arg)) {
incremental = 1;
continue;
}
- if (!strncmp("--window=", arg, 9)) {
+ if (!prefixcmp(arg, "--window=")) {
char *end;
window = strtoul(arg+9, &end, 0);
if (!arg[9] || *end)
usage(pack_usage);
continue;
}
- if (!strncmp("--depth=", arg, 8)) {
+ if (!prefixcmp(arg, "--depth=")) {
char *end;
depth = strtoul(arg+8, &end, 0);
if (!arg[8] || *end)
progress = 1;
continue;
}
+ if (!strcmp("--all-progress", arg)) {
+ progress = 2;
+ continue;
+ }
if (!strcmp("-q", arg)) {
progress = 0;
continue;
continue;
}
if (!strcmp("--unpacked", arg) ||
- !strncmp("--unpacked=", arg, 11) ||
+ !prefixcmp(arg, "--unpacked=") ||
+ !strcmp("--reflog", arg) ||
!strcmp("--all", arg)) {
use_internal_rev_list = 1;
if (ARRAY_SIZE(rp_av) - 1 <= rp_ac)
else {
if (nr_result)
prepare_pack(window, depth);
- if (progress && pack_to_stdout) {
+ if (progress == 1 && pack_to_stdout) {
/* the other end usually displays progress itself */
struct itimerval v = {{0,},};
setitimer(ITIMER_REAL, &v, NULL);
}
}
if (progress)
- fprintf(stderr, "Total %d, written %d (delta %d), reused %d (delta %d)\n",
- nr_result, written, written_delta, reused, reused_delta);
+ fprintf(stderr, "Total %d (delta %d), reused %d (delta %d)\n",
+ written, written_delta, reused, reused_delta);
return 0;
}