Merge branch 'jc/maint-clone-alternates'
authorJunio C Hamano <gitster@pobox.com>
Mon, 29 Aug 2011 04:19:21 +0000 (21:19 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 29 Aug 2011 04:19:21 +0000 (21:19 -0700)
* jc/maint-clone-alternates:
clone: clone from a repository with relative alternates
clone: allow more than one --reference

Conflicts:
builtin/clone.c

1  2 
builtin/clone.c
sha1_file.c
diff --combined builtin/clone.c
index 7663bc22c9a3cb35b803815762791fec44d4c477,16b4fba71f8fed16ac67ee09b186e0295fc6b6da..4d66a7f4e82e5e31a0250491bbe22f9ec9ac3bfe
@@@ -39,14 -39,23 +39,24 @@@ static const char * const builtin_clone
  
  static int option_no_checkout, option_bare, option_mirror;
  static int option_local, option_no_hardlinks, option_shared, option_recursive;
- static char *option_template, *option_reference, *option_depth;
+ static char *option_template, *option_depth;
  static char *option_origin = NULL;
  static char *option_branch = NULL;
  static const char *real_git_dir;
  static char *option_upload_pack = "git-upload-pack";
  static int option_verbosity;
  static int option_progress;
 +static struct string_list option_config;
+ static struct string_list option_reference;
+ static int opt_parse_reference(const struct option *opt, const char *arg, int unset)
+ {
+       struct string_list *option_reference = opt->value;
+       if (!arg)
+               return -1;
+       string_list_append(option_reference, arg);
+       return 0;
+ }
  
  static struct option builtin_clone_options[] = {
        OPT__VERBOSITY(&option_verbosity),
@@@ -72,8 -81,8 +82,8 @@@
                    "initialize submodules in the clone"),
        OPT_STRING(0, "template", &option_template, "template-directory",
                   "directory from which templates will be used"),
-       OPT_STRING(0, "reference", &option_reference, "repo",
-                  "reference repository"),
+       OPT_CALLBACK(0 , "reference", &option_reference, "repo",
+                    "reference repository", &opt_parse_reference),
        OPT_STRING('o', "origin", &option_origin, "branch",
                   "use <branch> instead of 'origin' to track upstream"),
        OPT_STRING('b', "branch", &option_branch, "branch",
@@@ -84,8 -93,7 +94,8 @@@
                    "create a shallow clone of that depth"),
        OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
                   "separate git dir from working tree"),
 -
 +      OPT_STRING_LIST('c', "config", &option_config, "key=value",
 +                      "set config inside the new repository"),
        OPT_END()
  };
  
@@@ -199,39 -207,80 +209,80 @@@ static void strip_trailing_slashes(cha
        *end = '\0';
  }
  
- static void setup_reference(const char *repo)
+ static int add_one_reference(struct string_list_item *item, void *cb_data)
  {
-       const char *ref_git;
-       char *ref_git_copy;
+       char *ref_git;
+       struct strbuf alternate = STRBUF_INIT;
        struct remote *remote;
        struct transport *transport;
        const struct ref *extra;
  
-       ref_git = real_path(option_reference);
-       if (is_directory(mkpath("%s/.git/objects", ref_git)))
-               ref_git = mkpath("%s/.git", ref_git);
-       else if (!is_directory(mkpath("%s/objects", ref_git)))
+       /* Beware: real_path() and mkpath() return static buffer */
+       ref_git = xstrdup(real_path(item->string));
+       if (is_directory(mkpath("%s/.git/objects", ref_git))) {
+               char *ref_git_git = xstrdup(mkpath("%s/.git", ref_git));
+               free(ref_git);
+               ref_git = ref_git_git;
+       } else if (!is_directory(mkpath("%s/objects", ref_git)))
                die(_("reference repository '%s' is not a local directory."),
-                   option_reference);
-       ref_git_copy = xstrdup(ref_git);
+                   item->string);
  
-       add_to_alternates_file(ref_git_copy);
+       strbuf_addf(&alternate, "%s/objects", ref_git);
+       add_to_alternates_file(alternate.buf);
+       strbuf_release(&alternate);
  
-       remote = remote_get(ref_git_copy);
-       transport = transport_get(remote, ref_git_copy);
+       remote = remote_get(ref_git);
+       transport = transport_get(remote, ref_git);
        for (extra = transport_get_remote_refs(transport); extra;
             extra = extra->next)
                add_extra_ref(extra->name, extra->old_sha1, 0);
  
        transport_disconnect(transport);
