index-pack: correct --keep[=<msg>]
[gitweb.git] / read-cache.c
index fb440b4d9d1aa002ebc760e4fa4e0f0d028fd868..7f5645e74546e459efdb584dbf63e1fd75857317 100644 (file)
@@ -990,11 +990,7 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
        }
 
        /* Make sure the array is big enough .. */
-       if (istate->cache_nr == istate->cache_alloc) {
-               istate->cache_alloc = alloc_nr(istate->cache_alloc);
-               istate->cache = xrealloc(istate->cache,
-                                       istate->cache_alloc * sizeof(*istate->cache));
-       }
+       ALLOC_GROW(istate->cache, istate->cache_nr + 1, istate->cache_alloc);
 
        /* Add it in.. */
        istate->cache_nr++;
@@ -1220,6 +1216,42 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
 
 #define INDEX_FORMAT_DEFAULT 3
 
+static int index_format_config(const char *var, const char *value, void *cb)
+{
+       unsigned int *version = cb;
+       if (!strcmp(var, "index.version")) {
+               *version = git_config_int(var, value);
+               return 0;
+       }
+       return 1;
+}
+
+static unsigned int get_index_format_default(void)
+{
+       char *envversion = getenv("GIT_INDEX_VERSION");
+       char *endp;
+       unsigned int version = INDEX_FORMAT_DEFAULT;
+
+       if (!envversion) {
+               git_config(index_format_config, &version);
+               if (version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < version) {
+                       warning(_("index.version set, but the value is invalid.\n"
+                                 "Using version %i"), INDEX_FORMAT_DEFAULT);
+                       return INDEX_FORMAT_DEFAULT;
+               }
+               return version;
+       }
+
+       version = strtoul(envversion, &endp, 10);
+       if (*endp ||
+           version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < version) {
+               warning(_("GIT_INDEX_VERSION set, but the value is invalid.\n"
+                         "Using version %i"), INDEX_FORMAT_DEFAULT);
+               version = INDEX_FORMAT_DEFAULT;
+       }
+       return version;
+}
+
 /*
  * dev/ino/uid/gid/size are also just tracked to the low 32 bits
  * Again - this is just a (very strong in practice) heuristic that
@@ -1445,6 +1477,7 @@ int read_index_from(struct index_state *istate, const char *path)
        if (verify_hdr(hdr, mmap_size) < 0)
                goto unmap;
 
+       hashcpy(istate->sha1, (unsigned char *)hdr + mmap_size - 20);
        istate->version = ntohl(hdr->hdr_version);
        istate->cache_nr = ntohl(hdr->hdr_entries);
        istate->cache_alloc = alloc_nr(istate->cache_nr);
@@ -1728,6 +1761,50 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
        return result;
 }
 
+/*
+ * This function verifies if index_state has the correct sha1 of the
+ * index file.  Don't die if we have any other failure, just return 0.
+ */
+static int verify_index_from(const struct index_state *istate, const char *path)
+{
+       int fd;
+       ssize_t n;
+       struct stat st;
+       unsigned char sha1[20];
+
+       if (!istate->initialized)
+               return 0;
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return 0;
+
+       if (fstat(fd, &st))
+               goto out;
+
+       if (st.st_size < sizeof(struct cache_header) + 20)
+               goto out;
+
+       n = pread_in_full(fd, sha1, 20, st.st_size - 20);
+       if (n != 20)
+               goto out;
+
+       if (hashcmp(istate->sha1, sha1))
+               goto out;
+
+       close(fd);
+       return 1;
+
+out:
+       close(fd);
+       return 0;
+}
+
+static int verify_index(const struct index_state *istate)
+{
+       return verify_index_from(istate, get_index_file());
+}
+
 static int has_racy_timestamp(struct index_state *istate)
 {
        int entries = istate->cache_nr;
@@ -1747,7 +1824,7 @@ static int has_racy_timestamp(struct index_state *istate)
 void update_index_if_able(struct index_state *istate, struct lock_file *lockfile)
 {
        if ((istate->cache_changed || has_racy_timestamp(istate)) &&
-           !write_index(istate, lockfile->fd))
+           verify_index(istate) && !write_index(istate, lockfile->fd))
                commit_locked_index(lockfile);
        else
                rollback_lock_file(lockfile);
@@ -1776,7 +1853,7 @@ int write_index(struct index_state *istate, int newfd)
        }
 
        if (!istate->version)
-               istate->version = INDEX_FORMAT_DEFAULT;
+               istate->version = get_index_format_default();
 
        /* demote version 3 to version 2 when the latter suffices */
        if (istate->version == 3 || istate->version == 2)