Merge branch 'ek/alt-odb-entry-fix'
authorJunio C Hamano <gitster@pobox.com>
Mon, 21 Jul 2014 18:18:46 +0000 (11:18 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 21 Jul 2014 18:18:46 +0000 (11:18 -0700)
* ek/alt-odb-entry-fix:
sha1_file: do not add own object directory as alternate

1  2 
sha1_file.c
diff --combined sha1_file.c
index 4127ae138de6bb002645aa83af00681b1805d982,9dbe423a6989b28e4b72a7852c1c1400906feaa9..ea6150892aef3416ef28c2daf74ab5288da3b7c3
@@@ -60,12 -60,6 +60,12 @@@ static struct cached_object empty_tree 
        0
  };
  
 +/*
 + * A pointer to the last packed_git in which an object was found.
 + * When an object is sought, we look in this packfile first, because
 + * objects that are looked up at similar times are often in the same
 + * packfile as one another.
 + */
  static struct packed_git *last_found_pack;
  
  static struct cached_object *find_cached_object(const unsigned char *sha1)
@@@ -111,63 -105,50 +111,63 @@@ int mkdir_in_gitdir(const char *path
        return adjust_shared_perm(path);
  }
  
 -int safe_create_leading_directories(char *path)
 +enum scld_error safe_create_leading_directories(char *path)
  {
 -      char *pos = path + offset_1st_component(path);
 -      struct stat st;
 +      char *next_component = path + offset_1st_component(path);
 +      enum scld_error ret = SCLD_OK;
 +
 +      while (ret == SCLD_OK && next_component) {
 +              struct stat st;
 +              char *slash = next_component, slash_character;
 +
 +              while (*slash && !is_dir_sep(*slash))
 +                      slash++;
  
 -      while (pos) {
 -              pos = strchr(pos, '/');
 -              if (!pos)
 +              if (!*slash)
                        break;
 -              while (*++pos == '/')
 -                      ;
 -              if (!*pos)
 +
 +              next_component = slash + 1;
 +              while (is_dir_sep(*next_component))
 +                      next_component++;
 +              if (!*next_component)
                        break;
 -              *--pos = '\0';
 +
 +              slash_character = *slash;
 +              *slash = '\0';
                if (!stat(path, &st)) {
                        /* path exists */
 -                      if (!S_ISDIR(st.st_mode)) {
 -                              *pos = '/';
 -                              return -3;
 -                      }
 -              }
 -              else if (mkdir(path, 0777)) {
 +                      if (!S_ISDIR(st.st_mode))
 +                              ret = SCLD_EXISTS;
 +              } else if (mkdir(path, 0777)) {
                        if (errno == EEXIST &&
 -                          !stat(path, &st) && S_ISDIR(st.st_mode)) {
 +                          !stat(path, &st) && S_ISDIR(st.st_mode))
                                ; /* somebody created it since we checked */
 -                      } else {
 -                              *pos = '/';
 -                              return -1;
 -                      }
 -              }
 -              else if (adjust_shared_perm(path)) {
 -                      *pos = '/';
 -                      return -2;
 +                      else if (errno == ENOENT)
 +                              /*
 +                               * Either mkdir() failed because
 +                               * somebody just pruned the containing
 +                               * directory, or stat() failed because
 +                               * the file that was in our way was
 +                               * just removed.  Either way, inform
 +                               * the caller that it might be worth
 +                               * trying again:
 +                               */
 +                              ret = SCLD_VANISHED;
 +                      else
 +                              ret = SCLD_FAILED;
 +              } else if (adjust_shared_perm(path)) {
 +                      ret = SCLD_PERMS;
                }
 -              *pos++ = '/';
 +              *slash = slash_character;
        }
 -      return 0;
 +      return ret;
  }
  
 -int safe_create_leading_directories_const(const char *path)
 +enum scld_error safe_create_leading_directories_const(const char *path)
  {
        /* path points to cache entries, so xstrdup before messing with it */
        char *buf = xstrdup(path);
 -      int result = safe_create_leading_directories(buf);
 +      enum scld_error result = safe_create_leading_directories(buf);
        free(buf);
        return result;
  }