+       free(ref_git);
+       return 0;
+ }
  
-       free(ref_git_copy);
+ static void setup_reference(void)
+ {
+       for_each_string_list(&option_reference, add_one_reference, NULL);
  }
  
- static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
+ static void copy_alternates(struct strbuf *src, struct strbuf *dst,
+                           const char *src_repo)
+ {
+       /*
+        * Read from the source objects/info/alternates file
+        * and copy the entries to corresponding file in the
+        * destination repository with add_to_alternates_file().
+        * Both src and dst have "$path/objects/info/alternates".
+        *
+        * Instead of copying bit-for-bit from the original,
+        * we need to append to existing one so that the already
+        * created entry via "clone -s" is not lost, and also
+        * to turn entries with paths relative to the original
+        * absolute, so that they can be used in the new repository.
+        */
+       FILE *in = fopen(src->buf, "r");
+       struct strbuf line = STRBUF_INIT;
+       while (strbuf_getline(&line, in, '\n') != EOF) {
+               char *abs_path, abs_buf[PATH_MAX];
+               if (!line.len || line.buf[0] == '#')
+                       continue;
+               if (is_absolute_path(line.buf)) {
+                       add_to_alternates_file(line.buf);
+                       continue;
+               }
+               abs_path = mkpath("%s/objects/%s", src_repo, line.buf);
+               normalize_path_copy(abs_buf, abs_path);
+               add_to_alternates_file(abs_buf);
+       }
+       strbuf_release(&line);
+       fclose(in);
+ }
+ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
+                                  const char *src_repo, int src_baselen)
  {
        struct dirent *de;
        struct stat buf;
                }
                if (S_ISDIR(buf.st_mode)) {
                        if (de->d_name[0] != '.')
-                               copy_or_link_directory(src, dest);
+                               copy_or_link_directory(src, dest,
+                                                      src_repo, src_baselen);
+                       continue;
+               }
+               /* Files that cannot be copied bit-for-bit... */
+               if (!strcmp(src->buf + src_baselen, "/info/alternates")) {
+                       copy_alternates(src, dest, src_repo);
                        continue;
                }
  
