Merge branch 'lt/maint-wrap-zlib'
authorJunio C Hamano <gitster@pobox.com>
Thu, 22 Jan 2009 00:55:17 +0000 (16:55 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 22 Jan 2009 00:55:17 +0000 (16:55 -0800)
* lt/maint-wrap-zlib:
Wrap inflate and other zlib routines for better error reporting

Conflicts:
http-push.c
http-walker.c
sha1_file.c

1  2 
builtin-apply.c
builtin-pack-objects.c
builtin-unpack-objects.c
cache.h
http-push.c
http-walker.c
index-pack.c
sha1_file.c
diff --combined builtin-apply.c
index 6d5a60214ca5de6cb4376a66503cb8149b7ef997,eface9793ad9d4dd736161c54b9ee4a8af461218..b415daf07edacacd8bda0527bb5ed229be91c861
@@@ -14,7 -14,6 +14,7 @@@
  #include "builtin.h"
  #include "string-list.h"
  #include "dir.h"
 +#include "parse-options.h"
  
  /*
   *  --check turns on checking that the working tree matches the
@@@ -46,11 -45,9 +46,11 @@@ static int apply_verbosely
  static int no_add;
  static const char *fake_ancestor;
  static int line_termination = '\n';
 -static unsigned long p_context = ULONG_MAX;
 -static const char apply_usage[] =
 -"git apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|fix|error|error-all>] <patch>...";
 +static unsigned int p_context = UINT_MAX;
 +static const char * const apply_usage[] = {
 +      "git apply [options] [<patch>...]",
 +      NULL
 +};
  
  static enum ws_error_action {
        nowarn_ws_error,
@@@ -64,8 -61,6 +64,8 @@@ static int applied_after_fixing_ws
  static const char *patch_input_file;
  static const char *root;
  static int root_len;
 +static int read_stdin = 1;
 +static int options;
  
  static void parse_whitespace_option(const char *option)
  {
@@@ -326,12 -321,13 +326,12 @@@ static char *find_name(const char *line
        const char *start = line;
  
        if (*line == '"') {
 -              struct strbuf name;
 +              struct strbuf name = STRBUF_INIT;
  
                /*
                 * Proposed "new-style" GNU patch/diff format; see
                 * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
                 */
 -              strbuf_init(&name, 0);
                if (!unquote_c_style(&name, line, NULL)) {
                        char *cp;
  
@@@ -635,7 -631,7 +635,7 @@@ static int gitdiff_index(const char *li
        memcpy(patch->new_sha1_prefix, line, len);
        patch->new_sha1_prefix[len] = 0;
        if (*ptr == ' ')
 -              patch->new_mode = patch->old_mode = strtoul(ptr+1, NULL, 8);
 +              patch->old_mode = strtoul(ptr+1, NULL, 8);
        return 0;
  }
  
@@@ -679,8 -675,11 +679,8 @@@ static char *git_header_name(char *line
  
        if (*line == '"') {
                const char *cp;
 -              struct strbuf first;
 -              struct strbuf sp;
 -
 -              strbuf_init(&first, 0);
 -              strbuf_init(&sp, 0);
 +              struct strbuf first = STRBUF_INIT;
 +              struct strbuf sp = STRBUF_INIT;
  
                if (unquote_c_style(&first, line, &second))
                        goto free_and_fail1;
         */
        for (second = name; second < line + llen; second++) {
                if (*second == '"') {
 -                      struct strbuf sp;
 +                      struct strbuf sp = STRBUF_INIT;
                        const char *np;
  
 -                      strbuf_init(&sp, 0);
                        if (unquote_c_style(&sp, second, NULL))
                                goto free_and_fail2;
  
@@@ -1258,8 -1258,9 +1258,9 @@@ static char *inflate_it(const void *dat
        stream.avail_in = size;
        stream.next_out = out = xmalloc(inflated_size);
        stream.avail_out = inflated_size;
-       inflateInit(&stream);
-       st = inflate(&stream, Z_FINISH);
+       git_inflate_init(&stream);
+       st = git_inflate(&stream, Z_FINISH);
+       git_inflate_end(&stream);
        if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
                free(out);
                return NULL;
@@@ -1515,10 -1516,11 +1516,10 @@@ static const char minuses[]
  
  static void show_stats(struct patch *patch)
  {
 -      struct strbuf qname;
 +      struct strbuf qname = STRBUF_INIT;
        char *cp = patch->new_name ? patch->new_name : patch->old_name;
        int max, add, del;
  
 -      strbuf_init(&qname, 0);
        quote_c_style(cp, &qname, NULL, 0);
  
        /*
@@@ -1564,8 -1566,10 +1565,8 @@@ static int read_old_data(struct stat *s
  {
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
 -              strbuf_grow(buf, st->st_size);
 -              if (readlink(path, buf->buf, st->st_size) != st->st_size)
 -                      return -1;
 -              strbuf_setlen(buf, st->st_size);
 +              if (strbuf_readlink(buf, path, st->st_size) < 0)
 +                      return error("unable to read symlink %s", path);
                return 0;
        case S_IFREG:
                if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
@@@ -2296,12 -2300,14 +2297,12 @@@ static void add_to_fn_table(struct patc
  
  static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
  {
 -      struct strbuf buf;
 +      struct strbuf buf = STRBUF_INIT;
        struct image image;
        size_t len;
        char *img;
        struct patch *tpatch;
  
 -      strbuf_init(&buf, 0);
 -
        if (!(patch->is_copy || patch->is_rename) &&
            ((tpatch = in_fn_table(patch->old_name)) != NULL)) {
                if (tpatch == (struct patch *) -1) {
@@@ -2452,8 -2458,6 +2453,8 @@@ static int check_preimage(struct patch 
        if (st_mode != patch->old_mode)
                fprintf(stderr, "warning: %s has type %o, expected %o\n",
                        old_name, st_mode, patch->old_mode);
 +      if (!patch->new_mode)
 +              patch->new_mode = st_mode;
        return 0;
  
   is_new:
@@@ -2783,7 -2787,7 +2784,7 @@@ static void add_index_file(const char *
  static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
  {
        int fd;
 -      struct strbuf nbuf;
 +      struct strbuf nbuf = STRBUF_INIT;
  
        if (S_ISGITLINK(mode)) {
                struct stat st;
        if (fd < 0)
                return -1;
  
 -      strbuf_init(&nbuf, 0);
        if (convert_to_working_tree(path, buf, size, &nbuf)) {
                size = nbuf.len;
                buf  = nbuf.buf;
@@@ -2992,45 -2997,29 +2993,45 @@@ static int write_out_results(struct pat
  
  static struct lock_file lock_file;
  
 -static struct excludes {
 -      struct excludes *next;
 -      const char *path;
 -} *excludes;
 +static struct string_list limit_by_name;
 +static int has_include;
 +static void add_name_limit(const char *name, int exclude)
 +{
 +      struct string_list_item *it;
 +
 +      it = string_list_append(name, &limit_by_name);
 +      it->util = exclude ? NULL : (void *) 1;
 +}
  
  static int use_patch(struct patch *p)
  {
        const char *pathname = p->new_name ? p->new_name : p->old_name;
 -      struct excludes *x = excludes;
 -      while (x) {
 -              if (fnmatch(x->path, pathname, 0) == 0)
 -                      return 0;
 -              x = x->next;
 -      }
 +      int i;
 +
 +      /* Paths outside are not touched regardless of "--include" */
        if (0 < prefix_length) {
                int pathlen = strlen(pathname);
                if (pathlen <= prefix_length ||
                    memcmp(prefix, pathname, prefix_length))
                        return 0;
        }
 -      return 1;
 +
 +      /* See if it matches any of exclude/include rule */
 +      for (i = 0; i < limit_by_name.nr; i++) {
 +              struct string_list_item *it = &limit_by_name.items[i];
 +              if (!fnmatch(it->string, pathname, 0))
 +                      return (it->util != NULL);
 +      }
 +
 +      /*
 +       * If we had any include, a path that does not match any rule is
 +       * not used.  Otherwise, we saw bunch of exclude rules (or none)
 +       * and such a path is used.
 +       */
 +      return !has_include;
  }
  
 +
  static void prefix_one(char **name)
  {
        char *old_name = *name;
@@@ -3063,12 -3052,13 +3064,12 @@@ static void prefix_patches(struct patc
  static int apply_patch(int fd, const char *filename, int options)
  {
        size_t offset;
 -      struct strbuf buf;
 +      struct strbuf buf = STRBUF_INIT;
        struct patch *list = NULL, **listp = &list;
        int skipped_patch = 0;
  
        /* FIXME - memory leak when using multiple patch files as inputs */
        memset(&fn_table, 0, sizeof(struct string_list));
 -      strbuf_init(&buf, 0);
        patch_input_file = filename;
        read_patch_file(&buf, fd);
        offset = 0;
@@@ -3142,160 -3132,149 +3143,160 @@@ static int git_apply_config(const char 
        return git_default_config(var, value, cb);
  }
  
 +static int option_parse_exclude(const struct option *opt,
 +                              const char *arg, int unset)
 +{
 +      add_name_limit(arg, 1);
 +      return 0;
 +}
 +
 +static int option_parse_include(const struct option *opt,
 +                              const char *arg, int unset)
 +{
 +      add_name_limit(arg, 0);
 +      has_include = 1;
 +      return 0;
 +}
 +
 +static int option_parse_p(const struct option *opt,
 +                        const char *arg, int unset)
 +{
 +      p_value = atoi(arg);
 +      p_value_known = 1;
 +      return 0;
 +}
 +
 +static int option_parse_z(const struct option *opt,
 +                        const char *arg, int unset)
 +{
 +      if (unset)
 +              line_termination = '\n';
 +      else
 +              line_termination = 0;
 +      return 0;
 +}
 +
 +static int option_parse_whitespace(const struct option *opt,
 +                                 const char *arg, int unset)
 +{
 +      const char **whitespace_option = opt->value;
 +
 +      *whitespace_option = arg;
 +      parse_whitespace_option(arg);
 +      return 0;
 +}
 +
 +static int option_parse_directory(const struct option *opt,
 +                                const char *arg, int unset)
 +{
 +      root_len = strlen(arg);
 +      if (root_len && arg[root_len - 1] != '/') {
 +              char *new_root;
 +              root = new_root = xmalloc(root_len + 2);
 +              strcpy(new_root, arg);
 +              strcpy(new_root + root_len++, "/");
 +      } else
 +              root = arg;
 +      return 0;
 +}
  
  int cmd_apply(int argc, const char **argv, const char *unused_prefix)
  {
        int i;
 -      int read_stdin = 1;
 -      int options = 0;
        int errs = 0;
        int is_not_gitdir;
 +      int binary;
 +      int force_apply = 0;
  
        const char *whitespace_option = NULL;
  
 +      struct option builtin_apply_options[] = {
 +              { OPTION_CALLBACK, 0, "exclude", NULL, "path",
 +                      "donĀ“t apply changes matching the given path",
 +                      0, option_parse_exclude },
 +              { OPTION_CALLBACK, 0, "include", NULL, "path",
 +                      "apply changes matching the given path",
 +                      0, option_parse_include },
 +              { OPTION_CALLBACK, 'p', NULL, NULL, "num",
 +                      "remove <num> leading slashes from traditional diff paths",
 +                      0, option_parse_p },
 +              OPT_BOOLEAN(0, "no-add", &no_add,
 +                      "ignore additions made by the patch"),
 +              OPT_BOOLEAN(0, "stat", &diffstat,
 +                      "instead of applying the patch, output diffstat for the input"),
 +              OPT_BOOLEAN(0, "allow-binary-replacement", &binary,
 +                      "now no-op"),
 +              OPT_BOOLEAN(0, "binary", &binary,
 +                      "now no-op"),
 +              OPT_BOOLEAN(0, "numstat", &numstat,
 +                      "shows number of added and deleted lines in decimal notation"),
 +              OPT_BOOLEAN(0, "summary", &summary,
 +                      "instead of applying the patch, output a summary for the input"),
 +              OPT_BOOLEAN(0, "check", &check,
 +                      "instead of applying the patch, see if the patch is applicable"),
 +              OPT_BOOLEAN(0, "index", &check_index,
 +                      "make sure the patch is applicable to the current index"),
 +              OPT_BOOLEAN(0, "cached", &cached,
 +                      "apply a patch without touching the working tree"),
 +              OPT_BOOLEAN(0, "apply", &force_apply,
 +                      "also apply the patch (use with --stat/--summary/--check)"),
 +              OPT_STRING(0, "build-fake-ancestor", &fake_ancestor, "file",
 +                      "build a temporary index based on embedded index information"),
 +              { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
 +                      "paths are separated with NUL character",
 +                      PARSE_OPT_NOARG, option_parse_z },
 +              OPT_INTEGER('C', NULL, &p_context,
 +                              "ensure at least <n> lines of context match"),
 +              { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, "action",
 +                      "detect new or modified lines that have whitespace errors",
 +                      0, option_parse_whitespace },
 +              OPT_BOOLEAN('R', "reverse", &apply_in_reverse,
 +                      "apply the patch in reverse"),
 +              OPT_BOOLEAN(0, "unidiff-zero", &unidiff_zero,
 +                      "don't expect at least one line of context"),
 +              OPT_BOOLEAN(0, "reject", &apply_with_reject,
 +                      "leave the rejected hunks in corresponding *.rej files"),
 +              OPT__VERBOSE(&apply_verbosely),
 +              OPT_BIT(0, "inaccurate-eof", &options,
 +                      "tolerate incorrectly detected missing new-line at the end of file",
 +                      INACCURATE_EOF),
 +              OPT_BIT(0, "recount", &options,
 +                      "do not trust the line counts in the hunk headers",
 +                      RECOUNT),
 +              { OPTION_CALLBACK, 0, "directory", NULL, "root",
 +                      "prepend <root> to all filenames",
 +                      0, option_parse_directory },
 +              OPT_END()
 +      };
 +
        prefix = setup_git_directory_gently(&is_not_gitdir);
        prefix_length = prefix ? strlen(prefix) : 0;
        git_config(git_apply_config, NULL);
        if (apply_default_whitespace)
                parse_whitespace_option(apply_default_whitespace);
  
 -      for (i = 1; i < argc; i++) {
 +      argc = parse_options(argc, argv, builtin_apply_options,
 +                      apply_usage, 0);
 +      if (apply_with_reject)
 +              apply = apply_verbosely = 1;
 +      if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
 +              apply = 0;
 +      if (check_index && is_not_gitdir)
 +              die("--index outside a repository");
 +      if (cached) {
 +              if (is_not_gitdir)
 +                      die("--cached outside a repository");
 +              check_index = 1;
 +      }
 +      for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
 -              char *end;
                int fd;
  
                if (!strcmp(arg, "-")) {
                        errs |= apply_patch(0, "<stdin>", options);
                        read_stdin = 0;
                        continue;
 -              }
 -              if (!prefixcmp(arg, "--exclude=")) {
 -                      struct excludes *x = xmalloc(sizeof(*x));
 -                      x->path = arg + 10;
 -                      x->next = excludes;
 -                      excludes = x;
 -                      continue;
 -              }
 -              if (!prefixcmp(arg, "-p")) {
 -                      p_value = atoi(arg + 2);
 -                      p_value_known = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--no-add")) {
 -                      no_add = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--stat")) {
 -                      apply = 0;
 -                      diffstat = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--allow-binary-replacement") ||
 -                  !strcmp(arg, "--binary")) {
 -                      continue; /* now no-op */
 -              }
 -              if (!strcmp(arg, "--numstat")) {
 -                      apply = 0;
 -                      numstat = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--summary")) {
 -                      apply = 0;
 -                      summary = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--check")) {
 -                      apply = 0;
 -                      check = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--index")) {
 -                      if (is_not_gitdir)
 -                              die("--index outside a repository");
 -                      check_index = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--cached")) {
 -                      if (is_not_gitdir)
 -                              die("--cached outside a repository");
 -                      check_index = 1;
 -                      cached = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--apply")) {
 -                      apply = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--build-fake-ancestor")) {
 -                      apply = 0;
 -                      if (++i >= argc)
 -                              die ("need a filename");
 -                      fake_ancestor = argv[i];
 -                      continue;
 -              }
 -              if (!strcmp(arg, "-z")) {
 -                      line_termination = 0;
 -                      continue;
 -              }
 -              if (!prefixcmp(arg, "-C")) {
 -                      p_context = strtoul(arg + 2, &end, 0);
 -                      if (*end != '\0')
 -                              die("unrecognized context count '%s'", arg + 2);
 -                      continue;
 -              }
 -              if (!prefixcmp(arg, "--whitespace=")) {
 -                      whitespace_option = arg + 13;
 -                      parse_whitespace_option(arg + 13);
 -                      continue;
 -              }
 -              if (!strcmp(arg, "-R") || !strcmp(arg, "--reverse")) {
 -                      apply_in_reverse = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--unidiff-zero")) {
 -                      unidiff_zero = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--reject")) {
 -                      apply = apply_with_reject = apply_verbosely = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose")) {
 -                      apply_verbosely = 1;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--inaccurate-eof")) {
 -                      options |= INACCURATE_EOF;
 -                      continue;
 -              }
 -              if (!strcmp(arg, "--recount")) {
 -                      options |= RECOUNT;
 -                      continue;
 -              }
 -              if (!prefixcmp(arg, "--directory=")) {
 -                      arg += strlen("--directory=");
 -                      root_len = strlen(arg);
 -                      if (root_len && arg[root_len - 1] != '/') {
 -                              char *new_root;
 -                              root = new_root = xmalloc(root_len + 2);
 -                              strcpy(new_root, arg);
 -                              strcpy(new_root + root_len++, "/");
 -                      } else
 -                              root = arg;
 -                      continue;
 -              }
 -              if (0 < prefix_length)
 +              } else if (0 < prefix_length)
                        arg = prefix_filename(prefix, prefix_length, arg);
  
                fd = open(arg, O_RDONLY);
diff --combined builtin-pack-objects.c
index e8515348be397fdf1d8201c5d957f2a5f2dbb334,85af80f229ef2f1be78ba1341edcbfeb5d0fdbff..cb51916fe33a904b8ab11b7c43dfe3a84ec11705
@@@ -78,7 -78,7 +78,7 @@@ static int progress = 1
  static int window = 10;
  static uint32_t pack_size_limit, pack_size_limit_cfg;
  static int depth = 50;
 -static int delta_search_threads = 1;
 +static int delta_search_threads;
  static int pack_to_stdout;
  static int num_preferred_base;
  static struct progress *progress_state;
@@@ -195,16 -195,16 +195,16 @@@ static int check_pack_inflate(struct pa
        int st;
  
        memset(&stream, 0, sizeof(stream));
-       inflateInit(&stream);
+       git_inflate_init(&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);
+               st = git_inflate(&stream, Z_FINISH);
                offset += stream.next_in - in;
        } while (st == Z_OK || st == Z_BUF_ERROR);
-       inflateEnd(&stream);
+       git_inflate_end(&stream);
        return (st == Z_STREAM_END &&
                stream.total_out == expect &&
                stream.total_in == len) ? 0 : -1;
@@@ -286,7 -286,6 +286,7 @@@ static unsigned long write_object(struc
                                 */
  
        if (!to_reuse) {
 +              no_reuse:
                if (!usable_delta) {
                        buf = read_sha1_file(entry->idx.sha1, &type, &size);
                        if (!buf)
                struct revindex_entry *revidx;
                off_t offset;
  
 -              if (entry->delta) {
 +              if (entry->delta)
                        type = (allow_ofs_delta && entry->delta->idx.offset) ?
                                OBJ_OFS_DELTA : OBJ_REF_DELTA;
 -                      reused_delta++;
 -              }
                hdrlen = encode_header(type, entry->size, header);
 +
                offset = entry->in_pack_offset;
                revidx = find_pack_revindex(p, offset);
                datalen = revidx[1].offset - offset;
                if (!pack_to_stdout && p->index_version > 1 &&
 -                  check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))
 -                      die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
 +                  check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
 +                      error("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
 +                      unuse_pack(&w_curs);
 +                      goto no_reuse;
 +              }
 +
                offset += entry->in_pack_header_size;
                datalen -= entry->in_pack_header_size;
 +              if (!pack_to_stdout && p->index_version == 1 &&
 +                  check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) {
 +                      error("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
 +                      unuse_pack(&w_curs);
 +                      goto no_reuse;
 +              }
 +
                if (type == OBJ_OFS_DELTA) {
                        off_t ofs = entry->idx.offset - entry->delta->idx.offset;
                        unsigned pos = sizeof(dheader) - 1;
                        dheader[pos] = ofs & 127;
                        while (ofs >>= 7)
                                dheader[--pos] = 128 | (--ofs & 127);
 -                      if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit)
 +                      if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
 +                              unuse_pack(&w_curs);
                                return 0;
 +                      }
                        sha1write(f, header, hdrlen);
                        sha1write(f, dheader + pos, sizeof(dheader) - pos);
                        hdrlen += sizeof(dheader) - pos;
 +                      reused_delta++;
                } else if (type == OBJ_REF_DELTA) {
 -                      if (limit && hdrlen + 20 + datalen + 20 >= limit)
 +                      if (limit && hdrlen + 20 + datalen + 20 >= limit) {
 +                              unuse_pack(&w_curs);
                                return 0;
 +                      }
                        sha1write(f, header, hdrlen);
                        sha1write(f, entry->delta->idx.sha1, 20);
                        hdrlen += 20;
 +                      reused_delta++;
                } else {
 -                      if (limit && hdrlen + datalen + 20 >= limit)
 +                      if (limit && hdrlen + datalen + 20 >= limit) {
 +                              unuse_pack(&w_curs);
                                return 0;
 +                      }
                        sha1write(f, header, hdrlen);
                }
 -
 -              if (!pack_to_stdout && p->index_version == 1 &&
 -                  check_pack_inflate(p, &w_curs, offset, datalen, entry->size))
 -                      die("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
                copy_pack_data(f, p, &w_curs, offset, datalen);
                unuse_pack(&w_curs);
                reused++;
@@@ -1032,11 -1017,9 +1032,11 @@@ static void check_object(struct object_
                 * We want in_pack_type even if we do not reuse delta
                 * since non-delta representations could still be reused.
                 */
 -              used = unpack_object_header_gently(buf, avail,
 +              used = unpack_object_header_buffer(buf, avail,
                                                   &entry->in_pack_type,
                                                   &entry->size);
 +              if (used == 0)
 +                      goto give_up;
  
                /*
                 * Determine if this is a delta and if so whether we can
                        /* Not a delta hence we've already got all we need. */
                        entry->type = entry->in_pack_type;
                        entry->in_pack_header_size = used;
 +                      if (entry->type < OBJ_COMMIT || entry->type > OBJ_BLOB)
 +                              goto give_up;
                        unuse_pack(&w_curs);
                        return;
                case OBJ_REF_DELTA:
                        ofs = c & 127;
                        while (c & 128) {
                                ofs += 1;
 -                              if (!ofs || MSB(ofs, 7))
 -                                      die("delta base offset overflow in pack for %s",
 -                                          sha1_to_hex(entry->idx.sha1));
 +                              if (!ofs || MSB(ofs, 7)) {
 +                                      error("delta base offset overflow in pack for %s",
 +                                            sha1_to_hex(entry->idx.sha1));
 +                                      goto give_up;
 +                              }
                                c = buf[used_0++];
                                ofs = (ofs << 7) + (c & 127);
                        }
 -                      if (ofs >= entry->in_pack_offset)
 -                              die("delta base offset out of bound for %s",
 -                                  sha1_to_hex(entry->idx.sha1));
                        ofs = entry->in_pack_offset - ofs;
 +                      if (ofs <= 0 || ofs >= entry->in_pack_offset) {
 +                              error("delta base offset out of bound for %s",
 +                                    sha1_to_hex(entry->idx.sha1));
 +                              goto give_up;
 +                      }
                        if (reuse_delta && !entry->preferred_base) {
                                struct revindex_entry *revidx;
                                revidx = find_pack_revindex(p, ofs);
 +                              if (!revidx)
 +                                      goto give_up;
                                base_ref = nth_packed_object_sha1(p, revidx->nr);
                        }
                        entry->in_pack_header_size = used + used_0;
                         */
                        entry->type = entry->in_pack_type;
                        entry->delta = base_entry;
 +                      entry->delta_size = entry->size;
                        entry->delta_sibling = base_entry->delta_child;
                        base_entry->delta_child = entry;
                        unuse_pack(&w_curs);
                         */
                        entry->size = get_size_from_delta(p, &w_curs,
                                        entry->in_pack_offset + entry->in_pack_header_size);
 +                      if (entry->size == 0)
 +                              goto give_up;
                        unuse_pack(&w_curs);
                        return;
                }
                 * with sha1_object_info() to find about the object type
                 * at this point...
                 */
 +              give_up:
                unuse_pack(&w_curs);
        }
  
@@@ -1413,10 -1384,12 +1413,10 @@@ static void find_deltas(struct object_e
                        int window, int depth, unsigned *processed)
  {
        uint32_t i, idx = 0, count = 0;
 -      unsigned int array_size = window * sizeof(struct unpacked);
        struct unpacked *array;
        unsigned long mem_usage = 0;
  
 -      array = xmalloc(array_size);
 -      memset(array, 0, array_size);
 +      array = xcalloc(window, sizeof(struct unpacked));
  
        for (;;) {
                struct object_entry *entry;
@@@ -1612,18 -1585,11 +1612,18 @@@ static void ll_find_deltas(struct objec
                find_deltas(list, &list_size, window, depth, processed);
                return;
        }
 +      if (progress > pack_to_stdout)
 +              fprintf(stderr, "Delta compression using %d threads.\n",
 +                              delta_search_threads);
  
        /* Partition the work amongst work threads. */
        for (i = 0; i < delta_search_threads; i++) {
                unsigned sub_size = list_size / (delta_search_threads - i);
  
 +              /* don't use too small segments or no deltas will be found */
 +              if (sub_size < 2*window && i+1 < delta_search_threads)
 +                      sub_size = 0;
 +
                p[i].window = window;
                p[i].depth = depth;
                p[i].processed = processed;
@@@ -1749,16 -1715,6 +1749,16 @@@ static void prepare_pack(int window, in
  
        get_object_details();
  
 +      /*
 +       * If we're locally repacking then we need to be doubly careful
 +       * from now on in order to make sure no stealth corruption gets
 +       * propagated to the new pack.  Clients receiving streamed packs
 +       * should validate everything they get anyway so no need to incur
 +       * the additional cost here in that case.
 +       */
 +      if (!pack_to_stdout)
 +              do_check_packed_object_crc = 1;
 +
        if (!nr_objects || !window || !depth)
                return;
  
                        if (entry->type < 0)
                                die("unable to get type of object %s",
                                    sha1_to_hex(entry->idx.sha1));
 +              } else {
 +                      if (entry->type < 0) {
 +                              /*
 +                               * This object is not found, but we
 +                               * don't have to include it anyway.
 +                               */
 +                              continue;
 +                      }
                }
  
                delta_list[n++] = entry;
diff --combined builtin-unpack-objects.c
index 47ed610677fe47f855beaac02f40fa84d132455e,41d00d36cd10cbbb775848c1a7e58330f09891b0..9a773239cabab9998bcea829c0fb2abea9bdb8e8
@@@ -19,7 -19,7 +19,7 @@@ static const char unpack_usage[] = "gi
  static unsigned char buffer[4096];
  static unsigned int offset, len;
  static off_t consumed_bytes;
 -static SHA_CTX ctx;
 +static git_SHA_CTX ctx;
  
  /*
   * When running under --strict mode, objects whose reachability are
@@@ -59,7 -59,7 +59,7 @@@ static void *fill(int min
        if (min > sizeof(buffer))
                die("cannot fill %d bytes", min);
        if (offset) {
 -              SHA1_Update(&ctx, buffer, offset);
 +              git_SHA1_Update(&ctx, buffer, offset);
                memmove(buffer, buffer + offset, len);
                offset = 0;
        }
@@@ -99,10 -99,10 +99,10 @@@ static void *get_data(unsigned long siz
        stream.avail_out = size;
        stream.next_in = fill(1);
        stream.avail_in = len;
-       inflateInit(&stream);
+       git_inflate_init(&stream);
  
        for (;;) {
-               int ret = inflate(&stream, 0);
+               int ret = git_inflate(&stream, 0);
                use(len - stream.avail_in);
                if (stream.total_out == size && ret == Z_STREAM_END)
                        break;
                stream.next_in = fill(1);
                stream.avail_in = len;
        }
-       inflateEnd(&stream);
+       git_inflate_end(&stream);
        return buf;
  }
  
@@@ -370,8 -370,6 +370,8 @@@ static void unpack_delta_entry(enum obj
                        base_offset = (base_offset << 7) + (c & 127);
                }
                base_offset = obj_list[nr].offset - base_offset;
 +              if (base_offset <= 0 || base_offset >= obj_list[nr].offset)
 +                      die("offset value out of bound for delta base object");
  
                delta_data = get_data(delta_size);
                if (dry_run || !delta_data) {
@@@ -479,7 -477,8 +479,7 @@@ static void unpack_all(void
  
        if (!quiet)
                progress = start_progress("Unpacking objects", nr_objects);
 -      obj_list = xmalloc(nr_objects * sizeof(*obj_list));
 -      memset(obj_list, 0, nr_objects * sizeof(*obj_list));
 +      obj_list = xcalloc(nr_objects, sizeof(*obj_list));
        for (i = 0; i < nr_objects; i++) {
                unpack_one(i);
                display_progress(progress, i + 1);
@@@ -540,10 -539,10 +540,10 @@@ int cmd_unpack_objects(int argc, const 
                /* We don't take any non-flag arguments now.. Maybe some day */
                usage(unpack_usage);
        }
 -      SHA1_Init(&ctx);
 +      git_SHA1_Init(&ctx);
        unpack_all();
 -      SHA1_Update(&ctx, buffer, offset);
 -      SHA1_Final(sha1, &ctx);
 +      git_SHA1_Update(&ctx, buffer, offset);
 +      git_SHA1_Final(sha1, &ctx);
        if (strict)
                write_rest();
        if (hashcmp(fill(20), sha1))
diff --combined cache.h
index 8e1af2669bd2e9af03a73b7058bec014d4d3a3aa,17ce4441b6a00e7f86774928954385fefa4d60dc..8d965b8c981d80a252dd69ca32d8e44fa545177a
+++ b/cache.h
@@@ -6,18 -6,16 +6,22 @@@
  #include "hash.h"
  
  #include SHA1_HEADER
 -#include <zlib.h>
 +#ifndef git_SHA_CTX
 +#define git_SHA_CTX   SHA_CTX
 +#define git_SHA1_Init SHA1_Init
 +#define git_SHA1_Update       SHA1_Update
 +#define git_SHA1_Final        SHA1_Final
 +#endif
  
 +#include <zlib.h>
  #if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
  #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
  #endif
  
+ void git_inflate_init(z_streamp strm);
+ void git_inflate_end(z_streamp strm);
+ int git_inflate(z_streamp strm, int flush);
  #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
  #define DTYPE(de)     ((de)->d_type)
  #else
@@@ -115,26 -113,6 +119,26 @@@ struct ondisk_cache_entry 
        char name[FLEX_ARRAY]; /* more */
  };
  
 +/*
 + * This struct is used when CE_EXTENDED bit is 1
 + * The struct must match ondisk_cache_entry exactly from
 + * ctime till flags
 + */
 +struct ondisk_cache_entry_extended {
 +      struct cache_time ctime;
 +      struct cache_time mtime;
 +      unsigned int dev;
 +      unsigned int ino;
 +      unsigned int mode;
 +      unsigned int uid;
 +      unsigned int gid;
 +      unsigned int size;
 +      unsigned char sha1[20];
 +      unsigned short flags;
 +      unsigned short flags2;
 +      char name[FLEX_ARRAY]; /* more */
 +};
 +
  struct cache_entry {
        unsigned int ce_ctime;
        unsigned int ce_mtime;
  
  #define CE_NAMEMASK  (0x0fff)
  #define CE_STAGEMASK (0x3000)
 +#define CE_EXTENDED  (0x4000)
  #define CE_VALID     (0x8000)
  #define CE_STAGESHIFT 12
  
 -/* In-memory only */
 +/*
 + * Range 0xFFFF0000 in ce_flags is divided into
 + * two parts: in-memory flags and on-disk ones.
 + * Flags in CE_EXTENDED_FLAGS will get saved on-disk
 + * if you want to save a new flag, add it in
 + * CE_EXTENDED_FLAGS
 + *
 + * In-memory only flags
 + */
  #define CE_UPDATE    (0x10000)
  #define CE_REMOVE    (0x20000)
  #define CE_UPTODATE  (0x40000)
  #define CE_HASHED    (0x100000)
  #define CE_UNHASHED  (0x200000)
  
 +/*
 + * Extended on-disk flags
 + */
 +#define CE_INTENT_TO_ADD 0x20000000
 +/* CE_EXTENDED2 is for future extension */
 +#define CE_EXTENDED2 0x80000000
 +
 +#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD)
 +
 +/*
 + * Safeguard to avoid saving wrong flags:
 + *  - CE_EXTENDED2 won't get saved until its semantic is known
 + *  - Bits in 0x0000FFFF have been saved in ce_flags already
 + *  - Bits in 0x003F0000 are currently in-memory flags
 + */
 +#if CE_EXTENDED_FLAGS & 0x803FFFFF
 +#error "CE_EXTENDED_FLAGS out of range"
 +#endif
 +
  /*
   * Copy the sha1 and stat state of a cache entry from one to
   * another. But we never change the name, or the hash state!
@@@ -224,9 -174,7 +228,9 @@@ static inline size_t ce_namelen(const s
  }
  
  #define ce_size(ce) cache_entry_size(ce_namelen(ce))
 -#define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce))
 +#define ondisk_ce_size(ce) (((ce)->ce_flags & CE_EXTENDED) ? \
 +                          ondisk_cache_entry_extended_size(ce_namelen(ce)) : \
 +                          ondisk_cache_entry_size(ce_namelen(ce)))
  #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
  #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
  #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
@@@ -269,10 -217,8 +273,10 @@@ static inline int ce_to_dtype(const str
        (S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
        S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)
  
 -#define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 -#define ondisk_cache_entry_size(len) ((offsetof(struct ondisk_cache_entry,name) + (len) + 8) & ~7)
 +#define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
 +#define cache_entry_size(len) flexible_size(cache_entry,len)
 +#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len)
 +#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len)
  
  struct index_state {
        struct cache_entry **cache;
@@@ -313,7 -259,6 +317,7 @@@ static inline void remove_name_hash(str
  
  #define read_cache() read_index(&the_index)
  #define read_cache_from(path) read_index_from(&the_index, (path))
 +#define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec))
  #define is_cache_unborn() is_index_unborn(&the_index)
  #define read_cache_unmerged() read_index_unmerged(&the_index)
  #define write_cache(newfd, cache, entries) write_index(&the_index, (newfd))
@@@ -373,7 -318,6 +377,7 @@@ extern int is_bare_repository(void)
  extern int is_inside_git_dir(void);
  extern char *git_work_tree_cfg;
  extern int is_inside_work_tree(void);
 +extern int have_git_dir(void);
  extern const char *get_git_dir(void);
  extern char *get_object_directory(void);
  extern char *get_index_file(void);
@@@ -420,7 -364,6 +424,7 @@@ extern int init_db(const char *template
  
  /* Initialize and use the cache information */
  extern int read_index(struct index_state *);
 +extern int read_index_preload(struct index_state *, const char **pathspec);
  extern int read_index_from(struct index_state *, const char *path);
  extern int is_index_unborn(struct index_state *);
  extern int read_index_unmerged(struct index_state *);
@@@ -434,7 -377,6 +438,7 @@@ extern int index_name_pos(const struct 
  #define ADD_CACHE_OK_TO_REPLACE 2     /* Ok to replace file/directory */
  #define ADD_CACHE_SKIP_DFCHECK 4      /* Ok to skip DF conflict checks */
  #define ADD_CACHE_JUST_APPEND 8               /* Append only; tree.c::read_tree() */
 +#define ADD_CACHE_NEW_ONLY 16         /* Do not replace existing ones */
  extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
  extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
  extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
@@@ -443,8 -385,6 +447,8 @@@ extern int remove_file_from_index(struc
  #define ADD_CACHE_VERBOSE 1
  #define ADD_CACHE_PRETEND 2
  #define ADD_CACHE_IGNORE_ERRORS       4
 +#define ADD_CACHE_IGNORE_REMOVAL 8
 +#define ADD_CACHE_INTENT 16
  extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
  extern int add_file_to_index(struct index_state *, const char *path, int flags);
  extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
@@@ -460,6 -400,7 +464,6 @@@ extern int ie_modified(const struct ind
  
  extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
  extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
 -extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
  extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
  extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
  
@@@ -511,7 -452,6 +515,7 @@@ extern size_t packed_git_limit
  extern size_t delta_base_cache_limit;
  extern int auto_crlf;
  extern int fsync_object_files;
 +extern int core_preload_index;
  
  enum safe_crlf {
        SAFE_CRLF_FALSE = 0,
  extern enum safe_crlf safe_crlf;
  
  enum branch_track {
 +      BRANCH_TRACK_UNSPECIFIED = -1,
        BRANCH_TRACK_NEVER = 0,
        BRANCH_TRACK_REMOTE,
        BRANCH_TRACK_ALWAYS,
@@@ -582,13 -521,6 +586,13 @@@ static inline void hashclr(unsigned cha
  {
        memset(hash, 0, 20);
  }
 +extern int is_empty_blob_sha1(const unsigned char *sha1);
 +
 +#define EMPTY_TREE_SHA1_HEX \
 +      "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
 +#define EMPTY_TREE_SHA1_BIN \
 +       "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
 +       "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
  
  int git_mkstemp(char *path, size_t n, const char *template);
  
@@@ -616,7 -548,6 +620,7 @@@ static inline int is_absolute_path(cons
  {
        return path[0] == '/' || has_dos_drive_prefix(path);
  }
 +int is_directory(const char *);
  const char *make_absolute_path(const char *path);
  const char *make_nonrelative_path(const char *path);
  const char *make_relative_path(const char *abs, const char *base);
@@@ -631,8 -562,8 +635,8 @@@ extern int write_sha1_file(void *buf, u
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
  extern int force_object_loose(const unsigned char *sha1, time_t mtime);
  
 -/* just like read_sha1_file(), but non fatal in presence of bad objects */
 -extern void *read_object(const unsigned char *sha1, enum object_type *type, unsigned long *size);
 +/* global flag to enable extra checks when accessing packed objects */
 +extern int do_check_packed_object_crc;
  
  extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
  
@@@ -725,8 -656,6 +729,8 @@@ extern struct alternate_object_databas
  } *alt_odb_list;
  extern void prepare_alt_odb(void);
  extern void add_to_alternates_file(const char *reference);
 +typedef int alt_odb_fn(struct alternate_object_database *, void *);
 +extern void foreach_alt_odb(alt_odb_fn, void*);
  
  struct pack_window {
        struct pack_window *next;
@@@ -796,11 -725,7 +800,11 @@@ extern struct child_process *git_connec
  extern int finish_connect(struct child_process *conn);
  extern int path_match(const char *path, int nr, char **match);
  extern int get_ack(int fd, unsigned char *result_sha1);
 -extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags);
 +struct extra_have_objects {
 +      int nr, alloc;
 +      unsigned char (*array)[20];
 +};
 +extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *);
  extern int server_supports(const char *feature);
  
  extern struct packed_git *parse_pack_index(unsigned char *sha1);
@@@ -823,7 -748,7 +827,7 @@@ extern const unsigned char *nth_packed_
  extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t);
  extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *);
  extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *);
 -extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
 +extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
  extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);
  extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
  extern int matches_pack_name(struct packed_git *p, const char *name);
@@@ -835,6 -760,7 +839,6 @@@ typedef int (*config_fn_t)(const char *
  extern int git_default_config(const char *, const char *, void *);
  extern int git_config_from_file(config_fn_t fn, const char *, void *);
  extern int git_config(config_fn_t fn, void *);
 -extern int git_parse_long(const char *, long *);
  extern int git_parse_ulong(const char *, unsigned long *);
  extern int git_config_int(const char *, const char *);
  extern unsigned long git_config_ulong(const char *, const char *);
diff --combined http-push.c
index 6ad853e2d01b4ee3b3ee282b30b8b7f374ae3d47,6d977ea6e17ce3a03e47fbfdbc83f8d33f6dd94b..cb5bf95a736c571259aef51884cc20e4169bf707
@@@ -87,7 -87,6 +87,7 @@@ static struct object_list *objects
  struct repo
  {
        char *url;
 +      char *path;
        int path_len;
        int has_info_refs;
        int can_update_info_refs;
@@@ -127,7 -126,7 +127,7 @@@ struct transfer_reques
        char errorstr[CURL_ERROR_SIZE];
        long http_code;
        unsigned char real_sha1[20];
 -      SHA_CTX c;
 +      git_SHA_CTX c;
        z_stream stream;
        int zret;
        int rename;
@@@ -209,8 -208,8 +209,8 @@@ static size_t fwrite_sha1_file(void *pt
        do {
                request->stream.next_out = expn;
                request->stream.avail_out = sizeof(expn);
-               request->zret = inflate(&request->stream, Z_SYNC_FLUSH);
+               request->zret = git_inflate(&request->stream, Z_SYNC_FLUSH);
 -              SHA1_Update(&request->c, expn,
 +              git_SHA1_Update(&request->c, expn,
                            sizeof(expn) - request->stream.avail_out);
        } while (request->stream.avail_in && request->zret == Z_OK);
        data_received++;
@@@ -269,9 -268,9 +269,9 @@@ static void start_fetch_loose(struct tr
  
        memset(&request->stream, 0, sizeof(request->stream));
  
-       inflateInit(&request->stream);
+       git_inflate_init(&request->stream);
  
 -      SHA1_Init(&request->c);
 +      git_SHA1_Init(&request->c);
  
        url = xmalloc(strlen(remote->url) + 50);
        request->url = xmalloc(strlen(remote->url) + 50);
           file; also rewind to the beginning of the local file. */
        if (prev_read == -1) {
                memset(&request->stream, 0, sizeof(request->stream));
-               inflateInit(&request->stream);
+               git_inflate_init(&request->stream);
 -              SHA1_Init(&request->c);
 +              git_SHA1_Init(&request->c);
                if (prev_posn>0) {
                        prev_posn = 0;
                        lseek(request->local_fileno, 0, SEEK_SET);
@@@ -596,7 -595,7 +596,7 @@@ static int refresh_lock(struct remote_l
        lock->refreshing = 1;
  
        if_header = xmalloc(strlen(lock->token) + 25);
 -      sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
 +      sprintf(if_header, "If: (<%s>)", lock->token);
        sprintf(timeout_header, "Timeout: Second-%ld", lock->timeout);
        dav_headers = curl_slist_append(dav_headers, if_header);
        dav_headers = curl_slist_append(dav_headers, timeout_header);
@@@ -742,8 -741,8 +742,8 @@@ static void finish_request(struct trans
                        if (request->http_code == 416)
                                fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
  
-                       inflateEnd(&request->stream);
+                       git_inflate_end(&request->stream);
 -                      SHA1_Final(request->real_sha1, &request->c);
 +                      git_SHA1_Final(request->real_sha1, &request->c);
                        if (request->zret != Z_STREAM_END) {
                                unlink(request->tmpfile);
                        } else if (hashcmp(request->obj->sha1, request->real_sha1)) {
@@@ -1121,8 -1120,10 +1121,8 @@@ static void handle_new_lock_ctx(struct 
                                lock->timeout =
                                        strtol(ctx->cdata + 7, NULL, 10);
                } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
 -                      if (!prefixcmp(ctx->cdata, "opaquelocktoken:")) {
 -                              lock->token = xmalloc(strlen(ctx->cdata) - 15);
 -                              strcpy(lock->token, ctx->cdata + 16);
 -                      }
 +                      lock->token = xmalloc(strlen(ctx->cdata) + 1);
 +                      strcpy(lock->token, ctx->cdata);
                }
        }
  }
@@@ -1201,8 -1202,7 +1201,8 @@@ static struct remote_lock *lock_remote(
        /* Make sure leading directories exist for the remote ref */
        ep = strchr(url + strlen(remote->url) + 1, '/');
        while (ep) {
 -              *ep = 0;
 +              char saved_character = ep[1];
 +              ep[1] = '\0';
                slot = get_active_slot();
                slot->results = &results;
                curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
                        free(url);
                        return NULL;
                }
 -              *ep = '/';
 +              ep[1] = saved_character;
                ep = strchr(ep + 1, '/');
        }
  
@@@ -1308,7 -1308,7 +1308,7 @@@ static int unlock_remote(struct remote_
        int rc = 0;
  
        lock_token_header = xmalloc(strlen(lock->token) + 31);
 -      sprintf(lock_token_header, "Lock-Token: <opaquelocktoken:%s>",
 +      sprintf(lock_token_header, "Lock-Token: <%s>",
                lock->token);
        dav_headers = curl_slist_append(dav_headers, lock_token_header);
  
@@@ -1426,17 -1426,9 +1426,17 @@@ static void handle_remote_ls_ctx(struc
                                ls->userFunc(ls);
                        }
                } else if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {
 -                      ls->dentry_name = xmalloc(strlen(ctx->cdata) -
 -                                                remote->path_len + 1);
 -                      strcpy(ls->dentry_name, ctx->cdata + remote->path_len);
 +                      char *path = ctx->cdata;
 +                      if (*ctx->cdata == 'h') {
 +                              path = strstr(path, "//");
 +                              if (path) {
 +                                      path = strchr(path+2, '/');
 +                              }
 +                      }
 +                      if (path) {
 +                              path += remote->path_len;
 +                              ls->dentry_name = xstrdup(path);
 +                      }
                } else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
                        ls->dentry_flags |= IS_DIR;
                }
        }
  }
  
 +/*
 + * NEEDSWORK: remote_ls() ignores info/refs on the remote side.  But it
 + * should _only_ heed the information from that file, instead of trying to
 + * determine the refs from the remote file system (badly: it does not even
 + * know about packed-refs).
 + */
  static void remote_ls(const char *path, int flags,
                      void (*userFunc)(struct remote_ls_ctx *ls),
                      void *userData)
@@@ -1736,7 -1722,7 +1736,7 @@@ static int update_remote(unsigned char 
        struct curl_slist *dav_headers = NULL;
  
        if_header = xmalloc(strlen(lock->token) + 25);
 -      sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
 +      sprintf(if_header, "If: (<%s>)", lock->token);
        dav_headers = curl_slist_append(dav_headers, if_header);
  
        strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1));
@@@ -1794,7 -1780,7 +1794,7 @@@ static void one_remote_ref(char *refnam
        struct ref *ref;
        struct object *obj;
  
 -      ref = alloc_ref_from_str(refname);
 +      ref = alloc_ref(refname);
  
        if (http_fetch_ref(remote->url, ref) != 0) {
                fprintf(stderr,
@@@ -1901,7 -1887,7 +1901,7 @@@ static void add_remote_info_ref(struct 
        char *ref_info;
        struct ref *ref;
  
 -      ref = alloc_ref_from_str(ls->dentry_name);
 +      ref = alloc_ref(ls->dentry_name);
  
        if (http_fetch_ref(remote->url, ref) != 0) {
                fprintf(stderr,
@@@ -1955,7 -1941,7 +1955,7 @@@ static void update_remote_info_refs(str
                  add_remote_info_ref, &buffer.buf);
        if (!aborted) {
                if_header = xmalloc(strlen(lock->token) + 25);
 -              sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
 +              sprintf(if_header, "If: (<%s>)", lock->token);
                dav_headers = curl_slist_append(dav_headers, if_header);
  
                slot = get_active_slot();
@@@ -2222,11 -2208,10 +2222,11 @@@ int main(int argc, char **argv
                if (!remote->url) {
                        char *path = strstr(arg, "//");
                        remote->url = arg;
 +                      remote->path_len = strlen(arg);
                        if (path) {
 -                              path = strchr(path+2, '/');
 -                              if (path)
 -                                      remote->path_len = strlen(path);
 +                              remote->path = strchr(path+2, '/');
 +                              if (remote->path)
 +                                      remote->path_len = strlen(remote->path);
                        }
                        continue;
                }
        no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
  
        if (remote->url && remote->url[strlen(remote->url)-1] != '/') {
 -              rewritten_url = malloc(strlen(remote->url)+2);
 +              rewritten_url = xmalloc(strlen(remote->url)+2);
                strcpy(rewritten_url, remote->url);
                strcat(rewritten_url, "/");
 +              remote->path = rewritten_url + (remote->path - remote->url);
 +              remote->path_len++;
                remote->url = rewritten_url;
 -              ++remote->path_len;
        }
  
        /* Verify DAV compliance/lock support */
diff --combined http-walker.c
index 7271c7d19d3b08ef76c9c868ae57f6872f6186d0,747d3adef884ec4d5c0370fc5c086e1904a7d442..0dbad3c888c6c9441af4d9550fd147ecb5b1aaf3
@@@ -36,7 -36,7 +36,7 @@@ struct object_reques
        char errorstr[CURL_ERROR_SIZE];
        long http_code;
        unsigned char real_sha1[20];
 -      SHA_CTX c;
 +      git_SHA_CTX c;
        z_stream stream;
        int zret;
        int rename;
@@@ -82,8 -82,8 +82,8 @@@ static size_t fwrite_sha1_file(void *pt
        do {
                obj_req->stream.next_out = expn;
                obj_req->stream.avail_out = sizeof(expn);
-               obj_req->zret = inflate(&obj_req->stream, Z_SYNC_FLUSH);
+               obj_req->zret = git_inflate(&obj_req->stream, Z_SYNC_FLUSH);
 -              SHA1_Update(&obj_req->c, expn,
 +              git_SHA1_Update(&obj_req->c, expn,
                            sizeof(expn) - obj_req->stream.avail_out);
        } while (obj_req->stream.avail_in && obj_req->zret == Z_OK);
        data_received++;
@@@ -142,9 -142,9 +142,9 @@@ static void start_object_request(struc
  
        memset(&obj_req->stream, 0, sizeof(obj_req->stream));
  
-       inflateInit(&obj_req->stream);
+       git_inflate_init(&obj_req->stream);
  
 -      SHA1_Init(&obj_req->c);
 +      git_SHA1_Init(&obj_req->c);
  
        url = xmalloc(strlen(obj_req->repo->base) + 51);
        obj_req->url = xmalloc(strlen(obj_req->repo->base) + 51);
           file; also rewind to the beginning of the local file. */
        if (prev_read == -1) {
                memset(&obj_req->stream, 0, sizeof(obj_req->stream));
-               inflateInit(&obj_req->stream);
+               git_inflate_init(&obj_req->stream);
 -              SHA1_Init(&obj_req->c);
 +              git_SHA1_Init(&obj_req->c);
                if (prev_posn>0) {
                        prev_posn = 0;
                        lseek(obj_req->local, 0, SEEK_SET);
@@@ -243,8 -243,8 +243,8 @@@ static void finish_object_request(struc
                return;
        }
  
-       inflateEnd(&obj_req->stream);
+       git_inflate_end(&obj_req->stream);
 -      SHA1_Final(obj_req->real_sha1, &obj_req->c);
 +      git_SHA1_Final(obj_req->real_sha1, &obj_req->c);
        if (obj_req->zret != Z_STREAM_END) {
                unlink(obj_req->tmpfile);
                return;
diff --combined index-pack.c
index 2931511e8cd9f2a825d1eb949858ea9b305c337f,c2d17bf61326190733620347812901fd791b0e63..b46a6d65973ac4b6ce4600a67c11e7bb37e49b89
@@@ -67,7 -67,7 +67,7 @@@ static struct progress *progress
  static unsigned char input_buffer[4096];
  static unsigned int input_offset, input_len;
  static off_t consumed_bytes;
 -static SHA_CTX input_ctx;
 +static git_SHA_CTX input_ctx;
  static uint32_t input_crc32;
  static int input_fd, output_fd, pack_fd;
  
@@@ -119,7 -119,7 +119,7 @@@ static void flush(void
        if (input_offset) {
                if (output_fd >= 0)
                        write_or_die(output_fd, input_buffer, input_offset);
 -              SHA1_Update(&input_ctx, 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;
        }
@@@ -178,7 -178,7 +178,7 @@@ static char *open_pack_file(char *pack_
                } else
                        output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
                if (output_fd < 0)
 -                      die("unable to create %s: %s\n", pack_name, strerror(errno));
 +                      die("unable to create %s: %s", pack_name, strerror(errno));
                pack_fd = output_fd;
        } else {
                input_fd = open(pack_name, O_RDONLY);
                output_fd = -1;
                pack_fd = input_fd;
        }
 -      SHA1_Init(&input_ctx);
 +      git_SHA1_Init(&input_ctx);
        return pack_name;
  }
  
@@@ -221,23 -221,17 +221,23 @@@ static void bad_object(unsigned long of
        die("pack has bad object at offset %lu: %s", offset, buf);
  }
  
 +static void free_base_data(struct base_data *c)
 +{
 +      if (c->data) {
 +              free(c->data);
 +              c->data = NULL;
 +              base_cache_used -= c->size;
 +      }
 +}
 +
  static void prune_base_data(struct base_data *retain)
  {
        struct base_data *b = base_cache;
        for (b = base_cache;
             base_cache_used > delta_base_cache_limit && b;
             b = b->child) {
 -              if (b->data && b != retain) {
 -                      free(b->data);
 -                      b->data = NULL;
 -                      base_cache_used -= b->size;
 -              }
 +              if (b->data && b != retain)
 +                      free_base_data(b);
        }
  }
  
@@@ -250,8 -244,7 +250,8 @@@ static void link_base_data(struct base_
  
        c->base = base;
        c->child = NULL;
 -      base_cache_used += c->size;
 +      if (c->data)
 +              base_cache_used += c->size;
        prune_base_data(c);
  }
  
@@@ -262,7 -255,10 +262,7 @@@ static void unlink_base_data(struct bas
                base->child = NULL;
        else
                base_cache = NULL;
 -      if (c->data) {
 -              free(c->data);
 -              base_cache_used -= c->size;
 -      }
 +      free_base_data(c);
  }
  
  static void *unpack_entry_data(unsigned long offset, unsigned long size)
        stream.avail_out = size;
        stream.next_in = fill(1);
        stream.avail_in = input_len;
-       inflateInit(&stream);
+       git_inflate_init(&stream);
  
        for (;;) {
-               int ret = inflate(&stream, 0);
+               int ret = git_inflate(&stream, 0);
                use(input_len - stream.avail_in);
                if (stream.total_out == size && ret == Z_STREAM_END)
                        break;
                stream.next_in = fill(1);
                stream.avail_in = input_len;
        }
-       inflateEnd(&stream);
+       git_inflate_end(&stream);
        return buf;
  }
  
@@@ -338,7 -334,7 +338,7 @@@ static void *unpack_raw_entry(struct ob
                        base_offset = (base_offset << 7) + (c & 127);
                }
                delta_base->offset = obj->idx.offset - base_offset;
 -              if (delta_base->offset >= obj->idx.offset)
 +              if (delta_base->offset <= 0 || delta_base->offset >= obj->idx.offset)
                        bad_object(obj->idx.offset, "delta base offset is out of bound");
                break;
        case OBJ_COMMIT:
@@@ -382,9 -378,9 +382,9 @@@ static void *get_data_from_pack(struct 
        stream.avail_out = obj->size;
        stream.next_in = src;
        stream.avail_in = len;
-       inflateInit(&stream);
-       while ((st = inflate(&stream, Z_FINISH)) == Z_OK);
-       inflateEnd(&stream);
+       git_inflate_init(&stream);
+       while ((st = git_inflate(&stream, Z_FINISH)) == Z_OK);
+       git_inflate_end(&stream);
        if (st != Z_STREAM_END || stream.total_out != obj->size)
                die("serious inflate inconsistency");
        free(src);
@@@ -412,24 -408,22 +412,24 @@@ static int find_delta(const union delta
          return -first-1;
  }
  
 -static int find_delta_children(const union delta_base *base,
 -                             int *first_index, int *last_index)
 +static void find_delta_children(const union delta_base *base,
 +                              int *first_index, int *last_index)
  {
        int first = find_delta(base);
        int last = first;
        int end = nr_deltas - 1;
  
 -      if (first < 0)
 -              return -1;
 +      if (first < 0) {
 +              *first_index = 0;
 +              *last_index = -1;
 +              return;
 +      }
        while (first > 0 && !memcmp(&deltas[first - 1].base, base, UNION_BASE_SZ))
                --first;
        while (last < end && !memcmp(&deltas[last + 1].base, base, UNION_BASE_SZ))
                ++last;
        *first_index = first;
        *last_index = last;
 -      return 0;
  }
  
  static void sha1_object(const void *data, unsigned long size,
@@@ -500,10 -494,8 +500,10 @@@ static void *get_base_data(struct base_
                        free(raw);
                        if (!c->data)
                                bad_object(obj->idx.offset, "failed to apply delta");
 -              } else
 +              } else {
                        c->data = get_data_from_pack(obj);
 +                      c->size = obj->size;
 +              }
  
                base_cache_used += c->size;
                prune_base_data(c);
  }
  
  static void resolve_delta(struct object_entry *delta_obj,
 -                        struct base_data *base_obj, enum object_type type)
 +                        struct base_data *base, struct base_data *result)
  {
 -      void *delta_data;
 -      unsigned long delta_size;
 -      union delta_base delta_base;
 -      int j, first, last;
 -      struct base_data result;
 +      void *base_data, *delta_data;
  
 -      delta_obj->real_type = type;
 +      delta_obj->real_type = base->obj->real_type;
        delta_data = get_data_from_pack(delta_obj);
 -      delta_size = delta_obj->size;
 -      result.data = patch_delta(get_base_data(base_obj), base_obj->size,
 -                           delta_data, delta_size,
 -                           &result.size);
 +      base_data = get_base_data(base);
 +      result->obj = delta_obj;
 +      result->data = patch_delta(base_data, base->size,
 +                                 delta_data, delta_obj->size, &result->size);
        free(delta_data);
 -      if (!result.data)
 +      if (!result->data)
                bad_object(delta_obj->idx.offset, "failed to apply delta");
 -      sha1_object(result.data, result.size, type, delta_obj->idx.sha1);
 +      sha1_object(result->data, result->size, delta_obj->real_type,
 +                  delta_obj->idx.sha1);
        nr_resolved_deltas++;
 +}
 +
 +static void find_unresolved_deltas(struct base_data *base,
 +                                 struct base_data *prev_base)
 +{
 +      int i, ref_first, ref_last, ofs_first, ofs_last;
 +
 +      /*
 +       * This is a recursive function. Those brackets should help reducing
 +       * stack usage by limiting the scope of the delta_base union.
 +       */
 +      {
 +              union delta_base base_spec;
 +
 +              hashcpy(base_spec.sha1, base->obj->idx.sha1);
 +              find_delta_children(&base_spec, &ref_first, &ref_last);
  
 -      result.obj = delta_obj;
 -      link_base_data(base_obj, &result);
 +              memset(&base_spec, 0, sizeof(base_spec));
 +              base_spec.offset = base->obj->idx.offset;
 +              find_delta_children(&base_spec, &ofs_first, &ofs_last);
 +      }
  
 -      hashcpy(delta_base.sha1, delta_obj->idx.sha1);
 -      if (!find_delta_children(&delta_base, &first, &last)) {
 -              for (j = first; j <= last; j++) {
 -                      struct object_entry *child = objects + deltas[j].obj_no;
 -                      if (child->real_type == OBJ_REF_DELTA)
 -                              resolve_delta(child, &result, type);
 +      if (ref_last == -1 && ofs_last == -1) {
 +              free(base->data);
 +              return;
 +      }
 +
 +      link_base_data(prev_base, base);
 +
 +      for (i = ref_first; i <= ref_last; i++) {
 +              struct object_entry *child = objects + deltas[i].obj_no;
 +              if (child->real_type == OBJ_REF_DELTA) {
 +                      struct base_data result;
 +                      resolve_delta(child, base, &result);
 +                      if (i == ref_last && ofs_last == -1)
 +                              free_base_data(base);
 +                      find_unresolved_deltas(&result, base);
                }
        }
  
 -      memset(&delta_base, 0, sizeof(delta_base));
 -      delta_base.offset = delta_obj->idx.offset;
 -      if (!find_delta_children(&delta_base, &first, &last)) {
 -              for (j = first; j <= last; j++) {
 -                      struct object_entry *child = objects + deltas[j].obj_no;
 -                      if (child->real_type == OBJ_OFS_DELTA)
 -                              resolve_delta(child, &result, type);
 +      for (i = ofs_first; i <= ofs_last; i++) {
 +              struct object_entry *child = objects + deltas[i].obj_no;
 +              if (child->real_type == OBJ_OFS_DELTA) {
 +                      struct base_data result;
 +                      resolve_delta(child, base, &result);
 +                      if (i == ofs_last)
 +                              free_base_data(base);
 +                      find_unresolved_deltas(&result, base);
                }
        }
  
 -      unlink_base_data(&result);
 +      unlink_base_data(base);
  }
  
  static int compare_delta_entry(const void *a, const void *b)
@@@ -624,7 -591,7 +624,7 @@@ static void parse_pack_objects(unsigne
  
        /* Check pack integrity */
        flush();
 -      SHA1_Final(sha1, &input_ctx);
 +      git_SHA1_Final(sha1, &input_ctx);
        if (hashcmp(fill(20), sha1))
                die("pack is corrupted (SHA1 mismatch)");
        use(20);
                progress = start_progress("Resolving deltas", nr_deltas);
        for (i = 0; i < nr_objects; i++) {
                struct object_entry *obj = &objects[i];
 -              union delta_base base;
 -              int j, ref, ref_first, ref_last, ofs, ofs_first, ofs_last;
                struct base_data base_obj;
  
                if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)
                        continue;
 -              hashcpy(base.sha1, obj->idx.sha1);
 -              ref = !find_delta_children(&base, &ref_first, &ref_last);
 -              memset(&base, 0, sizeof(base));
 -              base.offset = obj->idx.offset;
 -              ofs = !find_delta_children(&base, &ofs_first, &ofs_last);
 -              if (!ref && !ofs)
 -                      continue;
 -              base_obj.data = get_data_from_pack(obj);
 -              base_obj.size = obj->size;
                base_obj.obj = obj;
 -              link_base_data(NULL, &base_obj);
 -
 -              if (ref)
 -                      for (j = ref_first; j <= ref_last; j++) {
 -                              struct object_entry *child = objects + deltas[j].obj_no;
 -                              if (child->real_type == OBJ_REF_DELTA)
 -                                      resolve_delta(child, &base_obj, obj->type);
 -                      }
 -              if (ofs)
 -                      for (j = ofs_first; j <= ofs_last; j++) {
 -                              struct object_entry *child = objects + deltas[j].obj_no;
 -                              if (child->real_type == OBJ_OFS_DELTA)
 -                                      resolve_delta(child, &base_obj, obj->type);
 -                      }
 -              unlink_base_data(&base_obj);
 +              base_obj.data = NULL;
 +              find_unresolved_deltas(&base_obj, NULL);
                display_progress(progress, nr_resolved_deltas);
        }
  }
@@@ -754,6 -745,7 +754,6 @@@ static void fix_unresolved_deltas(struc
        for (i = 0; i < n; i++) {
                struct delta_entry *d = sorted_by_pos[i];
                enum object_type type;
 -              int j, first, last;
                struct base_data base_obj;
  
                if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
                        die("local object %s is corrupt", sha1_to_hex(d->base.sha1));
                base_obj.obj = append_obj_to_pack(f, d->base.sha1,
                                        base_obj.data, base_obj.size, type);
 -              link_base_data(NULL, &base_obj);
 -
 -              find_delta_children(&d->base, &first, &last);
 -              for (j = first; j <= last; j++) {
 -                      struct object_entry *child = objects + deltas[j].obj_no;
 -                      if (child->real_type == OBJ_REF_DELTA)
 -                              resolve_delta(child, &base_obj, type);
 -              }
 -
 -              unlink_base_data(&base_obj);
 +              find_unresolved_deltas(&base_obj, NULL);
                display_progress(progress, nr_resolved_deltas);
        }
        free(sorted_by_pos);
@@@ -789,6 -790,7 +789,6 @@@ static void final(const char *final_pac
                err = close(output_fd);
                if (err)
                        die("error while closing pack file: %s", strerror(errno));
 -              chmod(curr_pack_name, 0444);
        }
  
        if (keep_msg) {
                if (move_temp_to_file(curr_pack_name, final_pack_name))
                        die("cannot store pack file");
        }
 +      if (from_stdin)
 +              chmod(final_pack_name, 0444);
  
 -      chmod(curr_index_name, 0444);
        if (final_index_name != curr_index_name) {
                if (!final_index_name) {
                        snprintf(name, sizeof(name), "%s/pack/pack-%s.idx",
                if (move_temp_to_file(curr_index_name, final_index_name))
                        die("cannot store index file");
        }
 +      chmod(final_index_name, 0444);
  
        if (!from_stdin) {
                printf("%s\n", sha1_to_hex(sha1));
diff --combined sha1_file.c
index f08493f039fa28c90e3edc708bbcf0a527e4f659,71c2282c9c56a00be75e3bc395e6e695dae229f2..360f7e5a028b4842b152f1fcbd9f39f3a8623b5c
@@@ -99,11 -99,7 +99,11 @@@ int safe_create_leading_directories(cha
                pos = strchr(pos, '/');
                if (!pos)
                        break;
 -              *pos = 0;
 +              while (*++pos == '/')
 +                      ;
 +              if (!*pos)
 +                      break;
 +              *--pos = '\0';
                if (!stat(path, &st)) {
                        /* path exists */
                        if (!S_ISDIR(st.st_mode)) {
@@@ -254,6 -250,7 +254,6 @@@ static void read_info_alternates(const 
   */
  static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth)
  {
 -      struct stat st;
        const char *objdir = get_object_directory();
        struct alternate_object_database *ent;
        struct alternate_object_database *alt;
        ent->base[pfxlen] = ent->base[entlen-1] = 0;
  
        /* Detect cases where alternate disappeared */
 -      if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {
 +      if (!is_directory(ent->base)) {
                error("object directory %s does not exist; "
                      "check .git/objects/info/alternates.",
                      ent->base);
@@@ -397,16 -394,6 +397,16 @@@ void add_to_alternates_file(const char 
                link_alt_odb_entries(alt, alt + strlen(alt), '\n', NULL, 0);
  }
  
 +void foreach_alt_odb(alt_odb_fn fn, void *cb)
 +{
 +      struct alternate_object_database *ent;
 +
 +      prepare_alt_odb();
 +      for (ent = alt_odb_list; ent; ent = ent->next)
 +              if (fn(ent, cb))
 +                      return;
 +}
 +
  void prepare_alt_odb(void)
  {
        const char *alt;
@@@ -1153,8 -1140,7 +1153,8 @@@ static int legacy_loose_object(unsigne
                return 0;
  }
  
 -unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
 +unsigned long unpack_object_header_buffer(const unsigned char *buf,
 +              unsigned long len, enum object_type *type, unsigned long *sizep)
  {
        unsigned shift;
        unsigned char c;
        size = c & 15;
        shift = 4;
        while (c & 0x80) {
 -              if (len <= used)
 -                      return 0;
 -              if (sizeof(long) * 8 <= shift)
 +              if (len <= used || sizeof(long) * 8 <= shift) {
 +                      error("bad object header");
                        return 0;
 +              }
                c = buf[used++];
                size += (c & 0x7f) << shift;
                shift += 7;
@@@ -1196,8 -1182,8 +1196,8 @@@ static int unpack_sha1_header(z_stream 
        stream->avail_out = bufsiz;
  
        if (legacy_loose_object(map)) {
-               inflateInit(stream);
-               return inflate(stream, 0);
+               git_inflate_init(stream);
+               return git_inflate(stream, 0);
        }
  
  
         * really worth it and we don't write it any longer.  But we
         * can still read it.
         */
 -      used = unpack_object_header_gently(map, mapsize, &type, &size);
 +      used = unpack_object_header_buffer(map, mapsize, &type, &size);
        if (!used || !valid_loose_object_type[type])
                return -1;
        map += used;
        /* Set up the stream for the rest.. */
        stream->next_in = map;
        stream->avail_in = mapsize;
-       inflateInit(stream);
+       git_inflate_init(stream);
  
        /* And generate the fake traditional header */
        stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
@@@ -1254,11 -1240,11 +1254,11 @@@ static void *unpack_sha1_rest(z_stream 
                stream->next_out = buf + bytes;
                stream->avail_out = size - bytes;
                while (status == Z_OK)
-                       status = inflate(stream, Z_FINISH);
+                       status = git_inflate(stream, Z_FINISH);
        }
        buf[size] = 0;
        if (status == Z_STREAM_END && !stream->avail_in) {
-               inflateEnd(stream);
+               git_inflate_end(stream);
                return buf;
        }
  
@@@ -1348,19 -1334,17 +1348,19 @@@ unsigned long get_size_from_delta(struc
        stream.next_out = delta_head;
        stream.avail_out = sizeof(delta_head);
  
-       inflateInit(&stream);
+       git_inflate_init(&stream);
        do {
                in = use_pack(p, w_curs, curpos, &stream.avail_in);
                stream.next_in = in;
-               st = inflate(&stream, Z_FINISH);
+               st = git_inflate(&stream, Z_FINISH);
                curpos += stream.next_in - in;
        } while ((st == Z_OK || st == Z_BUF_ERROR) &&
                 stream.total_out < sizeof(delta_head));
-       inflateEnd(&stream);
+       git_inflate_end(&stream);
 -      if ((st != Z_STREAM_END) && stream.total_out != sizeof(delta_head))
 -              die("delta data unpack-initial failed");
 +      if ((st != Z_STREAM_END) && stream.total_out != sizeof(delta_head)) {
 +              error("delta data unpack-initial failed");
 +              return 0;
 +      }
  
        /* Examine the initial part of the delta to figure out
         * the result size.
@@@ -1401,7 -1385,7 +1401,7 @@@ static off_t get_delta_base(struct pack
                        base_offset = (base_offset << 7) + (c & 127);
                }
                base_offset = delta_obj_offset - base_offset;
 -              if (base_offset >= delta_obj_offset)
 +              if (base_offset <= 0 || base_offset >= delta_obj_offset)
                        return 0;  /* out of bound */
                *curpos += used;
        } else if (type == OBJ_REF_DELTA) {
@@@ -1427,32 -1411,15 +1427,32 @@@ static int packed_delta_info(struct pac
        off_t base_offset;
  
        base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset);
 +      if (!base_offset)
 +              return OBJ_BAD;
        type = packed_object_info(p, base_offset, NULL);
 +      if (type <= OBJ_NONE) {
 +              struct revindex_entry *revidx;
 +              const unsigned char *base_sha1;
 +              revidx = find_pack_revindex(p, base_offset);
 +              if (!revidx)
 +                      return OBJ_BAD;
 +              base_sha1 = nth_packed_object_sha1(p, revidx->nr);
 +              mark_bad_packed_object(p, base_sha1);
 +              type = sha1_object_info(base_sha1, NULL);
 +              if (type <= OBJ_NONE)
 +                      return OBJ_BAD;
 +      }
  
        /* We choose to only get the type of the base object and
         * ignore potentially corrupt pack file that expects the delta
         * based on a base with a wrong size.  This saves tons of
         * inflate() calls.
         */
 -      if (sizep)
 +      if (sizep) {
                *sizep = get_size_from_delta(p, w_curs, curpos);
 +              if (*sizep == 0)
 +                      type = OBJ_BAD;
 +      }
  
        return type;
  }
@@@ -1474,11 -1441,10 +1474,11 @@@ static int unpack_object_header(struct 
         * insane, so we know won't exceed what we have been given.
         */
        base = use_pack(p, w_curs, *curpos, &left);
 -      used = unpack_object_header_gently(base, left, &type, sizep);
 -      if (!used)
 -              die("object offset outside of pack file");
 -      *curpos += used;
 +      used = unpack_object_header_buffer(base, left, &type, sizep);
 +      if (!used) {
 +              type = OBJ_BAD;
 +      } else
 +              *curpos += used;
  
        return type;
  }
@@@ -1562,9 -1528,8 +1562,9 @@@ static int packed_object_info(struct pa
                        *sizep = size;
                break;
        default:
 -              die("pack %s contains unknown object type %d",
 -                  p->pack_name, type);
 +              error("unknown object type %i at offset %"PRIuMAX" in %s",
 +                    type, (uintmax_t)obj_offset, p->pack_name);
 +              type = OBJ_BAD;
        }
        unuse_pack(&w_curs);
        return type;
@@@ -1585,14 -1550,14 +1585,14 @@@ static void *unpack_compressed_entry(st
        stream.next_out = buffer;
        stream.avail_out = size;
  
-       inflateInit(&stream);
+       git_inflate_init(&stream);
        do {
                in = use_pack(p, w_curs, curpos, &stream.avail_in);
                stream.next_in = in;
-               st = inflate(&stream, Z_FINISH);
+               st = git_inflate(&stream, Z_FINISH);
                curpos += stream.next_in - in;
        } while (st == Z_OK || st == Z_BUF_ERROR);
-       inflateEnd(&stream);
+       git_inflate_end(&stream);
        if ((st != Z_STREAM_END) || stream.total_out != size) {
                free(buffer);
                return NULL;
@@@ -1636,9 -1601,11 +1636,9 @@@ static void *cache_or_unpack_entry(stru
        struct delta_base_cache_entry *ent = delta_base_cache + hash;
  
        ret = ent->data;
 -      if (ret && ent->p == p && ent->base_offset == base_offset)
 -              goto found_cache_entry;
 -      return unpack_entry(p, base_offset, type, base_size);
 +      if (!ret || ent->p != p || ent->base_offset != base_offset)
 +              return unpack_entry(p, base_offset, type, base_size);
  
 -found_cache_entry:
        if (!keep_cache) {
                ent->data = NULL;
                ent->lru.next->prev = ent->lru.prev;
@@@ -1700,9 -1667,6 +1700,9 @@@ static void add_delta_base_cache(struc
        delta_base_cache_lru.prev = &ent->lru;
  }
  
 +static void *read_object(const unsigned char *sha1, enum object_type *type,
 +                       unsigned long *size);
 +
  static void *unpack_delta_entry(struct packed_git *p,
                                struct pack_window **w_curs,
                                off_t curpos,
                 * This is costly but should happen only in the presence
                 * of a corrupted pack, and is better than failing outright.
                 */
 -              struct revindex_entry *revidx = find_pack_revindex(p, base_offset);
 -              const unsigned char *base_sha1 =
 -                                      nth_packed_object_sha1(p, revidx->nr);
 +              struct revindex_entry *revidx;
 +              const unsigned char *base_sha1;
 +              revidx = find_pack_revindex(p, base_offset);
 +              if (!revidx)
 +                      return NULL;
 +              base_sha1 = nth_packed_object_sha1(p, revidx->nr);
                error("failed to read delta base object %s"
                      " at offset %"PRIuMAX" from %s",
                      sha1_to_hex(base_sha1), (uintmax_t)base_offset,
        return result;
  }
  
 +int do_check_packed_object_crc;
 +
  void *unpack_entry(struct packed_git *p, off_t obj_offset,
                   enum object_type *type, unsigned long *sizep)
  {
        off_t curpos = obj_offset;
        void *data;
  
 +      if (do_check_packed_object_crc && p->index_version > 1) {
 +              struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
 +              unsigned long len = revidx[1].offset - obj_offset;
 +              if (check_pack_crc(p, &w_curs, obj_offset, len, revidx->nr)) {
 +                      const unsigned char *sha1 =
 +                              nth_packed_object_sha1(p, revidx->nr);
 +                      error("bad packed object CRC for %s",
 +                            sha1_to_hex(sha1));
 +                      mark_bad_packed_object(p, sha1);
 +                      unuse_pack(&w_curs);
 +                      return NULL;
 +              }
 +      }
 +
        *type = unpack_object_header(p, &w_curs, &curpos, sizep);
        switch (*type) {
        case OBJ_OFS_DELTA:
@@@ -2020,7 -1965,7 +2020,7 @@@ static int sha1_loose_object_info(cons
                status = error("unable to parse %s header", sha1_to_hex(sha1));
        else if (sizep)
                *sizep = size;
-       inflateEnd(&stream);
+       git_inflate_end(&stream);
        munmap(map, mapsize);
        return status;
  }
@@@ -2041,14 -1986,7 +2041,14 @@@ int sha1_object_info(const unsigned cha
                if (!find_pack_entry(sha1, &e, NULL))
                        return status;
        }
 -      return packed_object_info(e.p, e.offset, sizep);
 +
 +      status = packed_object_info(e.p, e.offset, sizep);
 +      if (status < 0) {
 +              mark_bad_packed_object(e.p, sha1);
 +              status = sha1_object_info(sha1, sizep);
 +      }
 +
 +      return status;
  }
  
  static void *read_packed_sha1(const unsigned char *sha1,
@@@ -2090,7 -2028,9 +2090,7 @@@ static struct cached_object 
  static int cached_object_nr, cached_object_alloc;
  
  static struct cached_object empty_tree = {
 -      /* empty tree sha1: 4b825dc642cb6eb9a060e54bf8d69288fbee4904 */
 -      "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60"
 -      "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04",
 +      EMPTY_TREE_SHA1_BIN,
        OBJ_TREE,
        "",
        0
@@@ -2133,8 -2073,8 +2133,8 @@@ int pretend_sha1_file(void *buf, unsign
        return 0;
  }
  
 -void *read_object(const unsigned char *sha1, enum object_type *type,
 -                unsigned long *size)
 +static void *read_object(const unsigned char *sha1, enum object_type *type,
 +                       unsigned long *size)
  {
        unsigned long mapsize;
        void *map, *buf;
@@@ -2222,16 -2162,16 +2222,16 @@@ static void write_sha1_file_prepare(con
                                      const char *type, unsigned char *sha1,
                                      char *hdr, int *hdrlen)
  {
 -      SHA_CTX c;
 +      git_SHA_CTX c;
  
        /* Generate the header */
        *hdrlen = sprintf(hdr, "%s %lu", type, len)+1;
  
        /* Sha1.. */
 -      SHA1_Init(&c);
 -      SHA1_Update(&c, hdr, *hdrlen);
 -      SHA1_Update(&c, buf, len);
 -      SHA1_Final(sha1, &c);
 +      git_SHA1_Init(&c);
 +      git_SHA1_Update(&c, hdr, *hdrlen);
 +      git_SHA1_Update(&c, buf, len);
 +      git_SHA1_Final(sha1, &c);
  }
  
  /*
@@@ -2470,21 -2410,51 +2470,21 @@@ int has_sha1_file(const unsigned char *
        return has_loose_object(sha1);
  }
  
 -int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
 +static int index_mem(unsigned char *sha1, void *buf, size_t size,
 +                   int write_object, enum object_type type, const char *path)
  {
 -      struct strbuf buf;
 -      int ret;
 -
 -      strbuf_init(&buf, 0);
 -      if (strbuf_read(&buf, fd, 4096) < 0) {
 -              strbuf_release(&buf);
 -              return -1;
 -      }
 -
 -      if (!type)
 -              type = blob_type;
 -      if (write_object)
 -              ret = write_sha1_file(buf.buf, buf.len, type, sha1);
 -      else
 -              ret = hash_sha1_file(buf.buf, buf.len, type, sha1);
 -      strbuf_release(&buf);
 -
 -      return ret;
 -}
 -
 -int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
 -           enum object_type type, const char *path)
 -{
 -      size_t size = xsize_t(st->st_size);
 -      void *buf = NULL;
        int ret, re_allocated = 0;
  
 -      if (size)
 -              buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 -      close(fd);
 -
        if (!type)
                type = OBJ_BLOB;
  
        /*
         * Convert blobs to git internal format
         */
 -      if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) {
 -              struct strbuf nbuf;
 -              strbuf_init(&nbuf, 0);
 +      if ((type == OBJ_BLOB) && path) {
 +              struct strbuf nbuf = STRBUF_INIT;
                if (convert_to_git(path, buf, size, &nbuf,
                                   write_object ? safe_crlf : 0)) {
 -                      munmap(buf, size);
                        buf = strbuf_detach(&nbuf, &size);
                        re_allocated = 1;
                }
                ret = write_sha1_file(buf, size, typename(type), sha1);
        else
                ret = hash_sha1_file(buf, size, typename(type), sha1);
 -      if (re_allocated) {
 +      if (re_allocated)
                free(buf);
 -              return ret;
 -      }
 -      if (size)
 +      return ret;
 +}
 +
 +int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
 +           enum object_type type, const char *path)
 +{
 +      int ret;
 +      size_t size = xsize_t(st->st_size);
 +
 +      if (!S_ISREG(st->st_mode)) {
 +              struct strbuf sbuf = STRBUF_INIT;
 +              if (strbuf_read(&sbuf, fd, 4096) >= 0)
 +                      ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object,
 +                                      type, path);
 +              else
 +                      ret = -1;
 +              strbuf_release(&sbuf);
 +      } else if (size) {
 +              void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 +              ret = index_mem(sha1, buf, size, write_object, type, path);
                munmap(buf, size);
 +      } else
 +              ret = index_mem(sha1, NULL, size, write_object, type, path);
 +      close(fd);
        return ret;
  }
  
  int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object)
  {
        int fd;
 -      char *target;
 -      size_t len;
 +      struct strbuf sb = STRBUF_INIT;
  
        switch (st->st_mode & S_IFMT) {
        case S_IFREG:
                                     path);
                break;
        case S_IFLNK:
 -              len = xsize_t(st->st_size);
 -              target = xmalloc(len + 1);
 -              if (readlink(path, target, len + 1) != st->st_size) {
 +              if (strbuf_readlink(&sb, path, st->st_size)) {
                        char *errstr = strerror(errno);
 -                      free(target);
                        return error("readlink(\"%s\"): %s", path,
                                     errstr);
                }
                if (!write_object)
 -                      hash_sha1_file(target, len, blob_type, sha1);
 -              else if (write_sha1_file(target, len, blob_type, sha1))
 +                      hash_sha1_file(sb.buf, sb.len, blob_type, sha1);
 +              else if (write_sha1_file(sb.buf, sb.len, blob_type, sha1))
                        return error("%s: failed to insert into database",
                                     path);
 -              free(target);
 +              strbuf_release(&sb);
                break;
        case S_IFDIR:
                return resolve_gitlink_ref(path, "HEAD", sha1);