Merge branch 'ar/maint-mksnpath' into maint
authorJunio C Hamano <gitster@pobox.com>
Sun, 9 Nov 2008 00:13:19 +0000 (16:13 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 9 Nov 2008 00:13:19 +0000 (16:13 -0800)
* 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
Fix potentially dangerous uses of mkpath and git_path
Fix mkpath abuse in dwim_ref and dwim_log of sha1_name.c
Add mksnpath which allows you to specify the output buffer

Conflicts:
builtin-revert.c
rerere.c

1  2 
builtin-revert.c
builtin-tag.c
cache.h
path.c
refs.c
rerere.c
diff --combined builtin-revert.c
index 786a956f26486856c97e15ce8ab464dfb25dcbc5,5c4ab58f4643b8a1b77507c1cc0f0b8a70691ebf..74845ef8e6f9c635bbafbf5dfea5e73cf6e11aa0
@@@ -269,7 -269,7 +269,7 @@@ static int revert_or_cherry_pick(int ar
        int i;
        char *oneline, *reencoded_message = NULL;
        const char *message, *encoding;
-       char *defmsg = xstrdup(git_path("MERGE_MSG"));
 -      const char *defmsg = git_pathdup("MERGE_MSG");
++      char *defmsg = git_pathdup("MERGE_MSG");
  
        git_config(git_default_config, NULL);
        me = action == REVERT ? "revert" : "cherry-pick";
         * 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)
                return execv_git_cmd(args);
        }
        free(reencoded_message);
 +      free(defmsg);
  
        return 0;
  }
