Allow callers of unpack_trees() to handle failure
[gitweb.git] / unpack-trees.c
index e9eb795d64b9cd6a6940995d41dd9c3f3239df02..9e6587f66186ef93c3403b15a016c00526cbc1e7 100644 (file)
@@ -219,6 +219,8 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
                                }
 #endif
                                ret = o->fn(src, o, remove);
+                               if (ret < 0)
+                                       return ret;
 
 #if DBRT_DEBUG > 1
                                printf("Added %d entries\n", ret);
@@ -289,7 +291,6 @@ static struct checkout state;
 static void check_updates(struct cache_entry **src, int nr,
                        struct unpack_trees_options *o)
 {
-       unsigned short mask = htons(CE_UPDATE);
        unsigned cnt = 0, total = 0;
        struct progress *progress = NULL;
        char last_symlink[PATH_MAX];
@@ -297,7 +298,7 @@ static void check_updates(struct cache_entry **src, int nr,
        if (o->update && o->verbose_update) {
                for (total = cnt = 0; cnt < nr; cnt++) {
                        struct cache_entry *ce = src[cnt];
-                       if (!ce->ce_mode || ce->ce_flags & mask)
+                       if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
                                total++;
                }
 
@@ -310,15 +311,15 @@ static void check_updates(struct cache_entry **src, int nr,
        while (nr--) {
                struct cache_entry *ce = *src++;
 
-               if (!ce->ce_mode || ce->ce_flags & mask)
+               if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
                        display_progress(progress, ++cnt);
-               if (!ce->ce_mode) {
+               if (ce->ce_flags & CE_REMOVE) {
                        if (o->update)
                                unlink_entry(ce->name, last_symlink);
                        continue;
                }
-               if (ce->ce_flags & mask) {
-                       ce->ce_flags &= ~mask;
+               if (ce->ce_flags & CE_UPDATE) {
+                       ce->ce_flags &= ~CE_UPDATE;
                        if (o->update) {
                                checkout_entry(ce, &state, NULL);
                                *last_symlink = '\0';
@@ -360,7 +361,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
        }
 
        if (o->trivial_merges_only && o->nontrivial_merge)
-               die("Merge requires file-level merging");
+               return error("Merge requires file-level merging");
 
        check_updates(active_cache, active_nr, o);
        return 0;
@@ -368,10 +369,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 
 /* Here come the merge functions */
 
-static void reject_merge(struct cache_entry *ce)
+static int reject_merge(struct cache_entry *ce)
 {
-       die("Entry '%s' would be overwritten by merge. Cannot merge.",
-           ce->name);
+       return error("Entry '%s' would be overwritten by merge. Cannot merge.",
+                    ce->name);
 }
 
 static int same(struct cache_entry *a, struct cache_entry *b)
@@ -389,18 +390,18 @@ static int same(struct cache_entry *a, struct cache_entry *b)
  * When a CE gets turned into an unmerged entry, we
  * want it to be up-to-date
  */
-static void verify_uptodate(struct cache_entry *ce,
+static int verify_uptodate(struct cache_entry *ce,
                struct unpack_trees_options *o)
 {
        struct stat st;
 
        if (o->index_only || o->reset)
-               return;
+               return 0;
 
        if (!lstat(ce->name, &st)) {
                unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
                if (!changed)
-                       return;
+                       return 0;
                /*
                 * NEEDSWORK: the current default policy is to allow
                 * submodule to be out of sync wrt the supermodule
@@ -408,13 +409,13 @@ static void verify_uptodate(struct cache_entry *ce,
                 * submodules that are marked to be automatically
                 * checked out.
                 */
-               if (S_ISGITLINK(ntohl(ce->ce_mode)))
-                       return;
+               if (S_ISGITLINK(ce->ce_mode))
+                       return 0;
                errno = 0;
        }
        if (errno == ENOENT)
-               return;
-       die("Entry '%s' not uptodate. Cannot merge.", ce->name);
+               return 0;
+       return error("Entry '%s' not uptodate. Cannot merge.", ce->name);
 }
 
 static void invalidate_ce_path(struct cache_entry *ce)
@@ -450,7 +451,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
        int cnt = 0;
        unsigned char sha1[20];
 
-       if (S_ISGITLINK(ntohl(ce->ce_mode)) &&
+       if (S_ISGITLINK(ce->ce_mode) &&
            resolve_gitlink_ref(ce->name, "HEAD", sha1) == 0) {
                /* If we are not going to update the submodule, then
                 * we don't care.
@@ -480,8 +481,9 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
                 * ce->name is an entry in the subdirectory.
                 */
                if (!ce_stage(ce)) {
-                       verify_uptodate(ce, o);
-                       ce->ce_mode = 0;
+                       if (verify_uptodate(ce, o))
+                               return -1;
+                       ce->ce_flags |= CE_REMOVE;
                }
                cnt++;
        }
@@ -499,8 +501,8 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
                d.exclude_per_dir = o->dir->exclude_per_dir;
        i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL);
        if (i)
-               die("Updating '%s' would lose untracked files in it",
-                   ce->name);
+               return error("Updating '%s' would lose untracked files in it",
+                            ce->name);
        free(pathbuf);
        return cnt;
 }
@@ -509,16 +511,16 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
  * We do not want to remove or overwrite a working tree file that
  * is not tracked, unless it is ignored.
  */
-static void verify_absent(struct cache_entry *ce, const char *action,
-               struct unpack_trees_options *o)
+static int verify_absent(struct cache_entry *ce, const char *action,
+                        struct unpack_trees_options *o)
 {
        struct stat st;
 
        if (o->index_only || o->reset || !o->update)
-               return;
+               return 0;
 
        if (has_symlink_leading_path(ce->name, NULL))
-               return;
+               return 0;
 
        if (!lstat(ce->name, &st)) {
                int cnt;
@@ -528,7 +530,7 @@ static void verify_absent(struct cache_entry *ce, const char *action,
                         * ce->name is explicitly excluded, so it is Ok to
                         * overwrite it.
                         */
-                       return;
+                       return 0;
                if (S_ISDIR(st.st_mode)) {
                        /*
                         * We are checking out path "foo" and
@@ -557,7 +559,7 @@ static void verify_absent(struct cache_entry *ce, const char *action,
                         * deleted entries here.
                         */
                        o->pos += cnt;
-                       return;
+                       return 0;
                }
 
                /*
@@ -568,19 +570,20 @@ static void verify_absent(struct cache_entry *ce, const char *action,
                cnt = cache_name_pos(ce->name, strlen(ce->name));
                if (0 <= cnt) {
                        struct cache_entry *ce = active_cache[cnt];
-                       if (!ce_stage(ce) && !ce->ce_mode)
-                               return;
+                       if (ce->ce_flags & CE_REMOVE)
+                               return 0;
                }
 
-               die("Untracked working tree file '%s' "
-                   "would be %s by merge.", ce->name, action);
+               return error("Untracked working tree file '%s' "
+                            "would be %s by merge.", ce->name, action);
        }
+       return 0;
 }
 
 static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
                struct unpack_trees_options *o)
 {
-       merge->ce_flags |= htons(CE_UPDATE);
+       merge->ce_flags |= CE_UPDATE;
        if (old) {
                /*
                 * See if we can re-use the old CE directly?
@@ -590,18 +593,20 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
                 * a match.
                 */
                if (same(old, merge)) {
-                       *merge = *old;
+                       memcpy(merge, old, offsetof(struct cache_entry, name));
                } else {
-                       verify_uptodate(old, o);
+                       if (verify_uptodate(old, o))
+                               return -1;
                        invalidate_ce_path(old);
                }
        }
        else {
-               verify_absent(merge, "overwritten", o);
+               if (verify_absent(merge, "overwritten", o))
+                       return -1;
                invalidate_ce_path(merge);
        }
 
-       merge->ce_flags &= ~htons(CE_STAGEMASK);
+       merge->ce_flags &= ~CE_STAGEMASK;
        add_cache_entry(merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
        return 1;
 }
@@ -609,11 +614,13 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
 static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
                struct unpack_trees_options *o)
 {
-       if (old)
-               verify_uptodate(old, o);
-       else
-               verify_absent(ce, "removed", o);
-       ce->ce_mode = 0;
+       if (old) {
+               if (verify_uptodate(old, o))
+                       return -1;
+       } else
+               if (verify_absent(ce, "removed", o))
+                       return -1;
+       ce->ce_flags |= CE_REMOVE;
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
        invalidate_ce_path(ce);
        return 1;
@@ -634,7 +641,7 @@ static void show_stage_entry(FILE *o,
        else
                fprintf(o, "%s%06o %s %d\t%s\n",
                        label,
-                       ntohl(ce->ce_mode),
+                       ce->ce_mode,
                        sha1_to_hex(ce->sha1),
                        ce_stage(ce),
                        ce->name);
@@ -700,7 +707,7 @@ int threeway_merge(struct cache_entry **stages,
        /* #14, #14ALT, #2ALT */
        if (remote && !df_conflict_head && head_match && !remote_match) {
                if (index && !same(index, remote) && !same(index, head))
-                       reject_merge(index);
+                       return reject_merge(index);
                return merged_entry(remote, index, o);
        }
        /*
@@ -708,7 +715,7 @@ int threeway_merge(struct cache_entry **stages,
         * make sure that it matches head.
         */
        if (index && !same(index, head)) {
-               reject_merge(index);
+               return reject_merge(index);
        }
 
        if (head) {
@@ -759,8 +766,10 @@ int threeway_merge(struct cache_entry **stages,
                        remove_entry(remove);
                        if (index)
                                return deleted_entry(index, index, o);
-                       else if (ce && !head_deleted)
-                               verify_absent(ce, "removed", o);
+                       else if (ce && !head_deleted) {
+                               if (verify_absent(ce, "removed", o))
+                                       return -1;
+                       }
                        return 0;
                }
                /*
@@ -776,7 +785,8 @@ int threeway_merge(struct cache_entry **stages,
         * conflict resolution files.
         */
        if (index) {
-               verify_uptodate(index, o);
+               if (verify_uptodate(index, o))
+                       return -1;
        }
 
        remove_entry(remove);
@@ -856,11 +866,11 @@ int twoway_merge(struct cache_entry **src,
                        /* all other failures */
                        remove_entry(remove);
                        if (oldtree)
-                               reject_merge(oldtree);
+                               return reject_merge(oldtree);
                        if (current)
-                               reject_merge(current);
+                               return reject_merge(current);
                        if (newtree)
-                               reject_merge(newtree);
+                               return reject_merge(newtree);
                        return -1;
                }
        }
@@ -887,7 +897,7 @@ int bind_merge(struct cache_entry **src,
                return error("Cannot do a bind merge of %d trees\n",
                             o->merge_size);
        if (a && old)
-               die("Entry '%s' overlaps.  Cannot bind.", a->name);
+               return error("Entry '%s' overlaps.  Cannot bind.", a->name);
        if (!a)
                return keep_entry(old, o);
        else
@@ -920,7 +930,7 @@ int oneway_merge(struct cache_entry **src,
                        struct stat st;
                        if (lstat(old->name, &st) ||
                            ce_match_stat(old, &st, CE_MATCH_IGNORE_VALID))
-                               old->ce_flags |= htons(CE_UPDATE);
+                               old->ce_flags |= CE_UPDATE;
                }
                return keep_entry(old, o);
        }