summaryrefslogtreecommitdiff
path: root/cache-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'cache-tree.c')
-rw-r--r--cache-tree.c162
1 files changed, 102 insertions, 60 deletions
diff --git a/cache-tree.c b/cache-tree.c
index 28ed6574a2..32772b9564 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
@@ -75,11 +76,7 @@ static struct cache_tree_sub *find_subtree(struct cache_tree *it,
return NULL;
pos = -pos-1;
- if (it->subtree_alloc <= it->subtree_nr) {
- it->subtree_alloc = alloc_nr(it->subtree_alloc);
- it->down = xrealloc(it->down, it->subtree_alloc *
- sizeof(*it->down));
- }
+ ALLOC_GROW(it->down, it->subtree_nr + 1, it->subtree_alloc);
it->subtree_nr++;
down = xmalloc(sizeof(*down) + pathlen + 1);
@@ -102,7 +99,7 @@ struct cache_tree_sub *cache_tree_sub(struct cache_tree *it, const char *path)
return find_subtree(it, path, pathlen, 1);
}
-void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
+static int do_invalidate_path(struct cache_tree *it, const char *path)
{
/* a/b/c
* ==> invalidate self
@@ -120,12 +117,12 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
#endif
if (!it)
- return;
- slash = strchr(path, '/');
+ return 0;
+ slash = strchrnul(path, '/');
+ namelen = slash - path;
it->entry_count = -1;
- if (!slash) {
+ if (!*slash) {
int pos;
- namelen = strlen(path);
pos = subtree_pos(it, path, namelen);
if (0 <= pos) {
cache_tree_free(&it->down[pos]->cache_tree);
@@ -141,12 +138,18 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
(it->subtree_nr - pos - 1));
it->subtree_nr--;
}
- return;
+ return 1;
}
- namelen = slash - path;
down = find_subtree(it, path, namelen, 0);
if (down)
- cache_tree_invalidate_path(down->cache_tree, slash + 1);
+ do_invalidate_path(down->cache_tree, slash + 1);
+ return 1;
+}
+
+void cache_tree_invalidate_path(struct index_state *istate, const char *path)
+{
+ if (do_invalidate_path(istate->cache_tree, path))
+ istate->cache_changed |= CACHE_TREE_CHANGED;
}
static int verify_cache(struct cache_entry **cache,
@@ -158,7 +161,7 @@ static int verify_cache(struct cache_entry **cache,
/* Verify that the tree is merged */
funny = 0;
for (i = 0; i < entries; i++) {
- struct cache_entry *ce = cache[i];
+ const struct cache_entry *ce = cache[i];
if (ce_stage(ce)) {
if (silent)
return -1;
@@ -166,12 +169,8 @@ static int verify_cache(struct cache_entry **cache,
fprintf(stderr, "...\n");
break;
}
- if (ce_stage(ce))
- fprintf(stderr, "%s: unmerged (%s)\n",
- ce->name, sha1_to_hex(ce->sha1));
- else
- fprintf(stderr, "%s: not added yet\n",
- ce->name);
+ fprintf(stderr, "%s: unmerged (%s)\n",
+ ce->name, sha1_to_hex(ce->sha1));
}
}
if (funny)
@@ -242,13 +241,20 @@ static int update_one(struct cache_tree *it,
int entries,
const char *base,
int baselen,
+ int *skip_count,
int flags)
{
struct strbuf buffer;
int missing_ok = flags & WRITE_TREE_MISSING_OK;
int dryrun = flags & WRITE_TREE_DRY_RUN;
+ int repair = flags & WRITE_TREE_REPAIR;
+ int to_invalidate = 0;
int i;
+ assert(!(dryrun && repair));
+
+ *skip_count = 0;
+
if (0 <= it->entry_count && has_sha1_file(it->sha1))
return it->entry_count;
@@ -263,11 +269,12 @@ static int update_one(struct cache_tree *it,
/*
* Find the subtrees and update them.
*/
- for (i = 0; i < entries; i++) {
- struct cache_entry *ce = cache[i];
+ i = 0;
+ while (i < entries) {
+ const struct cache_entry *ce = cache[i];
struct cache_tree_sub *sub;
const char *path, *slash;
- int pathlen, sublen, subcnt;
+ int pathlen, sublen, subcnt, subskip;
path = ce->name;
pathlen = ce_namelen(ce);
@@ -275,8 +282,10 @@ static int update_one(struct cache_tree *it,
break; /* at the end of this level */
slash = strchr(path + baselen, '/');
- if (!slash)
+ if (!slash) {
+ i++;
continue;
+ }
/*
* a/bbb/c (base = a/, slash = /c)
* ==>
@@ -290,10 +299,15 @@ static int update_one(struct cache_tree *it,
cache + i, entries - i,
path,
baselen + sublen + 1,
+ &subskip,
flags);
if (subcnt < 0)
return subcnt;
- i += subcnt - 1;
+ if (!subcnt)
+ die("index cache-tree records empty sub-tree");
+ i += subcnt;
+ sub->count = subcnt; /* to be used in the next loop */
+ *skip_count += subskip;
sub->used = 1;
}
@@ -304,13 +318,15 @@ static int update_one(struct cache_tree *it,
*/
strbuf_init(&buffer, 8192);
- for (i = 0; i < entries; i++) {
- struct cache_entry *ce = cache[i];
+ i = 0;
+ while (i < entries) {
+ const struct cache_entry *ce = cache[i];
struct cache_tree_sub *sub;
const char *path, *slash;
int pathlen, entlen;
const unsigned char *sha1;
unsigned mode;
+ int expected_missing = 0;
path = ce->name;
pathlen = ce_namelen(ce);
@@ -324,23 +340,47 @@ static int update_one(struct cache_tree *it,
if (!sub)
die("cache-tree.c: '%.*s' in '%s' not found",
entlen, path + baselen, path);
- i += sub->cache_tree->entry_count - 1;
+ i += sub->count;
sha1 = sub->cache_tree->sha1;
mode = S_IFDIR;
+ if (sub->cache_tree->entry_count < 0) {
+ to_invalidate = 1;
+ expected_missing = 1;
+ }
}
else {
sha1 = ce->sha1;
mode = ce->ce_mode;
entlen = pathlen - baselen;
+ i++;
}
if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) {
strbuf_release(&buffer);
+ if (expected_missing)
+ return -1;
return error("invalid object %06o %s for '%.*s'",
mode, sha1_to_hex(sha1), entlen+baselen, path);
}
- if (ce->ce_flags & (CE_REMOVE | CE_INTENT_TO_ADD))
- continue; /* entry being removed or placeholder */
+ /*
+ * CE_REMOVE entries are removed before the index is
+ * written to disk. Skip them to remain consistent
+ * with the future on-disk index.
+ */
+ if (ce->ce_flags & CE_REMOVE) {
+ *skip_count = *skip_count + 1;
+ continue;
+ }
+
+ /*
+ * CE_INTENT_TO_ADD entries exist on on-disk index but
+ * they are not part of generated trees. Invalidate up
+ * to root to force cache-tree users to read elsewhere.
+ */
+ if (ce->ce_flags & CE_INTENT_TO_ADD) {
+ to_invalidate = 1;
+ continue;
+ }
strbuf_grow(&buffer, entlen + 100);
strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
@@ -352,7 +392,14 @@ static int update_one(struct cache_tree *it,
#endif
}
- if (dryrun)
+ if (repair) {
+ unsigned char sha1[20];
+ hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1);
+ if (has_sha1_file(sha1))
+ hashcpy(it->sha1, sha1);
+ else
+ to_invalidate = 1;
+ } else if (dryrun)
hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) {
strbuf_release(&buffer);
@@ -360,7 +407,7 @@ static int update_one(struct cache_tree *it,
}
strbuf_release(&buffer);
- it->entry_count = i;
+ it->entry_count = to_invalidate ? -1 : i - *skip_count;
#if DEBUG
fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
it->entry_count, it->subtree_nr,
@@ -369,18 +416,19 @@ static int update_one(struct cache_tree *it,
return i;
}
-int cache_tree_update(struct cache_tree *it,
- struct cache_entry **cache,
- int entries,
- int flags)
+int cache_tree_update(struct index_state *istate, int flags)
{
- int i;
- i = verify_cache(cache, entries, flags);
+ struct cache_tree *it = istate->cache_tree;
+ struct cache_entry **cache = istate->cache;
+ int entries = istate->cache_nr;
+ int skip, i = verify_cache(cache, entries, flags);
+
if (i)
return i;
- i = update_one(it, cache, entries, "", 0, flags);
+ i = update_one(it, cache, entries, "", 0, &skip, flags);
if (i < 0)
return i;
+ istate->cache_changed |= CACHE_TREE_CHANGED;
return 0;
}
@@ -527,22 +575,19 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
const char *slash;
struct cache_tree_sub *sub;
- slash = strchr(path, '/');
- if (!slash)
- slash = path + strlen(path);
- /* between path and slash is the name of the
- * subtree to look for.
+ slash = strchrnul(path, '/');
+ /*
+ * Between path and slash is the name of the subtree
+ * to look for.
*/
sub = find_subtree(it, path, slash - path, 0);
if (!sub)
return NULL;
it = sub->cache_tree;
- if (slash)
- while (*slash && *slash == '/')
- slash++;
- if (!slash || !*slash)
- return it; /* prefix ended with slashes */
+
path = slash;
+ while (*path == '/')
+ path++;
}
return it;
}
@@ -571,13 +616,10 @@ int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
was_valid = cache_tree_fully_valid(active_cache_tree);
if (!was_valid) {
- if (cache_tree_update(active_cache_tree,
- active_cache, active_nr,
- flags) < 0)
+ if (cache_tree_update(&the_index, flags) < 0)
return WRITE_TREE_UNMERGED_INDEX;
if (0 <= newfd) {
- if (!write_cache(newfd, active_cache, active_nr) &&
- !commit_lock_file(lock_file))
+ if (!write_locked_index(&the_index, lock_file, COMMIT_LOCK))
newfd = -1;
}
/* Not being able to write is fine -- we are only interested
@@ -630,11 +672,12 @@ static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
it->entry_count = cnt;
}
-void prime_cache_tree(struct cache_tree **it, struct tree *tree)
+void prime_cache_tree(struct index_state *istate, struct tree *tree)
{
- cache_tree_free(it);
- *it = cache_tree();
- prime_cache_tree_rec(*it, tree);
+ cache_tree_free(&istate->cache_tree);
+ istate->cache_tree = cache_tree();
+ prime_cache_tree_rec(istate->cache_tree, tree);
+ istate->cache_changed |= CACHE_TREE_CHANGED;
}
/*
@@ -673,6 +716,5 @@ int update_main_cache_tree(int flags)
{
if (!the_index.cache_tree)
the_index.cache_tree = cache_tree();
- return cache_tree_update(the_index.cache_tree,
- the_index.cache, the_index.cache_nr, flags);
+ return cache_tree_update(&the_index, flags);
}