replace: add --graft option
[gitweb.git] / read-cache.c
index ba13353b377d4f27b9ff6cf1b85811fcca61e224..6a45966ec499b47efbc76719046b53633e8839a1 100644 (file)
@@ -422,18 +422,26 @@ int df_name_compare(const char *name1, int len1, int mode1,
        return c1 - c2;
 }
 
-int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2)
+int name_compare(const char *name1, size_t len1, const char *name2, size_t len2)
 {
-       int len = len1 < len2 ? len1 : len2;
-       int cmp;
-
-       cmp = memcmp(name1, name2, len);
+       size_t min_len = (len1 < len2) ? len1 : len2;
+       int cmp = memcmp(name1, name2, min_len);
        if (cmp)
                return cmp;
        if (len1 < len2)
                return -1;
        if (len1 > len2)
                return 1;
+       return 0;
+}
+
+int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2)
+{
+       int cmp;
+
+       cmp = name_compare(name1, len1, name2, len2);
+       if (cmp)
+               return cmp;
 
        if (stage1 < stage2)
                return -1;
@@ -442,11 +450,6 @@ int cache_name_stage_compare(const char *name1, int len1, int stage1, const char
        return 0;
 }
 
-int cache_name_compare(const char *name1, int len1, const char *name2, int len2)
-{
-       return cache_name_stage_compare(name1, len1, 0, name2, len2, 0);
-}
-
 static int index_name_stage_pos(const struct index_state *istate, const char *name, int namelen, int stage)
 {
        int first, last;
@@ -1477,6 +1480,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);
@@ -1760,6 +1764,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;
@@ -1779,7 +1827,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);