Merge branch 'ar/mksnpath'
authorJunio C Hamano <gitster@pobox.com>
Wed, 5 Nov 2008 19:35:53 +0000 (11:35 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 5 Nov 2008 19:35:53 +0000 (11:35 -0800)
* ar/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 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

1  2 
builtin-revert.c
builtin-tag.c
cache.h
path.c
refs.c
diff --combined builtin-revert.c
index 7483a7a63bf09a7a123e442e9b933b9d24f2b1a6,7e50c2aa542772b2bac7c599df8865c3dbae5bcd..4038b4118da087069db82bfcf6e0dd298aec9036
@@@ -251,7 -251,7 +251,7 @@@ static int revert_or_cherry_pick(int ar
        int i, index_fd, clean;
        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");
        struct merge_options o;
        struct tree *result, *next_tree, *base_tree, *head_tree;
        static struct lock_file index_lock;
                return execv_git_cmd(args);
        }
        free(reencoded_message);
 +      free(defmsg);
  
        return 0;
  }
diff --combined builtin-tag.c
index 1ff7b37162185a70de5183dd55819f6b11fa6688,efd77231ffb6f2574d130a612a1c38dfe646fdf8..84db156e63681de6322019b9b9ffa15371c443b1
@@@ -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 a3c77f08ca18f44c1617efd429a819ead3f80234,24d0d44f77123e2c869097191bfc7310621326e5..eda7028992421e3946d93179a0dd6539f43967bb
+++ b/cache.h
@@@ -434,7 -434,7 +434,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;
@@@ -495,6 -495,13 +495,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 cc4b4c3941145980bde66d387b0febd8f14c70e2,01e4df4ccfa203f140998f5da42b2a9fcfcca4c7..9ae447b10b79a4ba3c834dd74977db5bd321f055
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -413,7 -413,7 +413,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. */
                if (lstat(path, &st) < 0) {
                        struct ref_list *list = get_packed_refs();
@@@ -921,33 -922,25 +922,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
@@@ -972,16 -965,11 +973,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)) {
@@@ -1142,13 -1131,14 +1143,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/") ||
@@@ -1277,7 -1267,7 +1279,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))