git-fetch.shon commit ssh-upload: prevent buffer overrun (d677db8)
   1#!/bin/sh
   2#
   3
   4USAGE='<fetch-options> <repository> <refspec>...'
   5SUBDIRECTORY_OK=Yes
   6. git-sh-setup
   7set_reflog_action "fetch $*"
   8
   9TOP=$(git-rev-parse --show-cdup)
  10if test ! -z "$TOP"
  11then
  12        cd "$TOP"
  13fi
  14. git-parse-remote
  15_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
  16_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
  17
  18LF='
  19'
  20IFS="$LF"
  21
  22no_tags=
  23tags=
  24append=
  25force=
  26verbose=
  27update_head_ok=
  28exec=
  29upload_pack=
  30keep=
  31shallow_depth=
  32while case "$#" in 0) break ;; esac
  33do
  34        case "$1" in
  35        -a|--a|--ap|--app|--appe|--appen|--append)
  36                append=t
  37                ;;
  38        --upl|--uplo|--uploa|--upload|--upload-|--upload-p|\
  39        --upload-pa|--upload-pac|--upload-pack)
  40                shift
  41                exec="--exec=$1" 
  42                upload_pack="-u $1"
  43                ;;
  44        -f|--f|--fo|--for|--forc|--force)
  45                force=t
  46                ;;
  47        -t|--t|--ta|--tag|--tags)
  48                tags=t
  49                ;;
  50        -n|--n|--no|--no-|--no-t|--no-ta|--no-tag|--no-tags)
  51                no_tags=t
  52                ;;
  53        -u|--u|--up|--upd|--upda|--updat|--update|--update-|--update-h|\
  54        --update-he|--update-hea|--update-head|--update-head-|\
  55        --update-head-o|--update-head-ok)
  56                update_head_ok=t
  57                ;;
  58        -v|--verbose)
  59                verbose=Yes
  60                ;;
  61        -k|--k|--ke|--kee|--keep)
  62                keep='-k -k'
  63                ;;
  64        --depth=*)
  65                shallow_depth="--depth=`expr "z$1" : 'z-[^=]*=\(.*\)'`"
  66                ;;
  67        --depth)
  68                shift
  69                shallow_depth="--depth=$1"
  70                ;;
  71        -*)
  72                usage
  73                ;;
  74        *)
  75                break
  76                ;;
  77        esac
  78        shift
  79done
  80
  81case "$#" in
  820)
  83        origin=$(get_default_remote)
  84        test -n "$(get_remote_url ${origin})" ||
  85                die "Where do you want to fetch from today?"
  86        set x $origin ; shift ;;
  87esac
  88
  89remote_nick="$1"
  90remote=$(get_remote_url "$@")
  91refs=
  92rref=
  93rsync_slurped_objects=
  94
  95if test "" = "$append"
  96then
  97        : >"$GIT_DIR/FETCH_HEAD"
  98fi
  99
 100# Global that is reused later
 101ls_remote_result=$(git ls-remote $upload_pack "$remote") ||
 102        die "Cannot get the repository state from $remote"
 103
 104append_fetch_head () {
 105    head_="$1"
 106    remote_="$2"
 107    remote_name_="$3"
 108    remote_nick_="$4"
 109    local_name_="$5"
 110    case "$6" in
 111    t) not_for_merge_='not-for-merge' ;;
 112    '') not_for_merge_= ;;
 113    esac
 114
 115    # remote-nick is the URL given on the command line (or a shorthand)
 116    # remote-name is the $GIT_DIR relative refs/ path we computed
 117    # for this refspec.
 118
 119    # the $note_ variable will be fed to git-fmt-merge-msg for further
 120    # processing.
 121    case "$remote_name_" in
 122    HEAD)
 123        note_= ;;
 124    refs/heads/*)
 125        note_="$(expr "$remote_name_" : 'refs/heads/\(.*\)')"
 126        note_="branch '$note_' of " ;;
 127    refs/tags/*)
 128        note_="$(expr "$remote_name_" : 'refs/tags/\(.*\)')"
 129        note_="tag '$note_' of " ;;
 130    refs/remotes/*)
 131        note_="$(expr "$remote_name_" : 'refs/remotes/\(.*\)')"
 132        note_="remote branch '$note_' of " ;;
 133    *)
 134        note_="$remote_name of " ;;
 135    esac
 136    remote_1_=$(expr "z$remote_" : 'z\(.*\)\.git/*$') &&
 137        remote_="$remote_1_"
 138    note_="$note_$remote_"
 139
 140    # 2.6.11-tree tag would not be happy to be fed to resolve.
 141    if git-cat-file commit "$head_" >/dev/null 2>&1
 142    then
 143        headc_=$(git-rev-parse --verify "$head_^0") || exit
 144        echo "$headc_   $not_for_merge_ $note_" >>"$GIT_DIR/FETCH_HEAD"
 145    else
 146        echo "$head_    not-for-merge   $note_" >>"$GIT_DIR/FETCH_HEAD"
 147    fi
 148
 149    update_local_ref "$local_name_" "$head_" "$note_"
 150}
 151
 152update_local_ref () {
 153    # If we are storing the head locally make sure that it is
 154    # a fast forward (aka "reverse push").
 155
 156    label_=$(git-cat-file -t $2)
 157    newshort_=$(git-rev-parse --short $2)
 158    if test -z "$1" ; then
 159        [ "$verbose" ] && echo >&2 "* fetched $3"
 160        [ "$verbose" ] && echo >&2 "  $label_: $newshort_"
 161        return 0
 162    fi
 163    oldshort_=$(git show-ref --hash --abbrev "$1" 2>/dev/null)
 164
 165    case "$1" in
 166    refs/tags/*)
 167        # Tags need not be pointing at commits so there
 168        # is no way to guarantee "fast-forward" anyway.
 169        if test -n "$oldshort_"
 170        then
 171                if now_=$(git show-ref --hash "$1") && test "$now_" = "$2"
 172                then
 173                        [ "$verbose" ] && echo >&2 "* $1: same as $3"
 174                        [ "$verbose" ] && echo >&2 "  $label_: $newshort_" ||:
 175                else
 176                        echo >&2 "* $1: updating with $3"
 177                        echo >&2 "  $label_: $newshort_"
 178                        git-update-ref -m "$GIT_REFLOG_ACTION: updating tag" "$1" "$2"
 179                fi
 180        else
 181                echo >&2 "* $1: storing $3"
 182                echo >&2 "  $label_: $newshort_"
 183                git-update-ref -m "$GIT_REFLOG_ACTION: storing tag" "$1" "$2"
 184        fi
 185        ;;
 186
 187    refs/heads/* | refs/remotes/*)
 188        # $1 is the ref being updated.
 189        # $2 is the new value for the ref.
 190        local=$(git-rev-parse --verify "$1^0" 2>/dev/null)
 191        if test "$local"
 192        then
 193            # Require fast-forward.
 194            mb=$(git-merge-base "$local" "$2") &&
 195            case "$2,$mb" in
 196            $local,*)
 197                if test -n "$verbose"
 198                then
 199                        echo >&2 "* $1: same as $3"
 200                        echo >&2 "  $label_: $newshort_"
 201                fi
 202                ;;
 203            *,$local)
 204                echo >&2 "* $1: fast forward to $3"
 205                echo >&2 "  old..new: $oldshort_..$newshort_"
 206                git-update-ref -m "$GIT_REFLOG_ACTION: fast-forward" "$1" "$2" "$local"
 207                ;;
 208            *)
 209                false
 210                ;;
 211            esac || {
 212                case ",$force,$single_force," in
 213                *,t,*)
 214                        echo >&2 "* $1: forcing update to non-fast forward $3"
 215                        echo >&2 "  old...new: $oldshort_...$newshort_"
 216                        git-update-ref -m "$GIT_REFLOG_ACTION: forced-update" "$1" "$2" "$local"
 217                        ;;
 218                *)
 219                        echo >&2 "* $1: not updating to non-fast forward $3"
 220                        echo >&2 "  old...new: $oldshort_...$newshort_"
 221                        exit 1
 222                        ;;
 223                esac
 224            }
 225        else
 226            echo >&2 "* $1: storing $3"
 227            echo >&2 "  $label_: $newshort_"
 228            git-update-ref -m "$GIT_REFLOG_ACTION: storing head" "$1" "$2"
 229        fi
 230        ;;
 231    esac
 232}
 233
 234case "$update_head_ok" in
 235'')
 236        orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
 237        ;;
 238esac
 239
 240# If --tags (and later --heads or --all) is specified, then we are
 241# not talking about defaults stored in Pull: line of remotes or
 242# branches file, and just fetch those and refspecs explicitly given.
 243# Otherwise we do what we always did.
 244
 245reflist=$(get_remote_refs_for_fetch "$@")
 246if test "$tags"
 247then
 248        taglist=`IFS='  ' &&
 249                  echo "$ls_remote_result" |
 250                  while read sha1 name
 251                  do
 252                        case "$sha1" in
 253                        fail)
 254                                exit 1
 255                        esac
 256                        case "$name" in
 257                        *^*) continue ;;
 258                        refs/tags/*) ;;
 259                        *) continue ;;
 260                        esac
 261                        if git-check-ref-format "$name"
 262                        then
 263                            echo ".${name}:${name}"
 264                        else
 265                            echo >&2 "warning: tag ${name} ignored"
 266                        fi
 267                  done` || exit
 268        if test "$#" -gt 1
 269        then
 270                # remote URL plus explicit refspecs; we need to merge them.
 271                reflist="$reflist$LF$taglist"
 272        else
 273                # No explicit refspecs; fetch tags only.
 274                reflist=$taglist
 275        fi
 276fi
 277
 278fetch_main () {
 279  reflist="$1"
 280  refs=
 281  rref=
 282
 283  for ref in $reflist
 284  do
 285      refs="$refs$LF$ref"
 286
 287      # These are relative path from $GIT_DIR, typically starting at refs/
 288      # but may be HEAD
 289      if expr "z$ref" : 'z\.' >/dev/null
 290      then
 291          not_for_merge=t
 292          ref=$(expr "z$ref" : 'z\.\(.*\)')
 293      else
 294          not_for_merge=
 295      fi
 296      if expr "z$ref" : 'z+' >/dev/null
 297      then
 298          single_force=t
 299          ref=$(expr "z$ref" : 'z+\(.*\)')
 300      else
 301          single_force=
 302      fi
 303      remote_name=$(expr "z$ref" : 'z\([^:]*\):')
 304      local_name=$(expr "z$ref" : 'z[^:]*:\(.*\)')
 305
 306      rref="$rref$LF$remote_name"
 307
 308      # There are transports that can fetch only one head at a time...
 309      case "$remote" in
 310      http://* | https://* | ftp://*)
 311          test -n "$shallow_depth" &&
 312                die "shallow clone with http not supported"
 313          proto=`expr "$remote" : '\([^:]*\):'`
 314          if [ -n "$GIT_SSL_NO_VERIFY" ]; then
 315              curl_extra_args="-k"
 316          fi
 317          if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
 318                "`git-repo-config --bool http.noEPSV`" = true ]; then
 319              noepsv_opt="--disable-epsv"
 320          fi
 321
 322          # Find $remote_name from ls-remote output.
 323          head=$(
 324                IFS='   '
 325                echo "$ls_remote_result" |
 326                while read sha1 name
 327                do
 328                        test "z$name" = "z$remote_name" || continue
 329                        echo "$sha1"
 330                        break
 331                done
 332          )
 333          expr "z$head" : "z$_x40\$" >/dev/null ||
 334                die "No such ref $remote_name at $remote"
 335          echo >&2 "Fetching $remote_name from $remote using $proto"
 336          git-http-fetch -v -a "$head" "$remote/" || exit
 337          ;;
 338      rsync://*)
 339          test -n "$shallow_depth" &&
 340                die "shallow clone with rsync not supported"
 341          TMP_HEAD="$GIT_DIR/TMP_HEAD"
 342          rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
 343          head=$(git-rev-parse --verify TMP_HEAD)
 344          rm -f "$TMP_HEAD"
 345          test "$rsync_slurped_objects" || {
 346              rsync -av --ignore-existing --exclude info \
 347                  "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
 348
 349              # Look at objects/info/alternates for rsync -- http will
 350              # support it natively and git native ones will do it on
 351              # the remote end.  Not having that file is not a crime.
 352              rsync -q "$remote/objects/info/alternates" \
 353                  "$GIT_DIR/TMP_ALT" 2>/dev/null ||
 354                  rm -f "$GIT_DIR/TMP_ALT"
 355              if test -f "$GIT_DIR/TMP_ALT"
 356              then
 357                  resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" |
 358                  while read alt
 359                  do
 360                      case "$alt" in 'bad alternate: '*) die "$alt";; esac
 361                      echo >&2 "Getting alternate: $alt"
 362                      rsync -av --ignore-existing --exclude info \
 363                      "$alt" "$GIT_OBJECT_DIRECTORY/" || exit
 364                  done
 365                  rm -f "$GIT_DIR/TMP_ALT"
 366              fi
 367              rsync_slurped_objects=t
 368          }
 369          ;;
 370      *)
 371          # We will do git native transport with just one call later.
 372          continue ;;
 373      esac
 374
 375      append_fetch_head "$head" "$remote" \
 376          "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" || exit
 377
 378  done
 379
 380  case "$remote" in
 381  http://* | https://* | ftp://* | rsync://* )
 382      ;; # we are already done.
 383  *)
 384    ( : subshell because we muck with IFS
 385      IFS="     $LF"
 386      (
 387          git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref ||
 388          echo failed "$remote"
 389      ) |
 390      (
 391        trap '
 392                if test -n "$keepfile" && test -f "$keepfile"
 393                then
 394                        rm -f "$keepfile"
 395                fi
 396        ' 0
 397
 398        keepfile=
 399        while read sha1 remote_name
 400        do
 401          case "$sha1" in
 402          failed)
 403                  echo >&2 "Fetch failure: $remote"
 404                  exit 1 ;;
 405          # special line coming from index-pack with the pack name
 406          pack)
 407                  continue ;;
 408          keep)
 409                  keepfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
 410                  continue ;;
 411          esac
 412          found=
 413          single_force=
 414          for ref in $refs
 415          do
 416              case "$ref" in
 417              +$remote_name:*)
 418                  single_force=t
 419                  not_for_merge=
 420                  found="$ref"
 421                  break ;;
 422              .+$remote_name:*)
 423                  single_force=t
 424                  not_for_merge=t
 425                  found="$ref"
 426                  break ;;
 427              .$remote_name:*)
 428                  not_for_merge=t
 429                  found="$ref"
 430                  break ;;
 431              $remote_name:*)
 432                  not_for_merge=
 433                  found="$ref"
 434                  break ;;
 435              esac
 436          done
 437          local_name=$(expr "z$found" : 'z[^:]*:\(.*\)')
 438          append_fetch_head "$sha1" "$remote" \
 439                  "$remote_name" "$remote_nick" "$local_name" \
 440                  "$not_for_merge" || exit
 441        done
 442      )
 443    ) || exit ;;
 444  esac
 445
 446}
 447
 448fetch_main "$reflist" || exit
 449
 450# automated tag following
 451case "$no_tags$tags" in
 452'')
 453        case "$reflist" in
 454        *:refs/*)
 455                # effective only when we are following remote branch
 456                # using local tracking branch.
 457                taglist=$(IFS=' ' &&
 458                echo "$ls_remote_result" |
 459                git-show-ref --exclude-existing=refs/tags/ |
 460                while read sha1 name
 461                do
 462                        git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
 463                        echo >&2 "Auto-following $name"
 464                        echo ".${name}:${name}"
 465                done)
 466        esac
 467        case "$taglist" in
 468        '') ;;
 469        ?*)
 470                # do not deepen a shallow tree when following tags
 471                shallow_depth=
 472                fetch_main "$taglist" || exit ;;
 473        esac
 474esac
 475
 476# If the original head was empty (i.e. no "master" yet), or
 477# if we were told not to worry, we do not have to check.
 478case "$orig_head" in
 479'')
 480        ;;
 481?*)
 482        curr_head=$(git-rev-parse --verify HEAD 2>/dev/null)
 483        if test "$curr_head" != "$orig_head"
 484        then
 485            git-update-ref \
 486                        -m "$GIT_REFLOG_ACTION: Undoing incorrectly fetched HEAD." \
 487                        HEAD "$orig_head"
 488                die "Cannot fetch into the current branch."
 489        fi
 490        ;;
 491esac