diff --combined builtin-tag.c
index 5b141c584680ecc2362fc0e036e01dbeefa4ee90,6c6c35176e57a77fea85872fcea2c5b36f670e3e..843e9ac056c88bb2c9a8c6ded464096a99f13aff
@@@ -125,7 -125,7 +125,7 @@@ static int for_each_tag_name(const cha
  static int delete_tag(const char *name, const char *ref,
                                const unsigned char *sha1)
  {
 -      if (delete_ref(ref, sha1))
 +      if (delete_ref(ref, sha1, 0))
                return 1;
        printf("Deleted tag '%s'\n", name);
        return 0;
@@@ -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",
diff --combined cache.h
index 39f24ad827a419740e2c7515e0e8f294424cd9b0,eaacd6dd9fae9aac5f55614d099b0838c13f90cf..a1e4982cd424ec5c3695c2221583bca1bd861614
+++ b/cache.h
@@@ -270,7 -270,6 +270,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 {
@@@ -383,7 -382,6 +383,7 @@@ extern int add_to_index(struct index_st
  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
@@@ -413,8 -411,6 +413,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 *);
@@@ -424,7 -420,7 +424,7 @@@ extern int commit_locked_index(struct l
  extern void set_alternate_index_output(const char *);
  extern int close_lock_file(struct lock_file *);
  extern void rollback_lock_file(struct lock_file *);
 -extern int delete_ref(const char *, const unsigned char *sha1);
 +extern int delete_ref(const char *, const unsigned char *sha1, int delopt);
  
  /* Environment bits from configuration mechanism */
  extern int trust_executable_bit;
@@@ -484,6 -480,13 +484,13 @@@ extern int check_repository_format(void
  #define DATA_CHANGED    0x0020
  #define TYPE_CHANGED    0x0040
  
+ 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)));
  extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
diff --combined path.c
index c1cb54b7b8b478c717861a0205e537ded3fbbfc9,092ce57190cc75882a3766c9aee1df719da8a3d6..eb24017535f944a2c5dbc46663c02937cff69cd3
--- 1/path.c
--- 2/path.c
+++ b/path.c
@@@ -32,6 -32,60 +32,60 @@@ static char *cleanup_path(char *path
        return path;
  }
  
+ char *mksnpath(char *buf, size_t n, const char *fmt, ...)
+ {
+       va_list args;
+       unsigned len;
+       va_start(args, fmt);
+       len = vsnprintf(buf, n, fmt, args);
+       va_end(args);
+       if (len >= n) {
+               snprintf(buf, n, bad_path);
+               return buf;
+       }
+       return cleanup_path(buf);
+ }
+ static char *git_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
+ {
+       const char *git_dir = get_git_dir();
+       size_t len;
+       len = strlen(git_dir);
+       if (n < len + 1)
+               goto bad;
+       memcpy(buf, git_dir, len);
+       if (len && !is_dir_sep(git_dir[len-1]))
+               buf[len++] = '/';
+       len += vsnprintf(buf + len, n - len, fmt, args);
+       if (len >= n)
+               goto bad;
+       return cleanup_path(buf);
+ bad:
+       snprintf(buf, n, bad_path);
+       return buf;
+ }
+ char *git_snpath(char *buf, size_t n, const char *fmt, ...)
+ {
+       va_list args;
+       va_start(args, fmt);
+       (void)git_vsnpath(buf, n, fmt, args);
+       va_end(args);
+       return buf;
+ }
+ char *git_pathdup(const char *fmt, ...)
+ {
+       char path[PATH_MAX];
+       va_list args;
+       va_start(args, fmt);
+       (void)git_vsnpath(path, sizeof(path), fmt, args);
+       va_end(args);
+       return xstrdup(path);
+ }
  char *mkpath(const char *fmt, ...)
  {
        va_list args;
@@@ -348,7 -402,7 +402,7 @@@ int normalize_absolute_path(char *buf, 
                        goto next;
                }
  
 -              memcpy(dst, comp_start, comp_len);
 +              memmove(dst, comp_start, comp_len);
                dst += comp_len;
        next:
                comp_start = comp_end;
diff --combined refs.c
index 156714e54ee6c980a48f01610d78d10301e849b7,d589b25562405b5361b6a6e49e2501361552c6ec..48271a99ab0a7616ff0ae990a166c4a19811ffc9
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -401,7 -401,7 +401,7 @@@ const char *resolve_ref(const char *ref
                *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;
  
+               git_snpath(path, sizeof(path), "%s", ref);
                /* Special case: non-existing file.
                 * Not having the refs/heads/new-branch is OK
                 * if we are writing into it, so is .git/HEAD
@@@ -790,7 -791,7 +791,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:
@@@ -915,33 -913,25 +916,33 @@@ static int repack_without_ref(const cha
        return commit_lock_file(&packlock);
  }
  
 -int delete_ref(const char *refname, const unsigned char *sha1)
 +int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
  {
        struct ref_lock *lock;
 -      int err, i, ret = 0, flag = 0;
 +      int err, i = 0, ret = 0, flag = 0;
  
        lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
        if (!lock)
                return 1;
 -      if (!(flag & REF_ISPACKED)) {
 +      if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
                /* loose */
 -              i = strlen(lock->lk->filename) - 5; /* .lock */
 -              lock->lk->filename[i] = 0;
 -              err = unlink(lock->lk->filename);
 +              const char *path;
 +
 +              if (!(delopt & REF_NODEREF)) {
 +                      i = strlen(lock->lk->filename) - 5; /* .lock */
 +                      lock->lk->filename[i] = 0;
 +                      path = lock->lk->filename;
 +              } else {
 +                      path = git_path(refname);
 +              }
 +              err = unlink(path);
                if (err && errno != ENOENT) {
                        ret = 1;
                        error("unlink(%s) failed: %s",
 -                            lock->lk->filename, strerror(errno));
 +                            path, strerror(errno));
                }
 -              lock->lk->filename[i] = '.';
 +              if (!(delopt & REF_NODEREF))
 +                      lock->lk->filename[i] = '.';
        }
        /* removing the loose one could have resurrected an earlier
         * packed one.  Also, if it was not loose we need to repack
@@@ -966,16 -956,11 +967,16 @@@ int rename_ref(const char *oldref, cons
        struct ref_lock *lock;
        struct stat loginfo;
        int log = !lstat(git_path("logs/%s", oldref), &loginfo);
 +      const char *symref = NULL;
  
 -      if (S_ISLNK(loginfo.st_mode))
 +      if (log && S_ISLNK(loginfo.st_mode))
                return error("reflog for %s is a symlink", oldref);
  
 -      if (!resolve_ref(oldref, orig_sha1, 1, &flag))
 +      symref = resolve_ref(oldref, orig_sha1, 1, &flag);
 +      if (flag & REF_ISSYMREF)
 +              return error("refname %s is a symbolic ref, renaming it is not supported",
 +                      oldref);
 +      if (!symref)
                return error("refname %s not found", oldref);
  
        if (!is_refname_available(newref, oldref, get_packed_refs(), 0))
                return error("unable to move logfile logs/%s to tmp-renamed-log: %s",
                        oldref, strerror(errno));
  
 -      if (delete_ref(oldref, orig_sha1)) {
 +      if (delete_ref(oldref, orig_sha1, REF_NODEREF)) {
                error("unable to delete old %s", oldref);
                goto rollback;
        }
  
 -      if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1)) {
 +      if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1, REF_NODEREF)) {
                if (errno==EISDIR) {
                        if (remove_empty_directories(git_path("%s", newref))) {
                                error("Directory not empty: %s", newref);
                error("unable to lock %s for update", newref);
                goto rollback;
        }
 -
        lock->force_write = 1;
        hashcpy(lock->old_sha1, orig_sha1);
        if (write_ref_sha1(lock, orig_sha1, logmsg)) {
@@@ -1136,13 -1122,14 +1137,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/") ||
@@@ -1271,7 -1258,7 +1273,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 2b7a99d729e13b09239f1d9175d3d6c0048821b0,3d6ee8fa2a647d6ee8459f700cbc450c94e7f179..a0d477aaca73ff7ec8b12dc6c8255b69dbd677a5
+++ b/rerere.c
@@@ -345,9 -345,8 +345,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;
  }