Merge branch 'jc/rerere-multi'
authorJunio C Hamano <gitster@pobox.com>
Mon, 23 May 2016 21:54:37 +0000 (14:54 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 23 May 2016 21:54:38 +0000 (14:54 -0700)
* jc/rerere-multi:
rerere: remove an null statement
rerere: plug memory leaks upon "rerere forget" failure

1  2 
rerere.c
diff --combined rerere.c
index 1810c040daba6398580bd9a40179b365887a91a6,d4929a66ae9e6ba63a87c4663968b466bc4a4bfb..aaadec17d867d521fc0eaab7fcdd2e871bdf1267
+++ b/rerere.c
@@@ -21,6 -21,8 +21,6 @@@ static int rerere_enabled = -1
  /* automatically update cleanly resolved paths to the index */
  static int rerere_autoupdate;
  
 -static char *merge_rr_path;
 -
  static int rerere_dir_nr;
  static int rerere_dir_alloc;
  
@@@ -200,7 -202,7 +200,7 @@@ static struct rerere_id *new_rerere_id(
  static void read_rr(struct string_list *rr)
  {
        struct strbuf buf = STRBUF_INIT;
 -      FILE *in = fopen(merge_rr_path, "r");
 +      FILE *in = fopen(git_path_merge_rr(), "r");
  
        if (!in)
                return;
@@@ -501,7 -503,8 +501,7 @@@ static int handle_file(const char *path
                error("There were errors while writing %s (%s)",
                      path, strerror(io.io.wrerror));
        if (io.io.output && fclose(io.io.output))
 -              io.io.wrerror = error("Failed to flush %s: %s",
 -                                    path, strerror(errno));
 +              io.io.wrerror = error_errno("Failed to flush %s", path);
  
        if (hunk_no < 0) {
                if (output)
@@@ -597,8 -600,6 +597,8 @@@ static int find_conflict(struct string_
  int rerere_remaining(struct string_list *merge_rr)
  {
        int i;
 +      if (setup_rerere(merge_rr, RERERE_READONLY))
 +              return 0;
        if (read_cache() < 0)
                return error("Could not read index");
  
@@@ -683,17 -684,20 +683,17 @@@ static int merge(const struct rerere_i
         * Mark that "postimage" was used to help gc.
         */
        if (utime(rerere_path(id, "postimage"), NULL) < 0)
 -              warning("failed utime() on %s: %s",
 -                      rerere_path(id, "postimage"),
 -                      strerror(errno));
 +              warning_errno("failed utime() on %s",
 +                            rerere_path(id, "postimage"));
  
        /* Update "path" with the resolution */
        f = fopen(path, "w");
        if (!f)
 -              return error("Could not open %s: %s", path,
 -                           strerror(errno));
 +              return error_errno("Could not open %s", path);
        if (fwrite(result.ptr, result.size, 1, f) != 1)
 -              error("Could not write %s: %s", path, strerror(errno));
 +              error_errno("Could not write %s", path);
        if (fclose(f))
 -              return error("Writing %s failed: %s", path,
 -                           strerror(errno));
 +              return error_errno("Writing %s failed", path);
  
  out:
        free(cur.ptr);
@@@ -866,21 -870,21 +866,21 @@@ static void git_rerere_config(void
        git_config(git_default_config, NULL);
  }
  
 +static GIT_PATH_FUNC(git_path_rr_cache, "rr-cache")
 +
  static int is_rerere_enabled(void)
  {
 -      const char *rr_cache;
        int rr_cache_exists;
  
        if (!rerere_enabled)
                return 0;
  
 -      rr_cache = git_path("rr-cache");
 -      rr_cache_exists = is_directory(rr_cache);
 +      rr_cache_exists = is_directory(git_path_rr_cache());
        if (rerere_enabled < 0)
                return rr_cache_exists;
  
 -      if (!rr_cache_exists && mkdir_in_gitdir(rr_cache))
 -              die("Could not create directory %s", rr_cache);
 +      if (!rr_cache_exists && mkdir_in_gitdir(git_path_rr_cache()))
 +              die("Could not create directory %s", git_path_rr_cache());
        return 1;
  }
  
@@@ -894,11 -898,9 +894,11 @@@ int setup_rerere(struct string_list *me
  
        if (flags & (RERERE_AUTOUPDATE|RERERE_NOAUTOUPDATE))
                rerere_autoupdate = !!(flags & RERERE_AUTOUPDATE);
 -      merge_rr_path = git_pathdup("MERGE_RR");
 -      fd = hold_lock_file_for_update(&write_lock, merge_rr_path,
 -                                     LOCK_DIE_ON_ERROR);
 +      if (flags & RERERE_READONLY)
 +              fd = 0;
 +      else
 +              fd = hold_lock_file_for_update(&write_lock, git_path_merge_rr(),
 +                                             LOCK_DIE_ON_ERROR);
        read_rr(merge_rr);
        return fd;
  }
@@@ -1050,8 -1052,8 +1050,8 @@@ static int rerere_forget_one_path(cons
                handle_cache(path, sha1, rerere_path(id, "thisimage"));
                if (read_mmfile(&cur, rerere_path(id, "thisimage"))) {
                        free(cur.ptr);
-                       return error("Failed to update conflicted state in '%s'",
-                                    path);
+                       error("Failed to update conflicted state in '%s'", path);
+                       goto fail_exit;
                }
                cleanly_resolved = !try_merge(id, path, &cur, &result);
                free(result.ptr);
                        break;
        }
  
-       if (id->collection->status_nr <= id->variant)
-               return error("no remembered resolution for '%s'", path);
+       if (id->collection->status_nr <= id->variant) {
+               error("no remembered resolution for '%s'", path);
+               goto fail_exit;
+       }
  
        filename = rerere_path(id, "postimage");
-       if (unlink(filename))
-               return (errno == ENOENT
-                       ? error("no remembered resolution for %s", path)
-                       : error_errno("cannot unlink %s", filename));
+       if (unlink(filename)) {
+               if (errno == ENOENT)
+                       error("no remembered resolution for %s", path);
+               else
 -                      error("cannot unlink %s: %s", filename, strerror(errno));
++                      error_errno("cannot unlink %s", filename);
+               goto fail_exit;
+       }
  
        /*
         * Update the preimage so that the user can resolve the
        item->util = id;
        fprintf(stderr, "Forgot resolution for %s\n", path);
        return 0;
+ fail_exit:
+       free(id);
+       return -1;
  }
  
  int rerere_forget(struct pathspec *pathspec)
                return error("Could not read index");
  
        fd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);
 +      if (fd < 0)
 +              return 0;
  
        /*
         * The paths may have been resolved (incorrectly);
@@@ -1175,9 -1184,6 +1184,9 @@@ void rerere_gc(struct string_list *rr
        int cutoff_noresolve = 15;
        int cutoff_resolve = 60;
  
 +      if (setup_rerere(rr, 0) < 0)
 +              return;
 +
        git_config_get_int("gc.rerereresolved", &cutoff_resolve);
        git_config_get_int("gc.rerereunresolved", &cutoff_noresolve);
        git_config(git_default_config, NULL);
        for (i = 0; i < to_remove.nr; i++)
                rmdir(git_path("rr-cache/%s", to_remove.items[i].string));
        string_list_clear(&to_remove, 0);
 +      rollback_lock_file(&write_lock);
  }
  
  /*
@@@ -1227,9 -1232,6 +1236,9 @@@ void rerere_clear(struct string_list *m
  {
        int i;
  
 +      if (setup_rerere(merge_rr, 0) < 0)
 +              return;
 +
        for (i = 0; i < merge_rr->nr; i++) {
                struct rerere_id *id = merge_rr->items[i].util;
                if (!has_rerere_resolution(id)) {
                        rmdir(rerere_path(id, NULL));
                }
        }
 -      unlink_or_warn(git_path("MERGE_RR"));
 +      unlink_or_warn(git_path_merge_rr());
 +      rollback_lock_file(&write_lock);
  }