summaryrefslogtreecommitdiff
path: root/read-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'read-cache.c')
-rw-r--r--read-cache.c53
1 files changed, 46 insertions, 7 deletions
diff --git a/read-cache.c b/read-cache.c
index 6833af6cf1..5150c1e14b 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -43,6 +43,22 @@ static void replace_index_entry(struct index_state *istate, int nr, struct cache
istate->cache_changed = 1;
}
+void rename_index_entry_at(struct index_state *istate, int nr, const char *new_name)
+{
+ struct cache_entry *old = istate->cache[nr], *new;
+ int namelen = strlen(new_name);
+
+ new = xmalloc(cache_entry_size(namelen));
+ copy_cache_entry(new, old);
+ new->ce_flags &= ~(CE_STATE_MASK | CE_NAMEMASK);
+ new->ce_flags |= (namelen >= CE_NAMEMASK ? CE_NAMEMASK : namelen);
+ memcpy(new->name, new_name, namelen + 1);
+
+ cache_tree_invalidate_path(istate->cache_tree, old->name);
+ remove_index_entry_at(istate, nr);
+ add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+}
+
/*
* This only updates the "non-critical" parts of the directory
* cache, ie the parts that aren't tracked by GIT, and only used
@@ -136,7 +152,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
break;
case S_IFDIR:
if (S_ISGITLINK(ce->ce_mode))
- return 0;
+ return ce_compare_gitlink(ce) ? DATA_CHANGED : 0;
default:
return TYPE_CHANGED;
}
@@ -176,6 +192,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
changed |= TYPE_CHANGED;
break;
case S_IFGITLINK:
+ /* We ignore most of the st_xxx fields for gitlinks */
if (!S_ISDIR(st->st_mode))
changed |= TYPE_CHANGED;
else if (ce_compare_gitlink(ce))
@@ -186,7 +203,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
}
if (ce->ce_mtime != (unsigned int) st->st_mtime)
changed |= MTIME_CHANGED;
- if (ce->ce_ctime != (unsigned int) st->st_ctime)
+ if (trust_ctime && ce->ce_ctime != (unsigned int) st->st_ctime)
changed |= CTIME_CHANGED;
if (ce->ce_uid != (unsigned int) st->st_uid ||
@@ -282,11 +299,22 @@ int ie_modified(const struct index_state *istate,
if (changed & (MODE_CHANGED | TYPE_CHANGED))
return changed;
- /* Immediately after read-tree or update-index --cacheinfo,
- * the length field is zero. For other cases the ce_size
- * should match the SHA1 recorded in the index entry.
+ /*
+ * Immediately after read-tree or update-index --cacheinfo,
+ * the length field is zero, as we have never even read the
+ * lstat(2) information once, and we cannot trust DATA_CHANGED
+ * returned by ie_match_stat() which in turn was returned by
+ * ce_match_stat_basic() to signal that the filesize of the
+ * blob changed. We have to actually go to the filesystem to
+ * see if the contents match, and if so, should answer "unchanged".
+ *
+ * The logic does not apply to gitlinks, as ce_match_stat_basic()
+ * already has checked the actual HEAD from the filesystem in the
+ * subproject. If ie_match_stat() already said it is different,
+ * then we know it is.
*/
- if ((changed & DATA_CHANGED) && ce->ce_size != 0)
+ if ((changed & DATA_CHANGED) &&
+ (S_ISGITLINK(ce->ce_mode) || ce->ce_size != 0))
return changed;
changed_fs = ce_modified_check_fs(ce, st);
@@ -1095,6 +1123,10 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
ce->ce_size = ntohl(ondisk->size);
/* On-disk flags are just 16 bits */
ce->ce_flags = ntohs(ondisk->flags);
+
+ /* For future extension: we do not understand this entry yet */
+ if (ce->ce_flags & CE_EXTENDED)
+ die("Unknown index entry format");
hashcpy(ce->sha1, ondisk->sha1);
len = ce->ce_flags & CE_NAMEMASK;
@@ -1132,7 +1164,7 @@ int read_index_from(struct index_state *istate, const char *path)
size_t mmap_size;
errno = EBUSY;
- if (istate->alloc)
+ if (istate->initialized)
return istate->cache_nr;
errno = ENOENT;
@@ -1172,6 +1204,7 @@ int read_index_from(struct index_state *istate, const char *path)
* index size
*/
istate->alloc = xmalloc(estimate_cache_size(mmap_size, istate->cache_nr));
+ istate->initialized = 1;
src_offset = sizeof(*hdr);
dst_offset = 0;
@@ -1224,6 +1257,7 @@ int discard_index(struct index_state *istate)
cache_tree_free(&(istate->cache_tree));
free(istate->alloc);
istate->alloc = NULL;
+ istate->initialized = 0;
/* no need to throw away allocated active_cache */
return 0;
@@ -1315,6 +1349,11 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
* falsely clean entry due to touch-update-touch race, so we leave
* everything else as they are. We are called for entries whose
* ce_mtime match the index file mtime.
+ *
+ * Note that this actually does not do much for gitlinks, for
+ * which ce_match_stat_basic() always goes to the actual
+ * contents. The caller checks with is_racy_timestamp() which
+ * always says "no" for gitlinks, so we are not called for them ;-)
*/
struct stat st;