Code

Merge git://repo.or.cz/git-gui
[git.git] / read-cache.c
index 5dc998d21e79a8950896e7bb0db38cb137faacc1..0382804e7694e9a0e87cc2dc8340187ddeea2d64 100644 (file)
@@ -198,7 +198,8 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
 
 static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce)
 {
-       return (istate->timestamp &&
+       return (!S_ISGITLINK(ce->ce_mode) &&
+               istate->timestamp &&
                ((unsigned int)istate->timestamp) <= ce->ce_mtime);
 }
 
@@ -429,21 +430,50 @@ static int index_name_pos_also_unmerged(struct index_state *istate,
        return pos;
 }
 
-int add_file_to_index(struct index_state *istate, const char *path, int verbose)
+static int different_name(struct cache_entry *ce, struct cache_entry *alias)
 {
-       int size, namelen, pos;
-       struct stat st;
-       struct cache_entry *ce;
-       unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
+       int len = ce_namelen(ce);
+       return ce_namelen(alias) != len || memcmp(ce->name, alias->name, len);
+}
 
-       if (lstat(path, &st))
-               die("%s: unable to stat (%s)", path, strerror(errno));
+/*
+ * If we add a filename that aliases in the cache, we will use the
+ * name that we already have - but we don't want to update the same
+ * alias twice, because that implies that there were actually two
+ * different files with aliasing names!
+ *
+ * So we use the CE_ADDED flag to verify that the alias was an old
+ * one before we accept it as
+ */
+static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_entry *alias)
+{
+       int len;
+       struct cache_entry *new;
+
+       if (alias->ce_flags & CE_ADDED)
+               die("Will not add file alias '%s' ('%s' already exists in index)", ce->name, alias->name);
+
+       /* Ok, create the new entry using the name of the existing alias */
+       len = ce_namelen(alias);
+       new = xcalloc(1, cache_entry_size(len));
+       memcpy(new->name, alias->name, len);
+       copy_cache_entry(new, ce);
+       free(ce);
+       return new;
+}
+
+int add_to_index(struct index_state *istate, const char *path, struct stat *st, int verbose)
+{
+       int size, namelen;
+       mode_t st_mode = st->st_mode;
+       struct cache_entry *ce, *alias;
+       unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
 
-       if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
+       if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
                die("%s: can only add regular files, symbolic links or git-directories", path);
 
        namelen = strlen(path);
-       if (S_ISDIR(st.st_mode)) {
+       if (S_ISDIR(st_mode)) {
                while (namelen && path[namelen-1] == '/')
                        namelen--;
        }
@@ -451,10 +481,10 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
        ce = xcalloc(1, size);
        memcpy(ce->name, path, namelen);
        ce->ce_flags = namelen;
-       fill_stat_cache_info(ce, &st);
+       fill_stat_cache_info(ce, st);
 
        if (trust_executable_bit && has_symlinks)
-               ce->ce_mode = create_ce_mode(st.st_mode);
+               ce->ce_mode = create_ce_mode(st_mode);
        else {
                /* If there is an existing entry, pick the mode bits and type
                 * from it, otherwise assume unexecutable regular file.
@@ -463,21 +493,22 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
                int pos = index_name_pos_also_unmerged(istate, path, namelen);
 
                ent = (0 <= pos) ? istate->cache[pos] : NULL;
-               ce->ce_mode = ce_mode_from_stat(ent, st.st_mode);
+               ce->ce_mode = ce_mode_from_stat(ent, st_mode);
        }
 
-       pos = index_name_pos(istate, ce->name, namelen);
-       if (0 <= pos &&
-           !ce_stage(istate->cache[pos]) &&
-           !ie_match_stat(istate, istate->cache[pos], &st, ce_option)) {
+       alias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case);
+       if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) {
                /* Nothing changed, really */
                free(ce);
-               ce_mark_uptodate(istate->cache[pos]);
+               ce_mark_uptodate(alias);
+               alias->ce_flags |= CE_ADDED;
                return 0;
        }
-
-       if (index_path(ce->sha1, path, &st, 1))
+       if (index_path(ce->sha1, path, st, 1))
                die("unable to index file %s", path);
+       if (ignore_case && alias && different_name(ce, alias))
+               ce = create_alias_ce(ce, alias);
+       ce->ce_flags |= CE_ADDED;
        if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
                die("unable to add %s to index",path);
        if (verbose)
@@ -485,6 +516,14 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
        return 0;
 }
 
+int add_file_to_index(struct index_state *istate, const char *path, int verbose)
+{
+       struct stat st;
+       if (lstat(path, &st))
+               die("%s: unable to stat (%s)", path, strerror(errno));
+       return add_to_index(istate, path, &st, verbose);
+}
+
 struct cache_entry *make_cache_entry(unsigned int mode,
                const unsigned char *sha1, const char *path, int stage,
                int refresh)
@@ -1311,7 +1350,7 @@ int write_index(const struct index_state *istate, int newfd)
                struct cache_entry *ce = cache[i];
                if (ce->ce_flags & CE_REMOVE)
                        continue;
-               if (is_racy_timestamp(istate, ce))
+               if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
                        ce_smudge_racily_clean_entry(ce);
                if (ce_write_entry(&c, newfd, ce) < 0)
                        return -1;