t5520: test for failure if index has unresolved entries
[gitweb.git] / read-cache.c
index 8ecb9599e58d3e08e6cf84f3d5403eae59d1e997..9cff715d6b669ecf05f861bc553b61d20d04191d 100644 (file)
@@ -5,6 +5,7 @@
  */
 #define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
+#include "lockfile.h"
 #include "cache-tree.h"
 #include "refs.h"
 #include "dir.h"
@@ -16,6 +17,7 @@
 #include "varint.h"
 #include "split-index.h"
 #include "sigchain.h"
+#include "utf8.h"
 
 static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
                                               unsigned int options);
@@ -434,18 +436,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;
@@ -454,11 +464,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;
@@ -772,9 +777,10 @@ static int verify_dotfile(const char *rest)
         * shares the path end test with the ".." case.
         */
        case 'g':
-               if (rest[1] != 'i')
+       case 'G':
+               if (rest[1] != 'i' && rest[1] != 'I')
                        break;
-               if (rest[2] != 't')
+               if (rest[2] != 't' && rest[2] != 'T')
                        break;
                rest += 2;
        /* fallthrough */
@@ -798,6 +804,10 @@ int verify_path(const char *path)
                        return 1;
                if (is_dir_sep(c)) {
 inside:
+                       if (protect_hfs && is_hfs_dotgit(path))
+                               return 0;
+                       if (protect_ntfs && is_ntfs_dotgit(path))
+                               return 0;
                        c = *path++;
                        if ((c == '.' && !verify_dotfile(path)) ||
                            is_dir_sep(c) || c == '\0')
@@ -1061,6 +1071,14 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
                return ce;
        }
 
+       if (has_symlink_leading_path(ce->name, ce_namelen(ce))) {
+               if (ignore_missing)
+                       return ce;
+               if (err)
+                       *err = ENOENT;
+               return NULL;
+       }
+
        if (lstat(ce->name, &st) < 0) {
                if (ignore_missing && errno == ENOENT)
                        return ce;
@@ -1235,24 +1253,16 @@ 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;
+       int value;
        unsigned int version = INDEX_FORMAT_DEFAULT;
 
        if (!envversion) {
-               git_config(index_format_config, &version);
+               if (!git_config_get_int("index.version", &value))
+                       version = value;
                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);
@@ -1364,6 +1374,14 @@ static int read_index_extension(struct index_state *istate,
        return 0;
 }
 
+int hold_locked_index(struct lock_file *lk, int die_on_error)
+{
+       return hold_lock_file_for_update(lk, get_index_file(),
+                                        die_on_error
+                                        ? LOCK_DIE_ON_ERROR
+                                        : 0);
+}
+
 int read_index(struct index_state *istate)
 {
        return read_index_from(istate, get_index_file());
@@ -1462,9 +1480,23 @@ static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk,
        return ce;
 }
 
+static void check_ce_order(struct cache_entry *ce, struct cache_entry *next_ce)
+{
+       int name_compare = strcmp(ce->name, next_ce->name);
+       if (0 < name_compare)
+               die("unordered stage entries in index");
+       if (!name_compare) {
+               if (!ce_stage(ce))
+                       die("multiple stage entries for merged file '%s'",
+                               ce->name);
+               if (ce_stage(ce) > ce_stage(next_ce))
+                       die("unordered stage entries for '%s'",
+                               ce->name);
+       }
+}
+
 /* remember to discard_cache() before reading a different cache! */
-static int do_read_index(struct index_state *istate, const char *path,
-                        int must_exist)
+int do_read_index(struct index_state *istate, const char *path, int must_exist)
 {
        int fd, i;
        struct stat st;
@@ -1524,6 +1556,9 @@ static int do_read_index(struct index_state *istate, const char *path,
                ce = create_from_disk(disk_ce, &consumed, previous_name);
                set_index_entry(istate, i, ce);
 
+               if (i > 0)
+                       check_ce_order(istate->cache[i - 1], ce);
+
                src_offset += consumed;
        }
        strbuf_release(&previous_name_buf);
@@ -1839,6 +1874,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;
@@ -1858,6 +1937,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)) &&
+           verify_index(istate) &&
            write_locked_index(istate, lockfile, COMMIT_LOCK))
                rollback_lock_file(lockfile);
 }
@@ -1885,8 +1965,11 @@ static int do_write_index(struct index_state *istate, int newfd,
                }
        }
 
-       if (!istate->version)
+       if (!istate->version) {
                istate->version = get_index_format_default();
+               if (getenv("GIT_TEST_SPLIT_INDEX"))
+                       init_split_index(istate);
+       }
 
        /* demote version 3 to version 2 when the latter suffices */
        if (istate->version == 3 || istate->version == 2)
@@ -1973,16 +2056,10 @@ void set_alternate_index_output(const char *name)
 
 static int commit_locked_index(struct lock_file *lk)
 {
-       if (alternate_index_output) {
-               if (lk->fd >= 0 && close_lock_file(lk))
-                       return -1;
-               if (rename(lk->filename, alternate_index_output))
-                       return -1;
-               lk->filename[0] = 0;
-               return 0;
-       } else {
+       if (alternate_index_output)
+               return commit_lock_file_to(lk, alternate_index_output);
+       else
                return commit_lock_file(lk);
-       }
 }
 
 static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
@@ -2030,14 +2107,21 @@ static void remove_temporary_sharedindex_on_signal(int signo)
        raise(signo);
 }
 
-static int write_shared_index(struct index_state *istate)
+static int write_shared_index(struct index_state *istate,
+                             struct lock_file *lock, unsigned flags)
 {
        struct split_index *si = istate->split_index;
        static int installed_handler;
        int fd, ret;
 
        temporary_sharedindex = git_pathdup("sharedindex_XXXXXX");
-       fd = xmkstemp(temporary_sharedindex);
+       fd = mkstemp(temporary_sharedindex);
+       if (fd < 0) {
+               free(temporary_sharedindex);
+               temporary_sharedindex = NULL;
+               hashclr(si->base_sha1);
+               return do_write_locked_index(istate, lock, flags);
+       }
        if (!installed_handler) {
                atexit(remove_temporary_sharedindex);
                sigchain_push_common(remove_temporary_sharedindex_on_signal);
@@ -2063,14 +2147,20 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
 {
        struct split_index *si = istate->split_index;
 
-       if (!si || (istate->cache_changed & ~EXTMASK)) {
+       if (!si || alternate_index_output ||
+           (istate->cache_changed & ~EXTMASK)) {
                if (si)
                        hashclr(si->base_sha1);
                return do_write_locked_index(istate, lock, flags);
        }
 
+       if (getenv("GIT_TEST_SPLIT_INDEX")) {
+               int v = si->base_sha1[0];
+               if ((v & 15) < 6)
+                       istate->cache_changed |= SPLIT_INDEX_ORDERED;
+       }
        if (istate->cache_changed & SPLIT_INDEX_ORDERED) {
-               int ret = write_shared_index(istate);
+               int ret = write_shared_index(istate, lock, flags);
                if (ret)
                        return ret;
        }
@@ -2109,7 +2199,6 @@ int read_index_unmerged(struct index_state *istate)
                if (add_index_entry(istate, new_ce, 0))
                        return error("%s: cannot drop to stage #0",
                                     new_ce->name);
-               i = index_name_pos(istate, new_ce->name, len);
        }
        return unmerged;
 }