Merge branch 'ar/maint-mksnpath' into ar/mksnpath
authorJunio C Hamano <gitster@pobox.com>
Fri, 31 Oct 2008 01:08:58 +0000 (18:08 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 31 Oct 2008 01:08:58 +0000 (18:08 -0700)
* ar/maint-mksnpath:
Use git_pathdup instead of xstrdup(git_path(...))
git_pathdup: returns xstrdup-ed copy of the formatted path
Fix potentially dangerous use of git_path in ref.c
Add git_snpath: a .git path formatting routine with output buffer

Conflicts:
builtin-revert.c
refs.c
rerere.c

1  2 
builtin-reflog.c
builtin-revert.c
builtin-tag.c
cache.h
config.c
environment.c
refs.c
rerere.c
diff --combined builtin-reflog.c
index 6b3667ef0ebdfc2b8b70b24e474b22989fbf0cb7,da96da317be01c24ae9711206976f48f33e39f97..d95f515f2e32aa71c3a09fe5ed9486f352713360
@@@ -277,11 -277,11 +277,11 @@@ static int expire_reflog(const char *re
        lock = lock_any_ref_for_update(ref, sha1, 0);
        if (!lock)
                return error("cannot lock ref '%s'", ref);
-       log_file = xstrdup(git_path("logs/%s", ref));
+       log_file = git_pathdup("logs/%s", ref);
        if (!file_exists(log_file))
                goto finish;
        if (!cmd->dry_run) {
-               newlog_path = xstrdup(git_path("logs/%s.lock", ref));
+               newlog_path = git_pathdup("logs/%s.lock", ref);
                cb.newlog = fopen(newlog_path, "w");
        }
  
@@@ -540,11 -540,11 +540,11 @@@ static int cmd_reflog_expire(int argc, 
                free(collected.e);
        }
  
 -      while (i < argc) {
 -              const char *ref = argv[i++];
 +      for (; i < argc; i++) {
 +              char *ref;
                unsigned char sha1[20];
 -              if (!resolve_ref(ref, sha1, 1, NULL)) {
 -                      status |= error("%s points nowhere!", ref);
 +              if (!dwim_log(argv[i], strlen(argv[i]), sha1, &ref)) {
 +                      status |= error("%s points nowhere!", argv[i]);
                        continue;
                }
                set_reflog_expiry_param(&cb, explicit_expiry, ref);
diff --combined builtin-revert.c
index 472554019afdb5e8e21f2d362f62f40eb569d8aa,5c4ab58f4643b8a1b77507c1cc0f0b8a70691ebf..7e50c2aa542772b2bac7c599df8865c3dbae5bcd
@@@ -11,8 -11,6 +11,8 @@@
  #include "cache-tree.h"
  #include "diff.h"
  #include "revision.h"
 +#include "rerere.h"
 +#include "merge-recursive.h"
  
  /*
   * This implements the builtins revert and cherry-pick.
@@@ -202,6 -200,36 +202,6 @@@ static void set_author_ident_env(const 
                        sha1_to_hex(commit->object.sha1));
  }
  
 -static int merge_recursive(const char *base_sha1,
 -              const char *head_sha1, const char *head_name,
 -              const char *next_sha1, const char *next_name)
 -{
 -      char buffer[256];
 -      const char *argv[6];
 -      int i = 0;
 -
 -      sprintf(buffer, "GITHEAD_%s", head_sha1);
 -      setenv(buffer, head_name, 1);
 -      sprintf(buffer, "GITHEAD_%s", next_sha1);
 -      setenv(buffer, next_name, 1);
 -
 -      /*
 -       * This three way merge is an interesting one.  We are at
 -       * $head, and would want to apply the change between $commit
 -       * and $prev on top of us (when reverting), or the change between
 -       * $prev and $commit on top of us (when cherry-picking or replaying).
 -       */
 -      argv[i++] = "merge-recursive";
 -      if (base_sha1)
 -              argv[i++] = base_sha1;
 -      argv[i++] = "--";
 -      argv[i++] = head_sha1;
 -      argv[i++] = next_sha1;
 -      argv[i++] = NULL;
 -
 -      return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD);
 -}
 -
  static char *help_msg(const unsigned char *sha1)
  {
        static char helpbuf[1024];
@@@ -234,27 -262,14 +234,27 @@@ static int index_is_dirty(void
        return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
  }
  
 +static struct tree *empty_tree(void)
 +{
 +      struct tree *tree = xcalloc(1, sizeof(struct tree));
 +
 +      tree->object.parsed = 1;
 +      tree->object.type = OBJ_TREE;
 +      pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1);
 +      return tree;
 +}
 +
  static int revert_or_cherry_pick(int argc, const char **argv)
  {
        unsigned char head[20];
        struct commit *base, *next, *parent;
 -      int i;
 +      int i, index_fd, clean;
        char *oneline, *reencoded_message = NULL;
        const char *message, *encoding;
-       const char *defmsg = xstrdup(git_path("MERGE_MSG"));
+       const char *defmsg = git_pathdup("MERGE_MSG");
 +      struct merge_options o;
 +      struct tree *result, *next_tree, *base_tree, *head_tree;
 +      static struct lock_file index_lock;
  
        git_config(git_default_config, NULL);
        me = action == REVERT ? "revert" : "cherry-pick";
        if (action == REVERT && !no_replay)
                die("revert is incompatible with replay");
  
 +      if (read_cache() < 0)
 +              die("git %s: failed to read the index", me);
        if (no_commit) {
                /*
                 * We do not intend to commit immediately.  We just want to
        } else {
                if (get_sha1("HEAD", head))
                        die ("You do not have a valid HEAD");
 -              if (read_cache() < 0)
 -                      die("could not read the index");
                if (index_is_dirty())
                        die ("Dirty index: cannot %s", me);
 -              discard_cache();
        }
 +      discard_cache();
 +
 +      index_fd = hold_locked_index(&index_lock, 1);
  
        if (!commit->parents) {
                if (action == REVERT)
                die ("Cannot get commit message for %s",
                                sha1_to_hex(commit->object.sha1));
  
 +      if (parent && parse_commit(parent) < 0)
 +              die("%s: cannot parse parent commit %s",
 +                  me, sha1_to_hex(parent->object.sha1));
 +
        /*
         * "commit" is an existing commit.  We would want to apply
         * the difference it introduces since its first parent "prev"
         * reverse of it if we are revert.
         */
  
 -      msg_fd = hold_lock_file_for_update(&msg_file, defmsg, 1);
 +      msg_fd = hold_lock_file_for_update(&msg_file, defmsg,
 +                                         LOCK_DIE_ON_ERROR);
  
        encoding = get_encoding(message);
        if (!encoding)
                }
        }
  
 -      if (merge_recursive(base == NULL ?
 -                              NULL : sha1_to_hex(base->object.sha1),
 -                              sha1_to_hex(head), "HEAD",
 -                              sha1_to_hex(next->object.sha1), oneline) ||
 -                      write_cache_as_tree(head, 0, NULL)) {
 +      read_cache();
 +      init_merge_options(&o);
 +      o.branch1 = "HEAD";
 +      o.branch2 = oneline;
 +
 +      head_tree = parse_tree_indirect(head);
 +      next_tree = next ? next->tree : empty_tree();
 +      base_tree = base ? base->tree : empty_tree();
 +
 +      clean = merge_trees(&o,
 +                          head_tree,
 +                          next_tree, base_tree, &result);
 +
 +      if (active_cache_changed &&
 +          (write_cache(index_fd, active_cache, active_nr) ||
 +           commit_locked_index(&index_lock)))
 +              die("%s: Unable to write new index file", me);
 +
 +      if (!clean) {
                add_to_msg("\nConflicts:\n\n");
 -              read_cache();
                for (i = 0; i < active_nr;) {
                        struct cache_entry *ce = active_cache[i++];
                        if (ce_stage(ce)) {
                        die ("Error wrapping up %s", defmsg);
                fprintf(stderr, "Automatic %s failed.%s\n",
                        me, help_msg(commit->object.sha1));
 +              rerere();
                exit(1);
        }
        if (commit_lock_file(&msg_file) < 0)
diff --combined builtin-tag.c
index b13fa34d8c59a9226599ba10b4d679f41ad230b0,6c6c35176e57a77fea85872fcea2c5b36f670e3e..efd77231ffb6f2574d130a612a1c38dfe646fdf8
@@@ -283,7 -283,7 +283,7 @@@ static void create_tag(const unsigned c
                int fd;
  
                /* write the template message before editing: */
-               path = xstrdup(git_path("TAG_EDITMSG"));
+               path = git_pathdup("TAG_EDITMSG");
                fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
                if (fd < 0)
                        die("could not create file '%s': %s",
@@@ -338,7 -338,7 +338,7 @@@ static int parse_msg_arg(const struct o
  
  int cmd_tag(int argc, const char **argv, const char *prefix)
  {
 -      struct strbuf buf;
 +      struct strbuf buf = STRBUF_INIT;
        unsigned char object[20], prev[20];
        char ref[PATH_MAX];
        const char *object_ref, *tag;
        if (verify)
                return for_each_tag_name(argv, verify_tag);
  
 -      strbuf_init(&buf, 0);
        if (msg.given || msgfile) {
                if (msg.given && msgfile)
                        die("only one -F or -m option is allowed.");
diff --combined cache.h
index 629cdf3971f0e55fc34b7b5f43e5b4ea225e5be4,eaacd6dd9fae9aac5f55614d099b0838c13f90cf..24d0d44f77123e2c869097191bfc7310621326e5
+++ b/cache.h
@@@ -6,14 -6,8 +6,14 @@@
  #include "hash.h"
  
  #include SHA1_HEADER
 -#include <zlib.h>
 +#ifndef git_SHA_CTX
 +#define git_SHA_CTX   SHA_CTX
 +#define git_SHA1_Init SHA1_Init
 +#define git_SHA1_Update       SHA1_Update
 +#define git_SHA1_Final        SHA1_Final
 +#endif
  
 +#include <zlib.h>
  #if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
  #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
  #endif
@@@ -132,7 -126,6 +132,7 @@@ struct cache_entry 
  
  #define CE_NAMEMASK  (0x0fff)
  #define CE_STAGEMASK (0x3000)
 +#define CE_EXTENDED  (0x4000)
  #define CE_VALID     (0x8000)
  #define CE_STAGESHIFT 12
  
@@@ -277,7 -270,6 +277,7 @@@ static inline void remove_name_hash(str
  #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
  #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
  #define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
 +#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
  #endif
  
  enum object_type {
@@@ -320,7 -312,6 +320,7 @@@ extern int is_bare_repository(void)
  extern int is_inside_git_dir(void);
  extern char *git_work_tree_cfg;
  extern int is_inside_work_tree(void);
 +extern int have_git_dir(void);
  extern const char *get_git_dir(void);
  extern char *get_object_directory(void);
  extern char *get_index_file(void);
@@@ -379,7 -370,6 +379,7 @@@ extern int index_name_pos(const struct 
  #define ADD_CACHE_OK_TO_REPLACE 2     /* Ok to replace file/directory */
  #define ADD_CACHE_SKIP_DFCHECK 4      /* Ok to skip DF conflict checks */
  #define ADD_CACHE_JUST_APPEND 8               /* Append only; tree.c::read_tree() */
 +#define ADD_CACHE_NEW_ONLY 16         /* Do not replace existing ones */
  extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
  extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
  extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
@@@ -388,13 -378,10 +388,13 @@@ extern int remove_file_from_index(struc
  #define ADD_CACHE_VERBOSE 1
  #define ADD_CACHE_PRETEND 2
  #define ADD_CACHE_IGNORE_ERRORS       4
 +#define ADD_CACHE_IGNORE_REMOVAL 8
 +#define ADD_CACHE_INTENT 16
  extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
  extern int add_file_to_index(struct index_state *, const char *path, int flags);
  extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
  extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
 +extern int index_name_is_other(const struct index_state *, const char *, int);
  
  /* do stat comparison even if CE_VALID is true */
  #define CE_MATCH_IGNORE_VALID         01
@@@ -405,6 -392,7 +405,6 @@@ extern int ie_modified(const struct ind
  
  extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
  extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
 -extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
  extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
  extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
  
@@@ -423,8 -411,6 +423,8 @@@ struct lock_file 
        char on_list;
        char filename[PATH_MAX];
  };
 +#define LOCK_DIE_ON_ERROR 1
 +#define LOCK_NODEREF 2
  extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
  extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
  extern int commit_lock_file(struct lock_file *);
@@@ -466,7 -452,6 +466,7 @@@ enum safe_crlf 
  extern enum safe_crlf safe_crlf;
  
  enum branch_track {
 +      BRANCH_TRACK_UNSPECIFIED = -1,
        BRANCH_TRACK_NEVER = 0,
        BRANCH_TRACK_REMOTE,
        BRANCH_TRACK_ALWAYS,
@@@ -497,6 -482,10 +497,10 @@@ extern int check_repository_format(void
  
  extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
+ extern char *git_snpath(char *buf, size_t n, const char *fmt, ...)
+       __attribute__((format (printf, 3, 4)));
+ extern char *git_pathdup(const char *fmt, ...)
+       __attribute__((format (printf, 1, 2)));
  
  /* Return a statically allocated filename matching the sha1 signature */
  extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
@@@ -522,7 -511,6 +526,7 @@@ static inline void hashclr(unsigned cha
  {
        memset(hash, 0, 20);
  }
 +extern int is_empty_blob_sha1(const unsigned char *sha1);
  
  int git_mkstemp(char *path, size_t n, const char *template);
  
@@@ -550,7 -538,6 +554,7 @@@ static inline int is_absolute_path(cons
  {
        return path[0] == '/' || has_dos_drive_prefix(path);
  }
 +int is_directory(const char *);
  const char *make_absolute_path(const char *path);
  const char *make_nonrelative_path(const char *path);
  const char *make_relative_path(const char *abs, const char *base);
@@@ -658,8 -645,6 +662,8 @@@ extern struct alternate_object_databas
  } *alt_odb_list;
  extern void prepare_alt_odb(void);
  extern void add_to_alternates_file(const char *reference);
 +typedef int alt_odb_fn(struct alternate_object_database *, void *);
 +extern void foreach_alt_odb(alt_odb_fn, void*);
  
  struct pack_window {
        struct pack_window *next;
@@@ -728,11 -713,7 +732,11 @@@ extern struct child_process *git_connec
  extern int finish_connect(struct child_process *conn);
  extern int path_match(const char *path, int nr, char **match);
  extern int get_ack(int fd, unsigned char *result_sha1);
 -extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags);
 +struct extra_have_objects {
 +      int nr, alloc;
 +      unsigned char (*array)[20];
 +};
 +extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *);
  extern int server_supports(const char *feature);
  
  extern struct packed_git *parse_pack_index(unsigned char *sha1);
@@@ -766,6 -747,7 +770,6 @@@ typedef int (*config_fn_t)(const char *
  extern int git_default_config(const char *, const char *, void *);
  extern int git_config_from_file(config_fn_t fn, const char *, void *);
  extern int git_config(config_fn_t fn, void *);
 -extern int git_parse_long(const char *, long *);
  extern int git_parse_ulong(const char *, unsigned long *);
  extern int git_config_int(const char *, const char *);
  extern unsigned long git_config_ulong(const char *, const char *);
diff --combined config.c
index b8d289d21789b5017579d90b7894db8ebee4c47a,82807c83b20ef8fbabfda7d476feff92f2dbb823..67cc1dcad0b52f0186c0c9564af43853d8994797
+++ b/config.c
@@@ -205,27 -205,8 +205,27 @@@ static int git_parse_file(config_fn_t f
        int baselen = 0;
        static char var[MAXNAME];
  
 +      /* U+FEFF Byte Order Mark in UTF8 */
 +      static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
 +      const unsigned char *bomptr = utf8_bom;
 +
        for (;;) {
                int c = get_next_char();
 +              if (bomptr && *bomptr) {
 +                      /* We are at the file beginning; skip UTF8-encoded BOM
 +                       * if present. Sane editors won't put this in on their
 +                       * own, but e.g. Windows Notepad will do it happily. */
 +                      if ((unsigned char) c == *bomptr) {
 +                              bomptr++;
 +                              continue;
 +                      } else {
 +                              /* Do not tolerate partial BOM. */
 +                              if (bomptr != utf8_bom)
 +                                      break;
 +                              /* No BOM at file beginning. Cool. */
 +                              bomptr = NULL;
 +                      }
 +              }
                if (c == '\n') {
                        if (config_file_eof)
                                return 0;
@@@ -274,7 -255,7 +274,7 @@@ static int parse_unit_factor(const cha
        return 0;
  }
  
 -int git_parse_long(const char *value, long *ret)
 +static int git_parse_long(const char *value, long *ret)
  {
        if (value && *value) {
                char *end;
@@@ -310,7 -291,7 +310,7 @@@ static void die_bad_config(const char *
  
  int git_config_int(const char *name, const char *value)
  {
 -      long ret;
 +      long ret = 0;
        if (!git_parse_long(value, &ret))
                die_bad_config(name);
        return ret;
@@@ -649,7 -630,7 +649,7 @@@ int git_config(config_fn_t fn, void *da
                free(user_config);
        }
  
-       repo_config = xstrdup(git_path("config"));
+       repo_config = git_pathdup("config");
        ret += git_config_from_file(fn, repo_config, data);
        free(repo_config);
        return ret;
@@@ -753,8 -734,9 +753,8 @@@ static int store_write_section(int fd, 
  {
        const char *dot;
        int i, success;
 -      struct strbuf sb;
 +      struct strbuf sb = STRBUF_INIT;
  
 -      strbuf_init(&sb, 0);
        dot = memchr(key, '.', store.baselen);
        if (dot) {
                strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
@@@ -779,7 -761,7 +779,7 @@@ static int store_write_pair(int fd, con
        int i, success;
        int length = strlen(key + store.baselen + 1);
        const char *quote = "";
 -      struct strbuf sb;
 +      struct strbuf sb = STRBUF_INIT;
  
        /*
         * Check to see if the value needs to be surrounded with a dq pair.
        if (i && value[i - 1] == ' ')
                quote = "\"";
  
 -      strbuf_init(&sb, 0);
        strbuf_addf(&sb, "\t%.*s = %s",
                    length, key + store.baselen + 1, quote);
  
@@@ -889,7 -872,7 +889,7 @@@ int git_config_set_multivar(const char
        if (config_exclusive_filename)
                config_filename = xstrdup(config_exclusive_filename);
        else
-               config_filename = xstrdup(git_path("config"));
+               config_filename = git_pathdup("config");
  
        /*
         * Since "key" actually contains the section name and the real
@@@ -1149,7 -1132,7 +1149,7 @@@ int git_config_rename_section(const cha
        if (config_exclusive_filename)
                config_filename = xstrdup(config_exclusive_filename);
        else
-               config_filename = xstrdup(git_path("config"));
+               config_filename = git_pathdup("config");
        out_fd = hold_lock_file_for_update(lock, config_filename, 0);
        if (out_fd < 0) {
                ret = error("could not lock config file %s", config_filename);
diff --combined environment.c
index 0693cd9a42adf4914bb219ecf24fc6d5da7aafd3,df4f03a95f0b2098e97d0410bbb0589ff887e9cb..bf93a598d0e2c4aedbc4065a43df0e9750f93a1c
@@@ -71,7 -71,7 +71,7 @@@ static void setup_git_env(void
        }
        git_graft_file = getenv(GRAFT_ENVIRONMENT);
        if (!git_graft_file)
-               git_graft_file = xstrdup(git_path("info/grafts"));
+               git_graft_file = git_pathdup("info/grafts");
  }
  
  int is_bare_repository(void)
        return is_bare_repository_cfg && !get_git_work_tree();
  }
  
 +int have_git_dir(void)
 +{
 +      return !!git_dir;
 +}
 +
  const char *get_git_dir(void)
  {
        if (!git_dir)
diff --combined refs.c
index 0a126fa371ae24f5cb251ff52cf7d38322d78ba7,d589b25562405b5361b6a6e49e2501361552c6ec..01e4df4ccfa203f140998f5da42b2a9fcfcca4c7
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -390,18 -390,6 +390,18 @@@ int resolve_gitlink_ref(const char *pat
        return retval;
  }
  
 +/*
 + * If the "reading" argument is set, this function finds out what _object_
 + * the ref points at by "reading" the ref.  The ref, if it is not symbolic,
 + * has to exist, and if it is symbolic, it has to point at an existing ref,
 + * because the "read" goes through the symref to the ref it points at.
 + *
 + * The access that is not "reading" may often be "writing", but does not
 + * have to; it can be merely checking _where it leads to_. If it is a
 + * prelude to "writing" to the ref, a write to a symref that points at
 + * yet-to-be-born ref will create the real ref pointed by the symref.
 + * reading=0 allows the caller to check where such a symref leads to.
 + */
  const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
  {
        int depth = MAXDEPTH;
                *flag = 0;
  
        for (;;) {
-               const char *path = git_path("%s", ref);
+               char path[PATH_MAX];
                struct stat st;
                char *buf;
                int fd;
                if (--depth < 0)
                        return NULL;
  
 -              /* Special case: non-existing file.
 -               * Not having the refs/heads/new-branch is OK
 -               * if we are writing into it, so is .git/HEAD
 -               * that points at refs/heads/master still to be
 -               * born.  It is NOT OK if we are resolving for
 -               * reading.
 -               */
+               git_snpath(path, sizeof(path), "%s", ref);
 +              /* Special case: non-existing file. */
                if (lstat(path, &st) < 0) {
                        struct ref_list *list = get_packed_refs();
                        while (list) {
@@@ -796,7 -791,7 +797,7 @@@ static struct ref_lock *lock_ref_sha1_b
        struct ref_lock *lock;
        struct stat st;
        int last_errno = 0;
 -      int type;
 +      int type, lflags;
        int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
  
        lock = xcalloc(1, sizeof(struct ref_lock));
  
        lock->lk = xcalloc(1, sizeof(struct lock_file));
  
 -      if (flags & REF_NODEREF)
 +      lflags = LOCK_DIE_ON_ERROR;
 +      if (flags & REF_NODEREF) {
                ref = orig_ref;
 +              lflags |= LOCK_NODEREF;
 +      }
        lock->ref_name = xstrdup(ref);
        lock->orig_ref_name = xstrdup(orig_ref);
        ref_file = git_path("%s", ref);
                error("unable to create directory for %s", ref_file);
                goto error_return;
        }
 -      lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, 1);
  
 +      lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, lflags);
        return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
  
   error_return:
@@@ -1130,13 -1122,14 +1131,14 @@@ static int log_ref_write(const char *re
        int logfd, written, oflags = O_APPEND | O_WRONLY;
        unsigned maxlen, len;
        int msglen;
-       char *log_file, *logrec;
+       char log_file[PATH_MAX];
+       char *logrec;
        const char *committer;
  
        if (log_all_ref_updates < 0)
                log_all_ref_updates = !is_bare_repository();
  
-       log_file = git_path("logs/%s", ref_name);
+       git_snpath(log_file, sizeof(log_file), "logs/%s", ref_name);
  
        if (log_all_ref_updates &&
            (!prefixcmp(ref_name, "refs/heads/") ||
@@@ -1265,7 -1258,7 +1267,7 @@@ int create_symref(const char *ref_targe
        const char *lockpath;
        char ref[1000];
        int fd, len, written;
-       char *git_HEAD = xstrdup(git_path("%s", ref_target));
+       char *git_HEAD = git_pathdup("%s", ref_target);
        unsigned char old_sha1[20], new_sha1[20];
  
        if (logmsg && read_ref(ref_target, old_sha1))
diff --combined rerere.c
index 8e5532b1ff96a88133d837b9a29fa78117c36abd,3d6ee8fa2a647d6ee8459f700cbc450c94e7f179..02931a151f1abe183763c9a1edb65ffd36d83bc3
+++ b/rerere.c
@@@ -73,13 -73,10 +73,13 @@@ static int write_rr(struct string_list 
  static int handle_file(const char *path,
         unsigned char *sha1, const char *output)
  {
 -      SHA_CTX ctx;
 +      git_SHA_CTX ctx;
        char buf[1024];
 -      int hunk = 0, hunk_no = 0;
 -      struct strbuf one, two;
 +      int hunk_no = 0;
 +      enum {
 +              RR_CONTEXT = 0, RR_SIDE_1, RR_SIDE_2, RR_ORIGINAL,
 +      } hunk = RR_CONTEXT;
 +      struct strbuf one = STRBUF_INIT, two = STRBUF_INIT;
        FILE *f = fopen(path, "r");
        FILE *out = NULL;
  
        }
  
        if (sha1)
 -              SHA1_Init(&ctx);
 +              git_SHA1_Init(&ctx);
  
 -      strbuf_init(&one, 0);
 -      strbuf_init(&two,  0);
        while (fgets(buf, sizeof(buf), f)) {
                if (!prefixcmp(buf, "<<<<<<< ")) {
 -                      if (hunk)
 +                      if (hunk != RR_CONTEXT)
                                goto bad;
 -                      hunk = 1;
 +                      hunk = RR_SIDE_1;
 +              } else if (!prefixcmp(buf, "|||||||") && isspace(buf[7])) {
 +                      if (hunk != RR_SIDE_1)
 +                              goto bad;
 +                      hunk = RR_ORIGINAL;
                } else if (!prefixcmp(buf, "=======") && isspace(buf[7])) {
 -                      if (hunk != 1)
 +                      if (hunk != RR_SIDE_1 && hunk != RR_ORIGINAL)
                                goto bad;
 -                      hunk = 2;
 +                      hunk = RR_SIDE_2;
                } else if (!prefixcmp(buf, ">>>>>>> ")) {
 -                      if (hunk != 2)
 +                      if (hunk != RR_SIDE_2)
                                goto bad;
                        if (strbuf_cmp(&one, &two) > 0)
                                strbuf_swap(&one, &two);
                        hunk_no++;
 -                      hunk = 0;
 +                      hunk = RR_CONTEXT;
                        if (out) {
                                fputs("<<<<<<<\n", out);
                                fwrite(one.buf, one.len, 1, out);
                                fputs(">>>>>>>\n", out);
                        }
                        if (sha1) {
 -                              SHA1_Update(&ctx, one.buf ? one.buf : "",
 +                              git_SHA1_Update(&ctx, one.buf ? one.buf : "",
                                            one.len + 1);
 -                              SHA1_Update(&ctx, two.buf ? two.buf : "",
 +                              git_SHA1_Update(&ctx, two.buf ? two.buf : "",
                                            two.len + 1);
                        }
                        strbuf_reset(&one);
                        strbuf_reset(&two);
 -              } else if (hunk == 1)
 +              } else if (hunk == RR_SIDE_1)
                        strbuf_addstr(&one, buf);
 -              else if (hunk == 2)
 +              else if (hunk == RR_ORIGINAL)
 +                      ; /* discard */
 +              else if (hunk == RR_SIDE_2)
                        strbuf_addstr(&two, buf);
                else if (out)
                        fputs(buf, out);
        if (out)
                fclose(out);
        if (sha1)
 -              SHA1_Final(sha1, &ctx);
 -      if (hunk) {
 +              git_SHA1_Final(sha1, &ctx);
 +      if (hunk != RR_CONTEXT) {
                if (output)
                        unlink(output);
                return error("Could not parse conflict hunks in %s", path);
@@@ -326,6 -319,7 +326,6 @@@ static int git_rerere_config(const cha
  
  static int is_rerere_enabled(void)
  {
 -      struct stat st;
        const char *rr_cache;
        int rr_cache_exists;
  
                return 0;
  
        rr_cache = git_path("rr-cache");
 -      rr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode);
 +      rr_cache_exists = is_directory(rr_cache);
        if (rerere_enabled < 0)
                return rr_cache_exists;
  
@@@ -351,9 -345,8 +351,9 @@@ int setup_rerere(struct string_list *me
        if (!is_rerere_enabled())
                return -1;
  
-       merge_rr_path = xstrdup(git_path("MERGE_RR"));
+       merge_rr_path = git_pathdup("MERGE_RR");
 -      fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);
 +      fd = hold_lock_file_for_update(&write_lock, merge_rr_path,
 +                                     LOCK_DIE_ON_ERROR);
        read_rr(merge_rr);
        return fd;
  }