push: fix segfault for odd config
[gitweb.git] / unpack-trees.c
index e59d144d28164f2451784513105f6269f0e9167c..e547282ed5c0027b35cbbd8e4f07bf968c6f2171 100644 (file)
@@ -61,7 +61,7 @@ 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_namelen(ce), ce->name))
                return;
        if (unlink(name))
                return;
@@ -240,8 +240,11 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, con
        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;
@@ -291,7 +294,7 @@ static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmas
 
 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;
 
@@ -352,7 +355,7 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message)
        discard_index(&o->result);
        if (!o->gently) {
                if (message)
-                       return error(message);
+                       return error("%s", message);
                return -1;
        }
        return -1;
@@ -382,7 +385,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
        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) {
@@ -494,7 +497,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
         * anything in the existing directory there.
         */
        int namelen;
-       int pos, i;
+       int i;
        struct dir_struct d;
        char *pathbuf;
        int cnt = 0;
@@ -515,24 +518,20 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
         * 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++;
        }
@@ -584,11 +583,11 @@ static int verify_absent(struct cache_entry *ce, const char *action,
        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_namelen(ce), ce->name))
                return 0;
 
        if (!lstat(ce->name, &st)) {
-               int cnt;
+               int ret;
                int dtype = ce_to_dtype(ce);
                struct cache_entry *result;
 
@@ -616,13 +615,15 @@ static int verify_absent(struct cache_entry *ce, const char *action,
                         * 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;
@@ -635,7 +636,7 @@ static int verify_absent(struct cache_entry *ce, const char *action,
                         * We need to increment it by the number of
                         * deleted entries here.
                         */
-                       o->pos += cnt;
+                       o->pos += ret;
                        return 0;
                }