summaryrefslogtreecommitdiff
path: root/cache-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'cache-tree.c')
-rw-r--r--cache-tree.c207
1 files changed, 141 insertions, 66 deletions
diff --git a/cache-tree.c b/cache-tree.c
index 2440d1dc89..190c6e5aa6 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -3,6 +3,8 @@
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
+#include "object-store.h"
+#include "replace-object.h"
#ifndef DEBUG
#define DEBUG 0
@@ -49,7 +51,7 @@ static int subtree_pos(struct cache_tree *it, const char *path, int pathlen)
lo = 0;
hi = it->subtree_nr;
while (lo < hi) {
- int mi = (lo + hi) / 2;
+ int mi = lo + (hi - lo) / 2;
struct cache_tree_sub *mdl = down[mi];
int cmp = subtree_name_cmp(path, pathlen,
mdl->name, mdl->namelen);
@@ -84,9 +86,8 @@ static struct cache_tree_sub *find_subtree(struct cache_tree *it,
down->namelen = pathlen;
if (pos < it->subtree_nr)
- memmove(it->down + pos + 1,
- it->down + pos,
- sizeof(down) * (it->subtree_nr - pos - 1));
+ MOVE_ARRAY(it->down + pos + 1, it->down + pos,
+ it->subtree_nr - pos - 1);
it->down[pos] = down;
return down;
}
@@ -321,10 +322,11 @@ static int update_one(struct cache_tree *it,
struct cache_tree_sub *sub = NULL;
const char *path, *slash;
int pathlen, entlen;
- const unsigned char *sha1;
+ const struct object_id *oid;
unsigned mode;
int expected_missing = 0;
int contains_ita = 0;
+ int ce_missing_ok;
path = ce->name;
pathlen = ce_namelen(ce);
@@ -339,7 +341,7 @@ static int update_one(struct cache_tree *it,
die("cache-tree.c: '%.*s' in '%s' not found",
entlen, path + baselen, path);
i += sub->count;
- sha1 = sub->cache_tree->oid.hash;
+ oid = &sub->cache_tree->oid;
mode = S_IFDIR;
contains_ita = sub->cache_tree->entry_count < 0;
if (contains_ita) {
@@ -348,19 +350,22 @@ static int update_one(struct cache_tree *it,
}
}
else {
- sha1 = ce->oid.hash;
+ oid = &ce->oid;
mode = ce->ce_mode;
entlen = pathlen - baselen;
i++;
}
- if (is_null_sha1(sha1) ||
- (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1))) {
+ ce_missing_ok = mode == S_IFGITLINK || missing_ok ||
+ (repository_format_partial_clone &&
+ ce_skip_worktree(ce));
+ if (is_null_oid(oid) ||
+ (!ce_missing_ok && !has_object_file(oid))) {
strbuf_release(&buffer);
if (expected_missing)
return -1;
return error("invalid object %06o %s for '%.*s'",
- mode, sha1_to_hex(sha1), entlen+baselen, path);
+ mode, oid_to_hex(oid), entlen+baselen, path);
}
/*
@@ -386,12 +391,12 @@ static int update_one(struct cache_tree *it,
/*
* "sub" can be an empty tree if all subentries are i-t-a.
*/
- if (contains_ita && !hashcmp(sha1, EMPTY_TREE_SHA1_BIN))
+ if (contains_ita && is_empty_tree_oid(oid))
continue;
strbuf_grow(&buffer, entlen + 100);
strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
- strbuf_add(&buffer, sha1, 20);
+ strbuf_add(&buffer, oid->hash, the_hash_algo->rawsz);
#if DEBUG
fprintf(stderr, "cache-tree update-one %o %.*s\n",
@@ -400,16 +405,16 @@ static int update_one(struct cache_tree *it,
}
if (repair) {
- unsigned char sha1[20];
- hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1);
- if (has_sha1_file(sha1))
- hashcpy(it->oid.hash, sha1);
+ struct object_id oid;
+ hash_object_file(buffer.buf, buffer.len, tree_type, &oid);
+ if (has_object_file(&oid))
+ oidcpy(&it->oid, &oid);
else
to_invalidate = 1;
- } else if (dryrun)
- hash_sha1_file(buffer.buf, buffer.len, tree_type,
- it->oid.hash);
- else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->oid.hash)) {
+ } else if (dryrun) {
+ hash_object_file(buffer.buf, buffer.len, tree_type, &it->oid);
+ } else if (write_object_file(buffer.buf, buffer.len, tree_type,
+ &it->oid)) {
strbuf_release(&buffer);
return -1;
}
@@ -433,7 +438,9 @@ int cache_tree_update(struct index_state *istate, int flags)
if (i)
return i;
+ trace_performance_enter();
i = update_one(it, cache, entries, "", 0, &skip, flags);
+ trace_performance_leave("cache_tree_update");
if (i < 0)
return i;
istate->cache_changed |= CACHE_TREE_CHANGED;
@@ -466,7 +473,7 @@ static void write_one(struct strbuf *buffer, struct cache_tree *it,
#endif
if (0 <= it->entry_count) {
- strbuf_add(buffer, it->oid.hash, 20);
+ strbuf_add(buffer, it->oid.hash, the_hash_algo->rawsz);
}
for (i = 0; i < it->subtree_nr; i++) {
struct cache_tree_sub *down = it->down[i];
@@ -493,6 +500,7 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
char *ep;
struct cache_tree *it;
int i, subtree_nr;
+ const unsigned rawsz = the_hash_algo->rawsz;
it = NULL;
/* skip name, but make sure name exists */
@@ -521,11 +529,11 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
goto free_return;
buf++; size--;
if (0 <= it->entry_count) {
- if (size < 20)
+ if (size < rawsz)
goto free_return;
- hashcpy(it->oid.hash, (const unsigned char*)buf);
- buf += 20;
- size -= 20;
+ oidread(&it->oid, (const unsigned char *)buf);
+ buf += rawsz;
+ size -= rawsz;
}
#if DEBUG
@@ -600,22 +608,19 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
return it;
}
-int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
+int write_index_as_tree(struct object_id *oid, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
{
- int entries, was_valid, newfd;
- struct lock_file *lock_file;
+ int entries, was_valid;
+ struct lock_file lock_file = LOCK_INIT;
+ int ret = 0;
- /*
- * We can't free this memory, it becomes part of a linked list
- * parsed atexit()
- */
- lock_file = xcalloc(1, sizeof(struct lock_file));
-
- newfd = hold_lock_file_for_update(lock_file, index_path, LOCK_DIE_ON_ERROR);
+ hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
- entries = read_index_from(index_state, index_path);
- if (entries < 0)
- return WRITE_TREE_UNREADABLE_INDEX;
+ entries = read_index_from(index_state, index_path, get_git_dir());
+ if (entries < 0) {
+ ret = WRITE_TREE_UNREADABLE_INDEX;
+ goto out;
+ }
if (flags & WRITE_TREE_IGNORE_CACHE_TREE)
cache_tree_free(&index_state->cache_tree);
@@ -624,12 +629,11 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
was_valid = cache_tree_fully_valid(index_state->cache_tree);
if (!was_valid) {
- if (cache_tree_update(index_state, flags) < 0)
- return WRITE_TREE_UNMERGED_INDEX;
- if (0 <= newfd) {
- if (!write_locked_index(index_state, lock_file, COMMIT_LOCK))
- newfd = -1;
+ if (cache_tree_update(index_state, flags) < 0) {
+ ret = WRITE_TREE_UNMERGED_INDEX;
+ goto out;
}
+ write_locked_index(index_state, &lock_file, COMMIT_LOCK);
/* Not being able to write is fine -- we are only interested
* in updating the cache-tree part, and if the next caller
* ends up using the old index with unupdated cache-tree part
@@ -641,25 +645,23 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
if (prefix) {
struct cache_tree *subtree;
subtree = cache_tree_find(index_state->cache_tree, prefix);
- if (!subtree)
- return WRITE_TREE_PREFIX_ERROR;
- hashcpy(sha1, subtree->oid.hash);
+ if (!subtree) {
+ ret = WRITE_TREE_PREFIX_ERROR;
+ goto out;
+ }
+ oidcpy(oid, &subtree->oid);
}
else
- hashcpy(sha1, index_state->cache_tree->oid.hash);
+ oidcpy(oid, &index_state->cache_tree->oid);
- if (0 <= newfd)
- rollback_lock_file(lock_file);
-
- return 0;
+out:
+ rollback_lock_file(&lock_file);
+ return ret;
}
-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)
+static void prime_cache_tree_rec(struct repository *r,
+ struct cache_tree *it,
+ struct tree *tree)
{
struct tree_desc desc;
struct name_entry entry;
@@ -673,23 +675,25 @@ 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.oid);
+ struct tree *subtree = lookup_tree(r, entry.oid);
if (!subtree->object.parsed)
parse_tree(subtree);
sub = cache_tree_sub(it, entry.path);
sub->cache_tree = cache_tree();
- prime_cache_tree_rec(sub->cache_tree, subtree);
+ prime_cache_tree_rec(r, sub->cache_tree, subtree);
cnt += sub->cache_tree->entry_count;
}
}
it->entry_count = cnt;
}
-void prime_cache_tree(struct index_state *istate, struct tree *tree)
+void prime_cache_tree(struct repository *r,
+ struct index_state *istate,
+ struct tree *tree)
{
cache_tree_free(&istate->cache_tree);
istate->cache_tree = cache_tree();
- prime_cache_tree_rec(istate->cache_tree, tree);
+ prime_cache_tree_rec(r, istate->cache_tree, tree);
istate->cache_changed |= CACHE_TREE_CHANGED;
}
@@ -720,14 +724,85 @@ 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 && !oidcmp(ent->oid, &it->oid))
+ if (it && it->entry_count > 0 && oideq(ent->oid, &it->oid))
return it->entry_count;
return 0;
}
-int update_main_cache_tree(int flags)
+static void verify_one(struct repository *r,
+ struct index_state *istate,
+ struct cache_tree *it,
+ struct strbuf *path)
+{
+ int i, pos, len = path->len;
+ struct strbuf tree_buf = STRBUF_INIT;
+ struct object_id new_oid;
+
+ for (i = 0; i < it->subtree_nr; i++) {
+ strbuf_addf(path, "%s/", it->down[i]->name);
+ verify_one(r, istate, it->down[i]->cache_tree, path);
+ strbuf_setlen(path, len);
+ }
+
+ if (it->entry_count < 0 ||
+ /* no verification on tests (t7003) that replace trees */
+ lookup_replace_object(r, &it->oid) != &it->oid)
+ return;
+
+ if (path->len) {
+ pos = index_name_pos(istate, path->buf, path->len);
+ pos = -pos - 1;
+ } else {
+ pos = 0;
+ }
+
+ i = 0;
+ while (i < it->entry_count) {
+ struct cache_entry *ce = istate->cache[pos + i];
+ const char *slash;
+ struct cache_tree_sub *sub = NULL;
+ const struct object_id *oid;
+ const char *name;
+ unsigned mode;
+ int entlen;
+
+ if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE))
+ BUG("%s with flags 0x%x should not be in cache-tree",
+ ce->name, ce->ce_flags);
+ name = ce->name + path->len;
+ slash = strchr(name, '/');
+ if (slash) {
+ entlen = slash - name;
+ sub = find_subtree(it, ce->name + path->len, entlen, 0);
+ if (!sub || sub->cache_tree->entry_count < 0)
+ BUG("bad subtree '%.*s'", entlen, name);
+ oid = &sub->cache_tree->oid;
+ mode = S_IFDIR;
+ i += sub->cache_tree->entry_count;
+ } else {
+ oid = &ce->oid;
+ mode = ce->ce_mode;
+ entlen = ce_namelen(ce) - path->len;
+ i++;
+ }
+ strbuf_addf(&tree_buf, "%o %.*s%c", mode, entlen, name, '\0');
+ strbuf_add(&tree_buf, oid->hash, the_hash_algo->rawsz);
+ }
+ hash_object_file(tree_buf.buf, tree_buf.len, tree_type, &new_oid);
+ if (!oideq(&new_oid, &it->oid))
+ BUG("cache-tree for path %.*s does not match. "
+ "Expected %s got %s", len, path->buf,
+ oid_to_hex(&new_oid), oid_to_hex(&it->oid));
+ strbuf_setlen(path, len);
+ strbuf_release(&tree_buf);
+}
+
+void cache_tree_verify(struct repository *r, struct index_state *istate)
{
- if (!the_index.cache_tree)
- the_index.cache_tree = cache_tree();
- return cache_tree_update(&the_index, flags);
+ struct strbuf path = STRBUF_INIT;
+
+ if (!istate->cache_tree)
+ return;
+ verify_one(r, istate, istate->cache_tree, &path);
+ strbuf_release(&path);
}