summaryrefslogtreecommitdiff
path: root/cache-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'cache-tree.c')
-rw-r--r--cache-tree.c155
1 files changed, 90 insertions, 65 deletions
diff --git a/cache-tree.c b/cache-tree.c
index 0bbec43216..345ea35963 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,18 +76,12 @@ 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);
+ FLEX_ALLOC_MEM(down, name, path, pathlen);
down->cache_tree = NULL;
down->namelen = pathlen;
- memcpy(down->name, path, pathlen);
- down->name[pathlen] = 0;
if (pos < it->subtree_nr)
memmove(it->down + pos + 1,
@@ -102,7 +97,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 +115,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,15 +136,21 @@ 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;
}
-static int verify_cache(const struct cache_entry * const *cache,
+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,
int entries, int flags)
{
int i, funny;
@@ -167,7 +168,7 @@ static int verify_cache(const struct cache_entry * const *cache,
break;
}
fprintf(stderr, "%s: unmerged (%s)\n",
- ce->name, sha1_to_hex(ce->sha1));
+ ce->name, oid_to_hex(&ce->oid));
}
}
if (funny)
@@ -234,7 +235,7 @@ int cache_tree_fully_valid(struct cache_tree *it)
}
static int update_one(struct cache_tree *it,
- const struct cache_entry * const *cache,
+ struct cache_entry **cache,
int entries,
const char *base,
int baselen,
@@ -244,9 +245,12 @@ static int update_one(struct cache_tree *it,
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))
@@ -297,6 +301,8 @@ static int update_one(struct cache_tree *it,
flags);
if (subcnt < 0)
return subcnt;
+ 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;
@@ -313,11 +319,13 @@ static int update_one(struct cache_tree *it,
i = 0;
while (i < entries) {
const struct cache_entry *ce = cache[i];
- struct cache_tree_sub *sub;
+ struct cache_tree_sub *sub = NULL;
const char *path, *slash;
int pathlen, entlen;
const unsigned char *sha1;
unsigned mode;
+ int expected_missing = 0;
+ int contains_ita = 0;
path = ce->name;
pathlen = ce_namelen(ce);
@@ -334,17 +342,22 @@ static int update_one(struct cache_tree *it,
i += sub->count;
sha1 = sub->cache_tree->sha1;
mode = S_IFDIR;
- if (sub->cache_tree->entry_count < 0)
+ contains_ita = sub->cache_tree->entry_count < 0;
+ if (contains_ita) {
to_invalidate = 1;
+ expected_missing = 1;
+ }
}
else {
- sha1 = ce->sha1;
+ sha1 = ce->oid.hash;
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);
}
@@ -364,11 +377,17 @@ static int update_one(struct cache_tree *it,
* 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) {
+ if (!sub && ce_intent_to_add(ce)) {
to_invalidate = 1;
continue;
}
+ /*
+ * "sub" can be an empty tree if all subentries are i-t-a.
+ */
+ if (contains_ita && !hashcmp(sha1, EMPTY_TREE_SHA1_BIN))
+ continue;
+
strbuf_grow(&buffer, entlen + 100);
strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
strbuf_add(&buffer, sha1, 20);
@@ -379,7 +398,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);
@@ -396,18 +422,19 @@ static int update_one(struct cache_tree *it,
return i;
}
-int cache_tree_update(struct cache_tree *it,
- const struct cache_entry * const *cache,
- int entries,
- int flags)
+int cache_tree_update(struct index_state *istate, int flags)
{
- int i, skip;
- 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, &skip, flags);
if (i < 0)
return i;
+ istate->cache_changed |= CACHE_TREE_CHANGED;
return 0;
}
@@ -554,27 +581,24 @@ 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;
}
-int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
+int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
{
int entries, was_valid, newfd;
struct lock_file *lock_file;
@@ -585,26 +609,23 @@ int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
*/
lock_file = xcalloc(1, sizeof(struct lock_file));
- newfd = hold_locked_index(lock_file, 1);
+ newfd = hold_lock_file_for_update(lock_file, index_path, LOCK_DIE_ON_ERROR);
- entries = read_cache();
+ entries = read_index_from(index_state, index_path);
if (entries < 0)
return WRITE_TREE_UNREADABLE_INDEX;
if (flags & WRITE_TREE_IGNORE_CACHE_TREE)
- cache_tree_free(&(active_cache_tree));
+ cache_tree_free(&index_state->cache_tree);
- if (!active_cache_tree)
- active_cache_tree = cache_tree();
+ if (!index_state->cache_tree)
+ index_state->cache_tree = cache_tree();
- was_valid = cache_tree_fully_valid(active_cache_tree);
+ was_valid = cache_tree_fully_valid(index_state->cache_tree);
if (!was_valid) {
- if (cache_tree_update(active_cache_tree,
- (const struct cache_entry * const *)active_cache,
- active_nr, flags) < 0)
+ if (cache_tree_update(index_state, 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(index_state, lock_file, COMMIT_LOCK))
newfd = -1;
}
/* Not being able to write is fine -- we are only interested
@@ -616,14 +637,14 @@ int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
}
if (prefix) {
- struct cache_tree *subtree =
- cache_tree_find(active_cache_tree, prefix);
+ struct cache_tree *subtree;
+ subtree = cache_tree_find(index_state->cache_tree, prefix);
if (!subtree)
return WRITE_TREE_PREFIX_ERROR;
hashcpy(sha1, subtree->sha1);
}
else
- hashcpy(sha1, active_cache_tree->sha1);
+ hashcpy(sha1, index_state->cache_tree->sha1);
if (0 <= newfd)
rollback_lock_file(lock_file);
@@ -631,13 +652,18 @@ int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
return 0;
}
+int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
+{
+ return write_index_as_tree(sha1, &the_index, get_index_file(), flags, prefix);
+}
+
static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
{
struct tree_desc desc;
struct name_entry entry;
int cnt;
- hashcpy(it->sha1, tree->object.sha1);
+ hashcpy(it->sha1, tree->object.oid.hash);
init_tree_desc(&desc, tree->buffer, tree->size);
cnt = 0;
while (tree_entry(&desc, &entry)) {
@@ -645,7 +671,7 @@ static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
cnt++;
else {
struct cache_tree_sub *sub;
- struct tree *subtree = lookup_tree(entry.sha1);
+ struct tree *subtree = lookup_tree(entry.oid->hash);
if (!subtree->object.parsed)
parse_tree(subtree);
sub = cache_tree_sub(it, entry.path);
@@ -657,11 +683,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;
}
/*
@@ -691,7 +718,7 @@ int cache_tree_matches_traversal(struct cache_tree *root,
it = find_cache_tree_from_traversal(root, info);
it = cache_tree_find(it, ent->path);
- if (it && it->entry_count > 0 && !hashcmp(ent->sha1, it->sha1))
+ if (it && it->entry_count > 0 && !hashcmp(ent->oid->hash, it->sha1))
return it->entry_count;
return 0;
}
@@ -700,7 +727,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,
- (const struct cache_entry * const *)the_index.cache,
- the_index.cache_nr, flags);
+ return cache_tree_update(&the_index, flags);
}