@@@ -184,7 -165,17 +184,7 @@@ static void fill_sha1_path(char *pathbu
        }
  }
  
 -/*
 - * NOTE! This returns a statically allocated buffer, so you have to be
 - * careful about using it. Do an "xstrdup()" if you need to save the
 - * filename.
 - *
 - * Also note that this returns the location for creating.  Reading
 - * SHA1 file can happen from any alternate directory listed in the
 - * DB_ENVIRONMENT environment variable if it is not found in
 - * the primary object database.
 - */
 -char *sha1_file_name(const unsigned char *sha1)
 +const char *sha1_file_name(const unsigned char *sha1)
  {
        static char buf[PATH_MAX];
        const char *objdir;
        return buf;
  }
  
 +/*
 + * Return the name of the pack or index file with the specified sha1
 + * in its filename.  *base and *name are scratch space that must be
 + * provided by the caller.  which should be "pack" or "idx".
 + */
  static char *sha1_get_pack_name(const unsigned char *sha1,
                                char **name, char **base, const char *which)
  {
@@@ -253,6 -239,8 +253,6 @@@ char *sha1_pack_index_name(const unsign
  struct alternate_object_database *alt_odb_list;
  static struct alternate_object_database **alt_odb_tail;
  
 -static int git_open_noatime(const char *name);
 -
  /*
   * Prepare alternate object database registry.
   *
   * SHA1, an extra slash for the first level indirection, and the
   * terminating NUL.
   */
- static int link_alt_odb_entry(const char *entry, const char *relative_base, int depth)
+ static int link_alt_odb_entry(const char *entry, const char *relative_base,
+       int depth, const char *normalized_objdir)
  {
-       const char *objdir = get_object_directory();
        struct alternate_object_database *ent;
        struct alternate_object_database *alt;
        int pfxlen, entlen;
         * thing twice, or object directory itself.
         */
        for (alt = alt_odb_list; alt; alt = alt->next) {
 -              if (!memcmp(ent->base, alt->base, pfxlen)) {
 +              if (pfxlen == alt->name - alt->base - 1 &&
 +                  !memcmp(ent->base, alt->base, pfxlen)) {
                        free(ent);
                        return -1;
                }
        }
-       if (!strcmp(ent->base, objdir)) {
+       if (!strcmp_icase(ent->base, normalized_objdir)) {
                free(ent);
                return -1;
        }
@@@ -345,6 -332,7 +345,7 @@@ static void link_alt_odb_entries(const 
        struct string_list entries = STRING_LIST_INIT_NODUP;
        char *alt_copy;
        int i;
+       struct strbuf objdirbuf = STRBUF_INIT;
  
        if (depth > 5) {
                error("%s: ignoring alternate object stores, nesting too deep.",
                return;
        }
  
+       strbuf_addstr(&objdirbuf, absolute_path(get_object_directory()));
+       normalize_path_copy(objdirbuf.buf, objdirbuf.buf);
        alt_copy = xmemdupz(alt, len);
        string_list_split_in_place(&entries, alt_copy, sep, -1);
        for (i = 0; i < entries.nr; i++) {
                        error("%s: ignoring relative alternate object store %s",
                                        relative_base, entry);
                } else {
-                       link_alt_odb_entry(entry, relative_base, depth);
+                       link_alt_odb_entry(entry, relative_base, depth, objdirbuf.buf);
                }
        }
        string_list_clear(&entries, 0);
        free(alt_copy);
+       strbuf_release(&objdirbuf);
  }
  
  void read_info_alternates(const char * relative_base, int depth)
@@@ -438,7 -430,8 +443,7 @@@ void prepare_alt_odb(void
  
  static int has_loose_object_local(const unsigned char *sha1)
  {
 -      char *name = sha1_file_name(sha1);
 -      return !access(name, F_OK);
 +      return !access(sha1_file_name(sha1), F_OK);
  }
  
  int has_loose_object_nonlocal(const unsigned char *sha1)
@@@ -490,12 -483,7 +495,12 @@@ void pack_report(void
                sz_fmt(pack_mapped), sz_fmt(peak_pack_mapped));
  }
  
 -static int check_packed_git_idx(const char *path,  struct packed_git *p)
 +/*
 + * Open and mmap the index file at path, perform a couple of
 + * consistency checks, then record its information to p.  Return 0 on
 + * success.
 + */
 +static int check_packed_git_idx(const char *path, struct packed_git *p)
  {
        void *idx_map;
        struct pack_idx_header *hdr;
@@@ -791,7 -779,7 +796,7 @@@ void close_pack_index(struct packed_gi
   * contain the same set of objects as an existing one.  In that case
   * the resulting file might be different even if its name would be the
   * same.  It is best to close any reference to the old pack before it is
 - * replaced on disk.  Of course no index pointers nor windows for given pack
 + * replaced on disk.  Of course no index pointers or windows for given pack
   * must subsist at this point.  If ever objects from this pack are requested
   * again, the new version of the pack will be reinitialized through
   * reprepare_packed_git().
@@@ -1127,7 -1115,7 +1132,7 @@@ static void report_helper(const struct 
        const char *msg;
        switch (seen_bits) {
        case 0:
 -              msg = "no corresponding .idx nor .pack";
 +              msg = "no corresponding .idx or .pack";
                break;
        case 1:
                msg = "no corresponding .idx";
@@@ -1178,42 -1166,48 +1183,42 @@@ static void report_pack_garbage(struct 
  
  static void prepare_packed_git_one(char *objdir, int local)
  {
 -      /* Ensure that this buffer is large enough so that we can
 -         append "/pack/" without clobbering the stack even if
 -         strlen(objdir) were PATH_MAX.  */
 -      char path[PATH_MAX + 1 + 4 + 1 + 1];
 -      int len;
 +      struct strbuf path = STRBUF_INIT;
 +      size_t dirnamelen;
        DIR *dir;
        struct dirent *de;
        struct string_list garbage = STRING_LIST_INIT_DUP;
  
 -      sprintf(path, "%s/pack", objdir);
 -      len = strlen(path);
 -      dir = opendir(path);
 +      strbuf_addstr(&path, objdir);
 +      strbuf_addstr(&path, "/pack");
 +      dir = opendir(path.buf);
        if (!dir) {
                if (errno != ENOENT)
                        error("unable to open object pack directory: %s: %s",
 -                            path, strerror(errno));
 +                            path.buf, strerror(errno));
 +              strbuf_release(&path);
                return;
        }
 -      path[len++] = '/';
 +      strbuf_addch(&path, '/');
 +      dirnamelen = path.len;
        while ((de = readdir(dir)) != NULL) {
 -              int namelen = strlen(de->d_name);
                struct packed_git *p;
 -
 -              if (len + namelen + 1 > sizeof(path)) {
 -                      if (report_garbage) {
 -                              struct strbuf sb = STRBUF_INIT;
 -                              strbuf_addf(&sb, "%.*s/%s", len - 1, path, de->d_name);
 -                              report_garbage("path too long", sb.buf);
 -                              strbuf_release(&sb);
 -                      }
 -                      continue;
 -              }
 +              size_t base_len;
  
                if (is_dot_or_dotdot(de->d_name))
                        continue;
  
 -              strcpy(path + len, de->d_name);
 +              strbuf_setlen(&path, dirnamelen);
 +              strbuf_addstr(&path, de->d_name);
  
 -              if (has_extension(de->d_name, ".idx")) {
 +              base_len = path.len;
 +              if (strip_suffix_mem(path.buf, &base_len, ".idx")) {
                        /* Don't reopen a pack we already have. */
                        for (p = packed_git; p; p = p->next) {
 -                              if (!memcmp(path, p->pack_name, len + namelen - 4))
 +                              size_t len;
 +                              if (strip_suffix(p->pack_name, ".pack", &len) &&
 +                                  len == base_len &&
 +                                  !memcmp(p->pack_name, path.buf, len))
                                        break;
                        }
                        if (p == NULL &&
                             * See if it really is a valid .idx file with
                             * corresponding .pack file that we can map.
                             */
 -                          (p = add_packed_git(path, len + namelen, local)) != NULL)
 +                          (p = add_packed_git(path.buf, path.len, local)) != NULL)
                                install_packed_git(p);
                }
  
                if (!report_garbage)
                        continue;
  
 -              if (has_extension(de->d_name, ".idx") ||
 -                  has_extension(de->d_name, ".pack") ||
 -                  has_extension(de->d_name, ".keep"))
 -                      string_list_append(&garbage, path);
 +              if (ends_with(de->d_name, ".idx") ||
 +                  ends_with(de->d_name, ".pack") ||
 +                  ends_with(de->d_name, ".bitmap") ||
 +                  ends_with(de->d_name, ".keep"))
 +                      string_list_append(&garbage, path.buf);
                else
 -                      report_garbage("garbage found", path);
 +                      report_garbage("garbage found", path.buf);
        }
        closedir(dir);
        report_pack_garbage(&garbage);
        string_list_clear(&garbage, 0);
 +      strbuf_release(&path);
  }
  
  static int sort_pack(const void *a_, const void *b_)
@@@ -1316,6 -1308,7 +1321,6 @@@ void prepare_packed_git(void
  
  void reprepare_packed_git(void)
  {
 -      discard_revindex();
        prepare_packed_git_run_once = 0;
        prepare_packed_git();
  }
@@@ -1392,7 -1385,7 +1397,7 @@@ int check_sha1_signature(const unsigne
        return hashcmp(sha1, real_sha1) ? -1 : 0;
  }
  
 -static int git_open_noatime(const char *name)
 +int git_open_noatime(const char *name)
  {
        static int sha1_file_open_flag = O_NOATIME;
  
  
  static int stat_sha1_file(const unsigned char *sha1, struct stat *st)
  {
 -      char *name = sha1_file_name(sha1);
        struct alternate_object_database *alt;
  
 -      if (!lstat(name, st))
 +      if (!lstat(sha1_file_name(sha1), st))
                return 0;
  
        prepare_alt_odb();
        errno = ENOENT;
        for (alt = alt_odb_list; alt; alt = alt->next) {
 -              name = alt->name;
 -              fill_sha1_path(name, sha1);
 +              fill_sha1_path(alt->name, sha1);
                if (!lstat(alt->base, st))
                        return 0;
        }
  static int open_sha1_file(const unsigned char *sha1)
  {
        int fd;
 -      char *name = sha1_file_name(sha1);
        struct alternate_object_database *alt;
 +      int most_interesting_errno;
  
 -      fd = git_open_noatime(name);
 +      fd = git_open_noatime(sha1_file_name(sha1));
        if (fd >= 0)
                return fd;
 +      most_interesting_errno = errno;
  
        prepare_alt_odb();
 -      errno = ENOENT;
        for (alt = alt_odb_list; alt; alt = alt->next) {
 -              name = alt->name;
 -              fill_sha1_path(name, sha1);
 +              fill_sha1_path(alt->name, sha1);
                fd = git_open_noatime(alt->base);
                if (fd >= 0)
                        return fd;
 +              if (most_interesting_errno == ENOENT)
 +                      most_interesting_errno = errno;
        }
 +      errno = most_interesting_errno;
        return -1;
  }
  
@@@ -1477,6 -1470,51 +1482,6 @@@ void *map_sha1_file(const unsigned cha
        return 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;
 -
 -      /*
 -       * 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] & 0x8F) == 0x08 && !(word % 31))
 -              return 0;
 -      else
 -              return 1;
 -}
 -
  unsigned long unpack_object_header_buffer(const unsigned char *buf,
                unsigned long len, enum object_type *type, unsigned long *sizep)
  {
  
  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] = {
 -              0, /* OBJ_EXT */
 -              1, 1, 1, 1, /* "commit", "tree", "blob", "tag" */
 -              0, /* "delta" and others are invalid in a loose object */
 -      };
 -      enum object_type type;
 -
        /* Get the data stream */
        memset(stream, 0, sizeof(*stream));
        stream->next_in = map;
        stream->next_out = buffer;
        stream->avail_out = bufsiz;
  
 -      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;
 -
 -              /* Set up the stream for the rest.. */
 -              stream->next_in = map;
 -              stream->avail_in = mapsize;
 -              git_inflate_init(stream);
 -
 -              /* And generate the fake traditional header */
 -              stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
 -                                               typename(type), size);
 -              return 0;
 -      }
        git_inflate_init(stream);
        return git_inflate(stream, 0);
  }
@@@ -1702,38 -1769,6 +1707,38 @@@ static off_t get_delta_base(struct pack
        return base_offset;
  }
  
 +/*
 + * Like get_delta_base above, but we return the sha1 instead of the pack
 + * offset. This means it is cheaper for REF deltas (we do not have to do
 + * the final object lookup), but more expensive for OFS deltas (we
 + * have to load the revidx to convert the offset back into a sha1).
 + */
 +static const unsigned char *get_delta_base_sha1(struct packed_git *p,
 +                                              struct pack_window **w_curs,
 +                                              off_t curpos,
 +                                              enum object_type type,
 +                                              off_t delta_obj_offset)
 +{
 +      if (type == OBJ_REF_DELTA) {
 +              unsigned char *base = use_pack(p, w_curs, curpos, NULL);
 +              return base;
 +      } else if (type == OBJ_OFS_DELTA) {
 +              struct revindex_entry *revidx;
 +              off_t base_offset = get_delta_base(p, w_curs, &curpos,
 +                                                 type, delta_obj_offset);
 +
 +              if (!base_offset)
 +                      return NULL;
 +
 +              revidx = find_pack_revindex(p, base_offset);
 +              if (!revidx)
 +                      return NULL;
 +
 +              return nth_packed_object_sha1(p, revidx->nr);
 +      } else
 +              return NULL;
 +}
 +
  int unpack_object_header(struct packed_git *p,
                         struct pack_window **w_curs,
                         off_t *curpos,
@@@ -1891,22 -1926,6 +1896,22 @@@ static int packed_object_info(struct pa
                }
        }
  
 +      if (oi->delta_base_sha1) {
 +              if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
 +                      const unsigned char *base;
 +
 +                      base = get_delta_base_sha1(p, &w_curs, curpos,
 +                                                 type, obj_offset);
 +                      if (!base) {
 +                              type = OBJ_BAD;
 +                              goto out;
 +                      }
 +
 +                      hashcpy(oi->delta_base_sha1, base);
 +              } else
 +                      hashclr(oi->delta_base_sha1);
 +      }
 +
  out:
        unuse_pack(&w_curs);
        return type;
@@@ -2288,10 -2307,6 +2293,10 @@@ void *unpack_entry(struct packed_git *p
        *final_size = size;
  
        unuse_pack(&w_curs);
 +
 +      if (delta_stack != small_delta_stack)
 +              free(delta_stack);
 +
        return data;
  }
  
@@@ -2451,10 -2466,6 +2456,10 @@@ static int fill_pack_entry(const unsign
        return 1;
  }
  
 +/*
 + * Iff a pack file contains the object named by sha1, return true and
 + * store its location to e.
 + */
  static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
  {
        struct packed_git *p;
                return 1;
  
        for (p = packed_git; p; p = p->next) {
 -              if (p == last_found_pack || !fill_pack_entry(sha1, e, p))
 -                      continue;
 +              if (p == last_found_pack)
 +                      continue; /* we already checked this one */
  
 -              last_found_pack = p;
 -              return 1;
 +              if (fill_pack_entry(sha1, e, p)) {
 +                      last_found_pack = p;
 +                      return 1;
 +              }
        }
        return 0;
  }
@@@ -2500,9 -2509,6 +2505,9 @@@ static int sha1_loose_object_info(cons
        git_zstream stream;
        char hdr[32];
  
 +      if (oi->delta_base_sha1)
 +              hashclr(oi->delta_base_sha1);
 +
        /*
         * If we don't care about type or size, then we don't
         * need to look inside the object at all. Note that we
        return 0;
  }
  
 -int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
 +int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags)
  {
        struct cached_object *co;
        struct pack_entry e;
        int rtype;
 +      const unsigned char *real = lookup_replace_object_extended(sha1, flags);
  
 -      co = find_cached_object(sha1);
 +      co = find_cached_object(real);
        if (co) {
                if (oi->typep)
                        *(oi->typep) = co->type;
                        *(oi->sizep) = co->size;
                if (oi->disk_sizep)
                        *(oi->disk_sizep) = 0;
 +              if (oi->delta_base_sha1)
 +                      hashclr(oi->delta_base_sha1);
                oi->whence = OI_CACHED;
                return 0;
        }
  
 -      if (!find_pack_entry(sha1, &e)) {
 +      if (!find_pack_entry(real, &e)) {
                /* Most likely it's a loose object. */
 -              if (!sha1_loose_object_info(sha1, oi)) {
 +              if (!sha1_loose_object_info(real, oi)) {
                        oi->whence = OI_LOOSE;
                        return 0;
                }
  
                /* Not a loose object; someone else may have just packed it. */
                reprepare_packed_git();
 -              if (!find_pack_entry(sha1, &e))
 +              if (!find_pack_entry(real, &e))
                        return -1;
        }
  
        rtype = packed_object_info(e.p, e.offset, oi);
        if (rtype < 0) {
 -              mark_bad_packed_object(e.p, sha1);
 -              return sha1_object_info_extended(sha1, oi);
 +              mark_bad_packed_object(e.p, real);
 +              return sha1_object_info_extended(real, oi, 0);
        } else if (in_delta_base_cache(e.p, e.offset)) {
                oi->whence = OI_DBCACHED;
        } else {
@@@ -2598,7 -2601,7 +2603,7 @@@ int sha1_object_info(const unsigned cha
  
        oi.typep = &type;
        oi.sizep = sizep;
 -      if (sha1_object_info_extended(sha1, &oi) < 0)
 +      if (sha1_object_info_extended(sha1, &oi, LOOKUP_REPLACE_OBJECT) < 0)
                return -1;
        return type;
  }
@@@ -2635,7 -2638,12 +2640,7 @@@ int pretend_sha1_file(void *buf, unsign
        hash_sha1_file(buf, len, typename(type), sha1);
        if (has_sha1_file(sha1) || find_cached_object(sha1))
                return 0;
 -      if (cached_object_alloc <= cached_object_nr) {
 -              cached_object_alloc = alloc_nr(cached_object_alloc);
 -              cached_objects = xrealloc(cached_objects,
 -                                        sizeof(*cached_objects) *
 -                                        cached_object_alloc);
 -      }
 +      ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
        co = &cached_objects[cached_object_nr++];
        co->size = len;
        co->type = type;
@@@ -2683,8 -2691,10 +2688,8 @@@ void *read_sha1_file_extended(const uns
                              unsigned flag)
  {
        void *data;
 -      char *path;
        const struct packed_git *p;
 -      const unsigned char *repl = (flag & READ_SHA1_FILE_REPLACE)
 -              ? lookup_replace_object(sha1) : sha1;
 +      const unsigned char *repl = lookup_replace_object_extended(sha1, flag);
  
        errno = 0;
        data = read_object(repl, type, size);
                    sha1_to_hex(repl), sha1_to_hex(sha1));
  
        if (has_loose_object(repl)) {
 -              path = sha1_file_name(sha1);
 +              const char *path = sha1_file_name(sha1);
 +
                die("loose object %s (stored in %s) is corrupt",
                    sha1_to_hex(repl), path);
        }
@@@ -2899,9 -2908,10 +2904,9 @@@ static int write_loose_object(const uns
        git_zstream stream;
        git_SHA_CTX c;
        unsigned char parano_sha1[20];
 -      char *filename;
        static char tmp_file[PATH_MAX];
 +      const char *filename = sha1_file_name(sha1);
  
 -      filename = sha1_file_name(sha1);
        fd = create_tmpfile(tmp_file, sizeof(tmp_file), filename);
        if (fd < 0) {
                if (errno == EACCES)