@@@ -290,17 -346,20 +348,20 @@@ static const struct ref *clone_local(co
                                     const char *dest_repo)
  {
        const struct ref *ret;
-       struct strbuf src = STRBUF_INIT;
-       struct strbuf dest = STRBUF_INIT;
        struct remote *remote;
        struct transport *transport;
  
-       if (option_shared)
-               add_to_alternates_file(src_repo);
-       else {
+       if (option_shared) {
+               struct strbuf alt = STRBUF_INIT;
+               strbuf_addf(&alt, "%s/objects", src_repo);
+               add_to_alternates_file(alt.buf);
+               strbuf_release(&alt);
+       } else {
+               struct strbuf src = STRBUF_INIT;
+               struct strbuf dest = STRBUF_INIT;
                strbuf_addf(&src, "%s/objects", src_repo);
                strbuf_addf(&dest, "%s/objects", dest_repo);
-               copy_or_link_directory(&src, &dest);
+               copy_or_link_directory(&src, &dest, src_repo, src.len);
                strbuf_release(&src);
                strbuf_release(&dest);
        }
@@@ -345,9 -404,8 +406,9 @@@ static void remove_junk_on_signal(int s
  static struct ref *wanted_peer_refs(const struct ref *refs,
                struct refspec *refspec)
  {
 -      struct ref *local_refs = NULL;
 -      struct ref **tail = &local_refs;
 +      struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
 +      struct ref *local_refs = head;
 +      struct ref **tail = head ? &head->next : &local_refs;
  
        get_fetch_map(refs, refspec, &tail, 0);
        if (!option_mirror)
@@@ -360,32 -418,13 +421,32 @@@ static void write_remote_refs(const str
  {
        const struct ref *r;
  
 -      for (r = local_refs; r; r = r->next)
 +      for (r = local_refs; r; r = r->next) {
 +              if (!r->peer_ref)
 +                      continue;
                add_extra_ref(r->peer_ref->name, r->old_sha1, 0);
 +      }
  
        pack_refs(PACK_REFS_ALL);
        clear_extra_refs();
  }
  
 +static int write_one_config(const char *key, const char *value, void *data)
 +{
 +      return git_config_set_multivar(key, value ? value : "true", "^$", 0);
 +}
 +
 +static void write_config(struct string_list *config)
 +{
 +      int i;
 +
 +      for (i = 0; i < config->nr; i++) {
 +              if (git_config_parse_parameter(config->items[i].string,
 +                                             write_one_config, NULL) < 0)
 +                      die("unable to write parameters to config file");
 +      }
 +}
 +
  int cmd_clone(int argc, const char **argv, const char *prefix)
  {
        int is_bundle = 0, is_local;
                        printf(_("Cloning into %s...\n"), dir);
        }
        init_db(option_template, INIT_DB_QUIET);
 +      write_config(&option_config);
  
        /*
         * At this point, the config exists, so we do not need the
        git_config_set(key.buf, repo);
        strbuf_reset(&key);
  
-       if (option_reference)
-               setup_reference(git_dir);
+       if (option_reference.nr)
+               setup_reference();
  
        fetch_pattern = value.buf;
        refspec = parse_fetch_refspec(1, &fetch_pattern);
diff --combined sha1_file.c
index 44444ae8f4a01938e4f1b08cb7a270253dfe174b,f7c3408de61ce406874d9dea69133563c04c3ed8..e002056b85ce89c089dd09c1300461d60d81dffa
@@@ -380,7 -380,7 +380,7 @@@ void add_to_alternates_file(const char 
  {
        struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
        int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), LOCK_DIE_ON_ERROR);
-       char *alt = mkpath("%s/objects\n", reference);
+       char *alt = mkpath("%s\n", reference);
        write_or_die(fd, alt, strlen(alt));
        if (commit_lock_file(lock))
                die("could not close alternates file");
@@@ -834,7 -834,7 +834,7 @@@ static int in_window(struct pack_windo
  unsigned char *use_pack(struct packed_git *p,
                struct pack_window **w_cursor,
                off_t offset,
 -              unsigned int *left)
 +              unsigned long *left)
  {
        struct pack_window *win = *w_cursor;
  
@@@ -1186,7 -1186,7 +1186,7 @@@ static int open_sha1_file(const unsigne
        return -1;
  }
  
 -static void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
 +void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
  {
        void *map;
        int fd;
        return map;
  }
  
 -static int legacy_loose_object(unsigned char *map)
 +/*
 + * There used to be a second loose object header format which
 + * was meant to mimic the in-pack format, allowing for direct
 + * copy of the object data.  This format turned up not to be
 + * really worth it and we no longer write loose objects in that
 + * format.
 + */
 +static int experimental_loose_object(unsigned char *map)
  {
        unsigned int word;
  
        /*
 -       * Is it a zlib-compressed buffer? If so, the first byte
 -       * must be 0x78 (15-bit window size, deflated), and the
 -       * first 16-bit word is evenly divisible by 31
 +       * We must determine if the buffer contains the standard
 +       * zlib-deflated stream or the experimental format based
 +       * on the in-pack object format. Compare the header byte
 +       * for each format:
 +       *
 +       * RFC1950 zlib w/ deflate : 0www1000 : 0 <= www <= 7
 +       * Experimental pack-based : Stttssss : ttt = 1,2,3,4
 +       *
 +       * If bit 7 is clear and bits 0-3 equal 8, the buffer MUST be
 +       * in standard loose-object format, UNLESS it is a Git-pack
 +       * format object *exactly* 8 bytes in size when inflated.
 +       *
 +       * However, RFC1950 also specifies that the 1st 16-bit word
 +       * must be divisible by 31 - this checksum tells us our buffer
 +       * is in the standard format, giving a false positive only if
 +       * the 1st word of the Git-pack format object happens to be
 +       * divisible by 31, ie:
 +       *      ((byte0 * 256) + byte1) % 31 = 0
 +       *   =>        0ttt10000www1000 % 31 = 0
 +       *
 +       * As it happens, this case can only arise for www=3 & ttt=1
 +       * - ie, a Commit object, which would have to be 8 bytes in
 +       * size. As no Commit can be that small, we find that the
 +       * combination of these two criteria (bitmask & checksum)
 +       * can always correctly determine the buffer format.
         */
        word = (map[0] << 8) + map[1];
 -      if (map[0] == 0x78 && !(word % 31))
 -              return 1;
 -      else
 +      if ((map[0] & 0x8F) == 0x08 && !(word % 31))
                return 0;
 +      else
 +              return 1;
  }
  
  unsigned long unpack_object_header_buffer(const unsigned char *buf,
        return used;
  }
  
 -static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
 +int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
  {
        unsigned long size, used;
        static const char valid_loose_object_type[8] = {
        stream->next_out = buffer;
        stream->avail_out = bufsiz;
  
 -      if (legacy_loose_object(map)) {
 -              git_inflate_init(stream);
 -              return git_inflate(stream, 0);
 -      }
 -
 +      if (experimental_loose_object(map)) {
 +              /*
 +               * The old experimental format we no longer produce;
 +               * we can still read it.
 +               */
 +              used = unpack_object_header_buffer(map, mapsize, &type, &size);
 +              if (!used || !valid_loose_object_type[type])
 +                      return -1;
 +              map += used;
 +              mapsize -= used;
  
 -      /*
 -       * There used to be a second loose object header format which
 -       * was meant to mimic the in-pack format, allowing for direct
 -       * copy of the object data.  This format turned up not to be
 -       * really worth it and we don't write it any longer.  But we
 -       * can still read it.
 -       */
 -      used = unpack_object_header_buffer(map, mapsize, &type, &size);
 -      if (!used || !valid_loose_object_type[type])
 -              return -1;
 -      map += used;
 -      mapsize -= used;
 +              /* Set up the stream for the rest.. */
 +              stream->next_in = map;
 +              stream->avail_in = mapsize;
 +              git_inflate_init(stream);
  
 -      /* Set up the stream for the rest.. */
 -      stream->next_in = map;
 -      stream->avail_in = mapsize;
 +              /* And generate the fake traditional header */
 +              stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
 +                                               typename(type), size);
 +              return 0;
 +      }
        git_inflate_init(stream);
 -
 -      /* And generate the fake traditional header */
 -      stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
 -                                       typename(type), size);
 -      return 0;
 +      return git_inflate(stream, 0);
  }
  
 -static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size, const unsigned char *sha1)
 +static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long size, const unsigned char *sha1)
  {
        int bytes = strlen(buffer) + 1;
        unsigned char *buf = xmallocz(size);
   * too permissive for what we want to check. So do an anal
   * object header parse by hand.
   */
 -static int parse_sha1_header(const char *hdr, unsigned long *sizep)
 +int parse_sha1_header(const char *hdr, unsigned long *sizep)
  {
        char type[10];
        int i;
  static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1)
  {
        int ret;
 -      z_stream stream;
 +      git_zstream stream;
        char hdr[8192];
  
        ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
@@@ -1431,7 -1407,7 +1431,7 @@@ unsigned long get_size_from_delta(struc
  {
        const unsigned char *data;
        unsigned char delta_head[20], *in;
 -      z_stream stream;
 +      git_zstream stream;
        int st;
  
        memset(&stream, 0, sizeof(stream));
@@@ -1505,7 -1481,7 +1505,7 @@@ static off_t get_delta_base(struct pack
  
  /* forward declaration for a mutually recursive function */
  static int packed_object_info(struct packed_git *p, off_t offset,
 -                            unsigned long *sizep);
 +                            unsigned long *sizep, int *rtype);
  
  static int packed_delta_info(struct packed_git *p,
                             struct pack_window **w_curs,
        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);
 +      type = packed_object_info(p, base_offset, NULL, NULL);
        if (type <= OBJ_NONE) {
                struct revindex_entry *revidx;
                const unsigned char *base_sha1;
        return type;
  }
  
 -static int unpack_object_header(struct packed_git *p,
 -                              struct pack_window **w_curs,
 -                              off_t *curpos,
 -                              unsigned long *sizep)
 +int unpack_object_header(struct packed_git *p,
 +                       struct pack_window **w_curs,
 +                       off_t *curpos,
 +                       unsigned long *sizep)
  {
        unsigned char *base;
 -      unsigned int left;
 +      unsigned long left;
        unsigned long used;
        enum object_type type;
  
        return type;
  }
  
 -const char *packed_object_info_detail(struct packed_git *p,
 -                                    off_t obj_offset,
 -                                    unsigned long *size,
 -                                    unsigned long *store_size,
 -                                    unsigned int *delta_chain_length,
 -                                    unsigned char *base_sha1)
 -{
 -      struct pack_window *w_curs = NULL;
 -      off_t curpos;
 -      unsigned long dummy;
 -      unsigned char *next_sha1;
 -      enum object_type type;
 -      struct revindex_entry *revidx;
 -
 -      *delta_chain_length = 0;
 -      curpos = obj_offset;
 -      type = unpack_object_header(p, &w_curs, &curpos, size);
 -
 -      revidx = find_pack_revindex(p, obj_offset);
 -      *store_size = revidx[1].offset - obj_offset;
 -
 -      for (;;) {
 -              switch (type) {
 -              default:
 -                      die("pack %s contains unknown object type %d",
 -                          p->pack_name, type);
 -              case OBJ_COMMIT:
 -              case OBJ_TREE:
 -              case OBJ_BLOB:
 -              case OBJ_TAG:
 -                      unuse_pack(&w_curs);
 -                      return typename(type);
 -              case OBJ_OFS_DELTA:
 -                      obj_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
 -                      if (!obj_offset)
 -                              die("pack %s contains bad delta base reference of type %s",
 -                                  p->pack_name, typename(type));
 -                      if (*delta_chain_length == 0) {
 -                              revidx = find_pack_revindex(p, obj_offset);
 -                              hashcpy(base_sha1, nth_packed_object_sha1(p, revidx->nr));
 -                      }
 -                      break;
 -              case OBJ_REF_DELTA:
 -                      next_sha1 = use_pack(p, &w_curs, curpos, NULL);
 -                      if (*delta_chain_length == 0)
 -                              hashcpy(base_sha1, next_sha1);
 -                      obj_offset = find_pack_entry_one(next_sha1, p);
 -                      break;
 -              }
 -              (*delta_chain_length)++;
 -              curpos = obj_offset;
 -              type = unpack_object_header(p, &w_curs, &curpos, &dummy);
 -      }
 -}
 -
  static int packed_object_info(struct packed_git *p, off_t obj_offset,
 -                            unsigned long *sizep)
 +                            unsigned long *sizep, int *rtype)
  {
        struct pack_window *w_curs = NULL;
        unsigned long size;
        enum object_type type;
  
        type = unpack_object_header(p, &w_curs, &curpos, &size);
 +      if (rtype)
 +              *rtype = type; /* representation type */
  
        switch (type) {
        case OBJ_OFS_DELTA:
@@@ -1613,7 -1642,7 +1613,7 @@@ static void *unpack_compressed_entry(st
                                    unsigned long size)
  {
        int st;
 -      z_stream stream;
 +      git_zstream stream;
        unsigned char *buffer, *in;
  
        buffer = xmallocz(size);
@@@ -1666,13 -1695,6 +1666,13 @@@ static unsigned long pack_entry_hash(st
        return hash % MAX_DELTA_CACHE;
  }
  
 +static int in_delta_base_cache(struct packed_git *p, off_t base_offset)
 +{
 +      unsigned long hash = pack_entry_hash(p, base_offset);
 +      struct delta_base_cache_entry *ent = delta_base_cache + hash;
 +      return (ent->data && ent->p == p && ent->base_offset == base_offset);
 +}
 +
  static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
        unsigned long *base_size, enum object_type *type, int keep_cache)
  {
@@@ -1817,24 -1839,6 +1817,24 @@@ static void *unpack_delta_entry(struct 
        return result;
  }
  
 +static void write_pack_access_log(struct packed_git *p, off_t obj_offset)
 +{
 +      static FILE *log_file;
 +
 +      if (!log_file) {
 +              log_file = fopen(log_pack_access, "w");
 +              if (!log_file) {
 +                      error("cannot open pack access log '%s' for writing: %s",
 +                            log_pack_access, strerror(errno));
 +                      log_pack_access = NULL;
 +                      return;
 +              }
 +      }
 +      fprintf(log_file, "%s %"PRIuMAX"\n",
 +              p->pack_name, (uintmax_t)obj_offset);
 +      fflush(log_file);
 +}
 +
  int do_check_packed_object_crc;
  
  void *unpack_entry(struct packed_git *p, off_t obj_offset,
        off_t curpos = obj_offset;
        void *data;
  
 +      if (log_pack_access)
 +              write_pack_access_log(p, obj_offset);
 +
        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;
@@@ -2074,7 -2075,7 +2074,7 @@@ static int sha1_loose_object_info(cons
        int status;
        unsigned long mapsize, size;
        void *map;
 -      z_stream stream;
 +      git_zstream stream;
        char hdr[32];
  
        map = map_sha1_file(sha1, &mapsize);
        return status;
  }
  
 -int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
 +/* returns enum object_type or negative */
 +int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
  {
        struct cached_object *co;
        struct pack_entry e;
 -      int status;
 +      int status, rtype;
  
        co = find_cached_object(sha1);
        if (co) {
 -              if (sizep)
 -                      *sizep = co->size;
 +              if (oi->sizep)
 +                      *(oi->sizep) = co->size;
 +              oi->whence = OI_CACHED;
                return co->type;
        }
  
        if (!find_pack_entry(sha1, &e)) {
                /* Most likely it's a loose object. */
 -              status = sha1_loose_object_info(sha1, sizep);
 -              if (status >= 0)
 +              status = sha1_loose_object_info(sha1, oi->sizep);
 +              if (status >= 0) {
 +                      oi->whence = OI_LOOSE;
                        return status;
 +              }
  
                /* Not a loose object; someone else may have just packed it. */
                reprepare_packed_git();
                        return status;
        }
  
 -      status = packed_object_info(e.p, e.offset, sizep);
 +      status = packed_object_info(e.p, e.offset, oi->sizep, &rtype);
        if (status < 0) {
                mark_bad_packed_object(e.p, sha1);
 -              status = sha1_object_info(sha1, sizep);
 +              status = sha1_object_info_extended(sha1, oi);
 +      } else if (in_delta_base_cache(e.p, e.offset)) {
 +              oi->whence = OI_DBCACHED;
 +      } else {
 +              oi->whence = OI_PACKED;
 +              oi->u.packed.offset = e.offset;
 +              oi->u.packed.pack = e.p;
 +              oi->u.packed.is_delta = (rtype == OBJ_REF_DELTA ||
 +                                       rtype == OBJ_OFS_DELTA);
        }
  
        return status;
  }
  
 +int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
 +{
 +      struct object_info oi;
 +
 +      oi.sizep = sizep;
 +      return sha1_object_info_extended(sha1, &oi);
 +}
 +
  static void *read_packed_sha1(const unsigned char *sha1,
                              enum object_type *type, unsigned long *size)
  {
@@@ -2443,7 -2424,7 +2443,7 @@@ static int write_loose_object(const uns
  {
        int fd, ret;
        unsigned char compressed[4096];
 -      z_stream stream;
 +      git_zstream stream;
        git_SHA_CTX c;
        unsigned char parano_sha1[20];
        char *filename;
  
        /* Set it up */
        memset(&stream, 0, sizeof(stream));
 -      deflateInit(&stream, zlib_compression_level);
 +      git_deflate_init(&stream, zlib_compression_level);
        stream.next_out = compressed;
        stream.avail_out = sizeof(compressed);
        git_SHA1_Init(&c);
        /* First header.. */
        stream.next_in = (unsigned char *)hdr;
        stream.avail_in = hdrlen;
 -      while (deflate(&stream, 0) == Z_OK)
 -              /* nothing */;
 +      while (git_deflate(&stream, 0) == Z_OK)
 +              ; /* nothing */
        git_SHA1_Update(&c, hdr, hdrlen);
  
        /* Then the data itself.. */
        stream.avail_in = len;
        do {
                unsigned char *in0 = stream.next_in;
 -              ret = deflate(&stream, Z_FINISH);
 +              ret = git_deflate(&stream, Z_FINISH);
                git_SHA1_Update(&c, in0, stream.next_in - in0);
                if (write_buffer(fd, compressed, stream.next_out - compressed) < 0)
                        die("unable to write sha1 file");
  
        if (ret != Z_STREAM_END)
                die("unable to deflate new object %s (%d)", sha1_to_hex(sha1), ret);
 -      ret = deflateEnd(&stream);
 +      ret = git_deflate_end_gently(&stream);
        if (ret != Z_OK)
                die("deflateEnd on object %s failed (%d)", sha1_to_hex(sha1), ret);
        git_SHA1_Final(parano_sha1, &c);
@@@ -2723,7 -2704,7 +2723,7 @@@ static int index_stream(unsigned char *
        while (size) {
                char buf[10240];
                size_t sz = size < sizeof(buf) ? size : sizeof(buf);
 -              size_t actual;
 +              ssize_t actual;
  
                actual = read_in_full(fd, buf, sz);
                if (actual < 0)