X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=cache-tree.c;h=f755590da827234830d8b4359720cfbfd87a3dea;hb=bd193f46b70fd3f8a55e2a8dcbb1fb2b4eec13d6;hp=37bf35e636f0966662416f0693dbea5c1cc73311;hpb=77f143bf3e218857ec8e5244d7e862e8e0c1a041;p=git.git diff --git a/cache-tree.c b/cache-tree.c index 37bf35e63..f755590da 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; @@ -328,8 +330,11 @@ static int update_one(struct cache_tree *it, mode = ce->ce_mode; entlen = pathlen - baselen; } - if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) - return error("invalid object %s", sha1_to_hex(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 */ @@ -514,6 +519,8 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size) static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path) { + if (!it) + return NULL; while (*path) { const char *slash; struct cache_tree_sub *sub; @@ -538,28 +545,32 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat return it; } -int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix) +int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix) { int entries, was_valid, newfd; + struct lock_file *lock_file; /* * We can't free this memory, it becomes part of a linked list * parsed atexit() */ - struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); + lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_locked_index(lock_file, 1); entries = read_cache(); if (entries < 0) return WRITE_TREE_UNREADABLE_INDEX; + if (flags & WRITE_TREE_IGNORE_CACHE_TREE) + cache_tree_free(&(active_cache_tree)); if (!active_cache_tree) active_cache_tree = cache_tree(); 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) @@ -625,3 +636,35 @@ void prime_cache_tree(struct cache_tree **it, struct tree *tree) *it = cache_tree(); prime_cache_tree_rec(*it, tree); } + +/* + * find the cache_tree that corresponds to the current level without + * exploding the full path into textual form. The root of the + * cache tree is given as "root", and our current level is "info". + * (1) When at root level, info->prev is NULL, so it is "root" itself. + * (2) Otherwise, find the cache_tree that corresponds to one level + * above us, and find ourselves in there. + */ +static struct cache_tree *find_cache_tree_from_traversal(struct cache_tree *root, + struct traverse_info *info) +{ + struct cache_tree *our_parent; + + if (!info->prev) + return root; + our_parent = find_cache_tree_from_traversal(root, info->prev); + return cache_tree_find(our_parent, info->name.path); +} + +int cache_tree_matches_traversal(struct cache_tree *root, + struct name_entry *ent, + struct traverse_info *info) +{ + struct cache_tree *it; + + 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)) + return it->entry_count; + return 0; +}