22188f0106a50624c71dd59f095c4794ffd572b8
   1#include "cache.h"
   2#include "refs.h"
   3#include "refspec.h"
   4
   5static struct refspec_item s_tag_refspec = {
   6        0,
   7        1,
   8        0,
   9        0,
  10        "refs/tags/*",
  11        "refs/tags/*"
  12};
  13
  14/* See TAG_REFSPEC for the string version */
  15const struct refspec_item *tag_refspec = &s_tag_refspec;
  16
  17static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
  18{
  19        int i;
  20        struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));
  21
  22        for (i = 0; i < nr_refspec; i++) {
  23                size_t llen;
  24                int is_glob;
  25                const char *lhs, *rhs;
  26                int flags;
  27
  28                is_glob = 0;
  29
  30                lhs = refspec[i];
  31                if (*lhs == '+') {
  32                        rs[i].force = 1;
  33                        lhs++;
  34                }
  35
  36                rhs = strrchr(lhs, ':');
  37
  38                /*
  39                 * Before going on, special case ":" (or "+:") as a refspec
  40                 * for pushing matching refs.
  41                 */
  42                if (!fetch && rhs == lhs && rhs[1] == '\0') {
  43                        rs[i].matching = 1;
  44                        continue;
  45                }
  46
  47                if (rhs) {
  48                        size_t rlen = strlen(++rhs);
  49                        is_glob = (1 <= rlen && strchr(rhs, '*'));
  50                        rs[i].dst = xstrndup(rhs, rlen);
  51                }
  52
  53                llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
  54                if (1 <= llen && memchr(lhs, '*', llen)) {
  55                        if ((rhs && !is_glob) || (!rhs && fetch))
  56                                goto invalid;
  57                        is_glob = 1;
  58                } else if (rhs && is_glob) {
  59                        goto invalid;
  60                }
  61
  62                rs[i].pattern = is_glob;
  63                rs[i].src = xstrndup(lhs, llen);
  64                flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
  65
  66                if (fetch) {
  67                        struct object_id unused;
  68
  69                        /* LHS */
  70                        if (!*rs[i].src)
  71                                ; /* empty is ok; it means "HEAD" */
  72                        else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
  73                                rs[i].exact_sha1 = 1; /* ok */
  74                        else if (!check_refname_format(rs[i].src, flags))
  75                                ; /* valid looking ref is ok */
  76                        else
  77                                goto invalid;
  78                        /* RHS */
  79                        if (!rs[i].dst)
  80                                ; /* missing is ok; it is the same as empty */
  81                        else if (!*rs[i].dst)
  82                                ; /* empty is ok; it means "do not store" */
  83                        else if (!check_refname_format(rs[i].dst, flags))
  84                                ; /* valid looking ref is ok */
  85                        else
  86                                goto invalid;
  87                } else {
  88                        /*
  89                         * LHS
  90                         * - empty is allowed; it means delete.
  91                         * - when wildcarded, it must be a valid looking ref.
  92                         * - otherwise, it must be an extended SHA-1, but
  93                         *   there is no existing way to validate this.
  94                         */
  95                        if (!*rs[i].src)
  96                                ; /* empty is ok */
  97                        else if (is_glob) {
  98                                if (check_refname_format(rs[i].src, flags))
  99                                        goto invalid;
 100                        }
 101                        else
 102                                ; /* anything goes, for now */
 103                        /*
 104                         * RHS
 105                         * - missing is allowed, but LHS then must be a
 106                         *   valid looking ref.
 107                         * - empty is not allowed.
 108                         * - otherwise it must be a valid looking ref.
 109                         */
 110                        if (!rs[i].dst) {
 111                                if (check_refname_format(rs[i].src, flags))
 112                                        goto invalid;
 113                        } else if (!*rs[i].dst) {
 114                                goto invalid;
 115                        } else {
 116                                if (check_refname_format(rs[i].dst, flags))
 117                                        goto invalid;
 118                        }
 119                }
 120        }
 121        return rs;
 122
 123 invalid:
 124        if (verify) {
 125                /*
 126                 * nr_refspec must be greater than zero and i must be valid
 127                 * since it is only possible to reach this point from within
 128                 * the for loop above.
 129                 */
 130                free_refspec(i+1, rs);
 131                return NULL;
 132        }
 133        die("Invalid refspec '%s'", refspec[i]);
 134}
 135
 136int valid_fetch_refspec(const char *fetch_refspec_str)
 137{
 138        struct refspec_item *refspec;
 139
 140        refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
 141        free_refspec(1, refspec);
 142        return !!refspec;
 143}
 144
 145struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec)
 146{
 147        return parse_refspec_internal(nr_refspec, refspec, 1, 0);
 148}
 149
 150struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec)
 151{
 152        return parse_refspec_internal(nr_refspec, refspec, 0, 0);
 153}
 154
 155void free_refspec(int nr_refspec, struct refspec_item *refspec)
 156{
 157        int i;
 158
 159        if (!refspec)
 160                return;
 161
 162        for (i = 0; i < nr_refspec; i++) {
 163                free(refspec[i].src);
 164                free(refspec[i].dst);
 165        }
 166        free(refspec);
 167}