#define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
#include "config.h"
+#include "diff.h"
+#include "diffcore.h"
#include "tempfile.h"
#include "lockfile.h"
#include "cache-tree.h"
#include "refs.h"
#include "dir.h"
+#include "object-store.h"
#include "tree.h"
#include "commit.h"
#include "blob.h"
* Cache entries in istate->cache[] should have been allocated
* from the memory pool associated with this index, or from an
* associated split_index. There is no need to free individual
- * cache entries.
+ * cache entries. validate_cache_entries can detect when this
+ * assertion does not hold.
*/
+ validate_cache_entries(istate);
resolve_undo_clear_index(istate);
istate->cache_nr = 0;
istate->untracked = NULL;
if (istate->ce_mem_pool) {
- mem_pool_discard(istate->ce_mem_pool);
+ mem_pool_discard(istate->ce_mem_pool, should_validate_cache_entries());
istate->ce_mem_pool = NULL;
}
return 0;
}
+/*
+ * Validate the cache entries of this index.
+ * All cache entries associated with this index
+ * should have been allocated by the memory pool
+ * associated with this index, or by a referenced
+ * split index.
+ */
+void validate_cache_entries(const struct index_state *istate)
+{
+ int i;
+
+ if (!should_validate_cache_entries() ||!istate || !istate->initialized)
+ return;
+
+ for (i = 0; i < istate->cache_nr; i++) {
+ if (!istate) {
+ die("internal error: cache entry is not allocated from expected memory pool");
+ } else if (!istate->ce_mem_pool ||
+ !mem_pool_contains(istate->ce_mem_pool, istate->cache[i])) {
+ if (!istate->split_index ||
+ !istate->split_index->base ||
+ !istate->split_index->base->ce_mem_pool ||
+ !mem_pool_contains(istate->split_index->base->ce_mem_pool, istate->cache[i])) {
+ die("internal error: cache entry is not allocated from expected memory pool");
+ }
+ }
+ }
+
+ if (istate->split_index)
+ validate_cache_entries(istate->split_index->base);
+}
+
int unmerged_index(const struct index_state *istate)
{
int i;
return 0;
}
+int index_has_changes(const struct index_state *istate,
+ struct tree *tree,
+ struct strbuf *sb)
+{
+ struct object_id cmp;
+ int i;
+
+ if (istate != &the_index) {
+ BUG("index_has_changes cannot yet accept istate != &the_index; do_diff_cache needs updating first.");
+ }
+ if (tree)
+ cmp = tree->object.oid;
+ if (tree || !get_oid_tree("HEAD", &cmp)) {
+ struct diff_options opt;
+
+ diff_setup(&opt);
+ opt.flags.exit_with_status = 1;
+ if (!sb)
+ opt.flags.quick = 1;
+ do_diff_cache(&cmp, &opt);
+ diffcore_std(&opt);
+ for (i = 0; sb && i < diff_queued_diff.nr; i++) {
+ if (i)
+ strbuf_addch(sb, ' ');
+ strbuf_addstr(sb, diff_queued_diff.queue[i]->two->path);
+ }
+ diff_flush(&opt);
+ return opt.flags.has_changes != 0;
+ } else {
+ for (i = 0; sb && i < istate->cache_nr; i++) {
+ if (i)
+ strbuf_addch(sb, ' ');
+ strbuf_addstr(sb, istate->cache[i]->name);
+ }
+ return !!istate->cache_nr;
+ }
+}
+
#define WRITE_BUFFER_SIZE 8192
static unsigned char write_buffer[WRITE_BUFFER_SIZE];
static unsigned long write_buffer_len;
/*
* Read the index file that is potentially unmerged into given
- * index_state, dropping any unmerged entries. Returns true if
- * the index is unmerged. Callers who want to refuse to work
- * from an unmerged state can call this and check its return value,
- * instead of calling read_cache().
+ * index_state, dropping any unmerged entries to stage #0 (potentially
+ * resulting in a path appearing as both a file and a directory in the
+ * index; the caller is responsible to clear out the extra entries
+ * before writing the index to a tree). Returns true if the index is
+ * unmerged. Callers who want to refuse to work from an unmerged
+ * state can call this and check its return value, instead of calling
+ * read_cache().
*/
int read_index_unmerged(struct index_state *istate)
{
new_ce->ce_flags = create_ce_flags(0) | CE_CONFLICTED;
new_ce->ce_namelen = len;
new_ce->ce_mode = ce->ce_mode;
- if (add_index_entry(istate, new_ce, 0))
+ if (add_index_entry(istate, new_ce, ADD_CACHE_SKIP_DFCHECK))
return error("%s: cannot drop to stage #0",
new_ce->name);
}
void discard_cache_entry(struct cache_entry *ce)
{
+ if (ce && should_validate_cache_entries())
+ memset(ce, 0xCD, cache_entry_size(ce->ce_namelen));
+
if (ce && ce->mem_pool_allocated)
return;
free(ce);
}
+
+int should_validate_cache_entries(void)
+{
+ static int validate_index_cache_entries = -1;
+
+ if (validate_index_cache_entries < 0) {
+ if (getenv("GIT_TEST_VALIDATE_INDEX_CACHE_ENTRIES"))
+ validate_index_cache_entries = 1;
+ else
+ validate_index_cache_entries = 0;
+ }
+
+ return validate_index_cache_entries;
+}