diff options
Diffstat (limited to 'cache-tree.c')
-rw-r--r-- | cache-tree.c | 101 |
1 files changed, 70 insertions, 31 deletions
diff --git a/cache-tree.c b/cache-tree.c index d91743775d..37e4d008b5 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -22,8 +22,10 @@ void cache_tree_free(struct cache_tree **it_p) if (!it) return; for (i = 0; i < it->subtree_nr; i++) - if (it->down[i]) + if (it->down[i]) { cache_tree_free(&it->down[i]->cache_tree); + free(it->down[i]); + } free(it->down); free(it); *it_p = NULL; @@ -148,25 +150,24 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path) } static int verify_cache(struct cache_entry **cache, - int entries) + int entries, int flags) { int i, funny; + int silent = flags & WRITE_TREE_SILENT; /* Verify that the tree is merged */ funny = 0; for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; - if (ce_stage(ce) || (ce->ce_flags & CE_INTENT_TO_ADD)) { + if (ce_stage(ce)) { + if (silent) + return -1; if (10 < ++funny) { 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) @@ -237,12 +238,17 @@ static int update_one(struct cache_tree *it, int entries, const char *base, int baselen, - int missing_ok, - int dryrun) + int *skip_count, + int flags) { struct strbuf buffer; + int missing_ok = flags & WRITE_TREE_MISSING_OK; + int dryrun = flags & WRITE_TREE_DRY_RUN; + int to_invalidate = 0; int i; + *skip_count = 0; + if (0 <= it->entry_count && has_sha1_file(it->sha1)) return it->entry_count; @@ -257,11 +263,12 @@ static int update_one(struct cache_tree *it, /* * Find the subtrees and update them. */ - for (i = 0; i < entries; i++) { + i = 0; + while (i < entries) { 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); @@ -269,8 +276,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) * ==> @@ -284,11 +293,13 @@ static int update_one(struct cache_tree *it, cache + i, entries - i, path, baselen + sublen + 1, - missing_ok, - dryrun); + &subskip, + flags); if (subcnt < 0) return subcnt; - i += subcnt - 1; + i += subcnt; + sub->count = subcnt; /* to be used in the next loop */ + *skip_count += subskip; sub->used = 1; } @@ -299,7 +310,8 @@ static int update_one(struct cache_tree *it, */ strbuf_init(&buffer, 8192); - for (i = 0; i < entries; i++) { + i = 0; + while (i < entries) { struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; @@ -319,21 +331,43 @@ 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; } else { sha1 = ce->sha1; mode = ce->ce_mode; entlen = pathlen - baselen; + i++; } - if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) + if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) { + strbuf_release(&buffer); return error("invalid object %06o %s for '%.*s'", mode, sha1_to_hex(sha1), entlen+baselen, path); + } - if (ce->ce_flags & CE_REMOVE) - continue; /* entry being removed */ + /* + * 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'); @@ -353,7 +387,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, @@ -365,14 +399,13 @@ static int update_one(struct cache_tree *it, int cache_tree_update(struct cache_tree *it, struct cache_entry **cache, int entries, - int missing_ok, - int dryrun) + int flags) { - int i; - i = verify_cache(cache, entries); + int i, skip; + i = verify_cache(cache, entries, flags); if (i) return i; - i = update_one(it, cache, entries, "", 0, missing_ok, dryrun); + i = update_one(it, cache, entries, "", 0, &skip, flags); if (i < 0) return i; return 0; @@ -565,11 +598,9 @@ 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) { - int missing_ok = flags & WRITE_TREE_MISSING_OK; - if (cache_tree_update(active_cache_tree, active_cache, active_nr, - missing_ok, 0) < 0) + flags) < 0) return WRITE_TREE_UNMERGED_INDEX; if (0 <= newfd) { if (!write_cache(newfd, active_cache, active_nr) && @@ -664,3 +695,11 @@ int cache_tree_matches_traversal(struct cache_tree *root, return it->entry_count; return 0; } + +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); +} |