From: Junio C Hamano Date: Wed, 18 Mar 2009 01:58:55 +0000 (-0700) Subject: Merge branch 'jc/maint-1.6.0-read-tree-overlay' X-Git-Tag: v1.6.3-rc0~140 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/7d4e3a72fb2d544b4a7cfd75f8626532d78fd726?ds=inline;hp=-c Merge branch 'jc/maint-1.6.0-read-tree-overlay' * jc/maint-1.6.0-read-tree-overlay: read-tree A B C: do not create a bogus index and do not segfault --- 7d4e3a72fb2d544b4a7cfd75f8626532d78fd726 diff --combined unpack-trees.c index da2e3c0915,5b0a8c1728..86e28650b8 --- a/unpack-trees.c +++ b/unpack-trees.c @@@ -49,20 -49,39 +49,20 @@@ static void add_entry(struct unpack_tre memcpy(new, ce, size); new->next = NULL; new->ce_flags = (new->ce_flags & ~clear) | set; - add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|ADD_CACHE_SKIP_DFCHECK); + add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); } -/* Unlink the last component and attempt to remove leading - * directories, in case this unlink is the removal of the - * last entry in the directory -- empty directories are removed. +/* + * Unlink the last component and schedule the leading directories for + * removal, such that empty directories get removed. */ static void unlink_entry(struct cache_entry *ce) { - char *cp, *prev; - char *name = ce->name; - - if (has_symlink_leading_path(ce_namelen(ce), ce->name)) + if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce))) return; - if (unlink(name)) + if (unlink(ce->name)) return; - prev = NULL; - while (1) { - int status; - cp = strrchr(name, '/'); - if (prev) - *prev = '/'; - if (!cp) - break; - - *cp = 0; - status = rmdir(name); - if (status) { - *cp = '/'; - break; - } - prev = cp; - } + schedule_dir_for_removal(ce->name, ce_namelen(ce)); } static struct checkout state; @@@ -93,10 -112,11 +93,10 @@@ static int check_updates(struct unpack_ display_progress(progress, ++cnt); if (o->update) unlink_entry(ce); - remove_index_entry_at(&o->result, i); - i--; - continue; } } + remove_marked_cache_entries(&o->result); + remove_scheduled_dirs(); for (i = 0; i < index->cache_nr; i++) { struct cache_entry *ce = index->cache[i]; @@@ -220,11 -240,8 +220,11 @@@ static struct cache_entry *create_ce_en return ce; } -static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmask, struct cache_entry *src[5], - const struct name_entry *names, const struct traverse_info *info) +static int unpack_nondirectories(int n, unsigned long mask, + unsigned long dirmask, + struct cache_entry **src, + const struct name_entry *names, + const struct traverse_info *info) { int i; struct unpack_trees_options *o = info->data; @@@ -266,15 -283,15 +266,15 @@@ if (o->merge) return call_unpack_fn(src, o); - n += o->merge; for (i = 0; i < n; i++) - add_entry(o, src[i], 0, 0); + if (src[i] && src[i] != o->df_conflict_entry) + add_entry(o, src[i], 0, 0); return 0; } static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *names, struct traverse_info *info) { - struct cache_entry *src[5] = { NULL, }; + struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, }; struct unpack_trees_options *o = info->data; const struct name_entry *p = names; @@@ -335,7 -352,7 +335,7 @@@ static int unpack_failed(struct unpack_ discard_index(&o->result); if (!o->gently) { if (message) - return error(message); + return error("%s", message); return -1; } return -1; @@@ -359,15 -376,12 +359,15 @@@ int unpack_trees(unsigned len, struct t state.refresh_cache = 1; memset(&o->result, 0, sizeof(o->result)); - if (o->src_index) - o->result.timestamp = o->src_index->timestamp; + o->result.initialized = 1; + if (o->src_index) { + o->result.timestamp.sec = o->src_index->timestamp.sec; + o->result.timestamp.nsec = o->src_index->timestamp.nsec; + } o->merge_size = len; if (!dfc) - dfc = xcalloc(1, sizeof(struct cache_entry) + 1); + dfc = xcalloc(1, cache_entry_size(0)); o->df_conflict_entry = dfc; if (len) { @@@ -428,7 -442,7 +428,7 @@@ static int verify_uptodate(struct cache { struct stat st; - if (o->index_only || o->reset) + if (o->index_only || o->reset || ce_uptodate(ce)) return 0; if (!lstat(ce->name, &st)) { @@@ -479,7 -493,7 +479,7 @@@ static int verify_clean_subdirectory(st * anything in the existing directory there. */ int namelen; - int pos, i; + int i; struct dir_struct d; char *pathbuf; int cnt = 0; @@@ -500,20 -514,24 +500,20 @@@ * in that directory. */ namelen = strlen(ce->name); - pos = index_name_pos(o->src_index, ce->name, namelen); - if (0 <= pos) - return cnt; /* we have it as nondirectory */ - pos = -pos - 1; - for (i = pos; i < o->src_index->cache_nr; i++) { - struct cache_entry *ce = o->src_index->cache[i]; - int len = ce_namelen(ce); + for (i = o->pos; i < o->src_index->cache_nr; i++) { + struct cache_entry *ce2 = o->src_index->cache[i]; + int len = ce_namelen(ce2); if (len < namelen || - strncmp(ce->name, ce->name, namelen) || - ce->name[namelen] != '/') + strncmp(ce->name, ce2->name, namelen) || + ce2->name[namelen] != '/') break; /* - * ce->name is an entry in the subdirectory. + * ce2->name is an entry in the subdirectory. */ - if (!ce_stage(ce)) { - if (verify_uptodate(ce, o)) + if (!ce_stage(ce2)) { + if (verify_uptodate(ce2, o)) return -1; - add_entry(o, ce, CE_REMOVE, 0); + add_entry(o, ce2, CE_REMOVE, 0); } cnt++; } @@@ -565,11 -583,11 +565,11 @@@ static int verify_absent(struct cache_e if (o->index_only || o->reset || !o->update) return 0; - if (has_symlink_leading_path(ce_namelen(ce), ce->name)) + if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce))) return 0; if (!lstat(ce->name, &st)) { - int cnt; + int ret; int dtype = ce_to_dtype(ce); struct cache_entry *result; @@@ -597,15 -615,13 +597,15 @@@ * files that are in "foo/" we would lose * it. */ - cnt = verify_clean_subdirectory(ce, action, o); + ret = verify_clean_subdirectory(ce, action, o); + if (ret < 0) + return ret; /* * If this removed entries from the index, * what that means is: * - * (1) the caller unpack_trees_rec() saw path/foo + * (1) the caller unpack_callback() saw path/foo * in the index, and it has not removed it because * it thinks it is handling 'path' as blob with * D/F conflict; @@@ -618,7 -634,7 +618,7 @@@ * We need to increment it by the number of * deleted entries here. */ - o->pos += cnt; + o->pos += ret; return 0; } @@@ -924,17 -940,8 +924,17 @@@ int twoway_merge(struct cache_entry **s return -1; } } - else if (newtree) + else if (newtree) { + if (oldtree && !o->initial_checkout) { + /* + * deletion of the path was staged; + */ + if (same(oldtree, newtree)) + return 1; + return reject_merge(oldtree, o); + } return merged_entry(newtree, current, o); + } return deleted_entry(oldtree, current, o); }